Tracer une ligne dans UIView


86

J'ai besoin de dessiner une ligne horizontale dans un UIView. Quelle est la manière la plus simple de le faire. Par exemple, je veux dessiner une ligne horizontale noire à y-coord = 200.

Je n'utilise PAS Interface Builder.


1
Voici la solution complète et simple pour avoir correctement une ligne à un seul pixel, dans tous les iOS, et la rendre facile dans le storyboard: stackoverflow.com/a/26525466/294884
Fattie

Réponses:


122

Le moyen le plus simple dans votre cas (ligne horizontale) est d'ajouter une sous-vue avec une couleur de fond et un cadre noirs [0, 200, 320, 1].

Exemple de code (j'espère qu'il n'y a pas d'erreur - je l'ai écrit sans Xcode):

UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
[lineView release];
// You might also keep a reference to this view 
// if you are about to change its coordinates.
// Just create a member and a property for this...

Une autre façon consiste à créer une classe qui dessinera une ligne dans sa méthode drawRect (vous pouvez voir mon exemple de code pour cela ici ).


Faites cela sans aucun code dans Storyboard. C'est plus facile et mieux.
coolcool1994

3
@ coolcool1994, n'avez-vous pas remarqué "Je n'utilise PAS Interface Builder." exigence dans la question?
Michael Kessler

312

C'est peut-être un peu tard, mais je tiens à ajouter qu'il existe une meilleure solution. Utiliser UIView est simple, mais relativement lent. Cette méthode remplace la façon dont la vue se dessine elle-même et est plus rapide:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);

    // Draw them with a 2.0 stroke width so they are a bit more visible.
    CGContextSetLineWidth(context, 2.0f);

    CGContextMoveToPoint(context, 0.0f, 0.0f); //start at this point

    CGContextAddLineToPoint(context, 20.0f, 20.0f); //draw to this point

    // and now draw the Path!
    CGContextStrokePath(context);
}

Si ce code est utilisé dans un UIView, les coordonnées de cet exemple sont-elles relatives aux limites de la vue ou de l'écran entier?
ChrisP

N'a-t-on pas besoin d'appeler CGContextBeginPath(context);avant CGContextMoveToPoint(...);?
i_am_jorf

37
Utiliser une vue pour le faire n'est pas trop horrible. Cela facilite les choses, par exemple, lors de la réalisation d'animations implicites lors des changements d'orientation. S'il ne s'agit que d'un seul, un autre UIView n'est pas si cher et le code est beaucoup plus simple.
je_am_jorf

De plus, vous pouvez obtenir des limites et un point médian avec ces codes: CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2;
coolcool1994

1
Exactement, le commentaire selon lequel c'est «lent» n'est pas raisonnable. Il y a un grand nombre de vues UIV simples à l'écran à tout moment. Notez que dessiner UN (!) Caractère de texte, avec tout le traitement que cela implique, permet de dessiner un UIView rempli.
Fattie

30

Swift 3 et Swift 4

Voici comment vous pouvez dessiner une ligne grise à la fin de votre vue (même idée que la réponse de b123400)

class CustomView: UIView {

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        if let context = UIGraphicsGetCurrentContext() {
            context.setStrokeColor(UIColor.gray.cgColor)
            context.setLineWidth(1)
            context.move(to: CGPoint(x: 0, y: bounds.height))
            context.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
            context.strokePath()
        }
    }
}

Le "if let context" échoue lorsqu'il est appelé à partir de viewDidLayoutSubviews.
Oscar

14

Ajoutez simplement une étiquette sans texte et avec une couleur de fond. Définissez les coordonnées de votre choix ainsi que la hauteur et la largeur. Vous pouvez le faire manuellement ou avec Interface Builder.


11

Vous pouvez utiliser la classe UIBezierPath pour cela:

Et pouvez dessiner autant de lignes que vous le souhaitez:

J'ai sous-classé UIView:

    @interface MyLineDrawingView()
    {
       NSMutableArray *pathArray;
       NSMutableDictionary *dict_path;
       CGPoint startPoint, endPoint;
    }

       @property (nonatomic,retain)   UIBezierPath *myPath;
    @end

Et initialisé les objets pathArray et dictPAth qui seront utilisés pour le dessin au trait. J'écris la partie principale du code de mon propre projet:

- (void)drawRect:(CGRect)rect
{

    for(NSDictionary *_pathDict in pathArray)
    {
        [((UIColor *)[_pathDict valueForKey:@"color"]) setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
        [[_pathDict valueForKey:@"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
    }

    [[dict_path objectForKey:@"color"] setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
    [[dict_path objectForKey:@"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];

}

méthode touchesBegin:

UITouch *touch = [touches anyObject];
startPoint = [touch locationInView:self];
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth = currentSliderValue*2;
dict_path = [[NSMutableDictionary alloc] init];

touchesMoved, méthode:

UITouch *touch = [touches anyObject];
endPoint = [touch locationInView:self];

 [myPath removeAllPoints];
        [dict_path removeAllObjects];// remove prev object in dict (this dict is used for current drawing, All past drawings are managed by pathArry)

    // actual drawing
    [myPath moveToPoint:startPoint];
    [myPath addLineToPoint:endPoint];

    [dict_path setValue:myPath forKey:@"path"];
    [dict_path setValue:strokeColor forKey:@"color"];

    //                NSDictionary *tempDict = [NSDictionary dictionaryWithDictionary:dict_path];
    //                [pathArray addObject:tempDict];
    //                [dict_path removeAllObjects];
    [self setNeedsDisplay];

touchesEnded, méthode:

        NSDictionary *tempDict = [NSDictionary dictionaryWithDictionary:dict_path];
        [pathArray addObject:tempDict];
        [dict_path removeAllObjects];
        [self setNeedsDisplay];

11

Une autre possibilité (et encore plus courte). Si vous êtes à l'intérieur de drawRect, quelque chose comme ce qui suit:

[[UIColor blackColor] setFill];
UIRectFill((CGRect){0,200,rect.size.width,1});

0

Basé sur la réponse de Guy Daher.

J'essaye d'éviter d'utiliser? car cela peut provoquer un plantage de l'application si GetCurrentContext () renvoie nil.

Je ne vérifierais rien si la déclaration:

class CustomView: UIView 
{    
    override func draw(_ rect: CGRect) 
    {
        super.draw(rect)
        if let context = UIGraphicsGetCurrentContext()
        {
            context.setStrokeColor(UIColor.gray.cgColor)
            context.setLineWidth(1)
            context.move(to: CGPoint(x: 0, y: bounds.height))
            context.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
            context.strokePath()
        }
    }
}

2
si la raison de la ifclause est simplement de déballer de l'option, préférez utiliser une guardinstruction à la place.
Julio Flores

-1

Ajoutez une étiquette sans texte et avec la couleur d'arrière-plan correspondant à la taille du cadre (ex: hauteur = 1). Faites-le via le code ou dans le générateur d'interface.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.