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.

John Smith
la source
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 ).

Michael Kessler
la source
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);
}
b123400
la source
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()
        }
    }
}
Guy Daher
la source
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.

Phanindra
la source
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];
YogiAR
la source
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});
hkatz
la source
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()
        }
    }
}
Robert Harrold
la source
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.

Reddy
la source