Disegna una linea in UIView


86

Devo disegnare una linea orizzontale in una vista UIV. Qual è il modo più semplice per farlo. Ad esempio, voglio disegnare una linea orizzontale nera in y-coord = 200.

NON sto usando Interface Builder.


1
Ecco la soluzione completa e facile da avere correttamente una linea di singolo pixel, in tutte le iOS e rendendo più facile in storyboard: stackoverflow.com/a/26525466/294884
Fattie

Risposte:


122

Il modo più semplice nel tuo caso (linea orizzontale) è aggiungere una vista secondaria con il colore di sfondo e la cornice neri [0, 200, 320, 1].

Esempio di codice (spero che non ci siano errori - l'ho scritto senza 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...

Un altro modo è creare una classe che disegnerà una linea nel suo metodo drawRect (puoi vedere il mio esempio di codice per questo qui ).


Fallo senza alcun codice in Storyboard. È più facile e migliore.
coolcool1994

3
@ coolcool1994, non hai notato "NON sto usando Interface Builder". requisito nella domanda?
Michael Kessler

312

Forse è un po 'tardi, ma voglio aggiungere che c'è un modo migliore. Usare UIView è semplice, ma relativamente lento. Questo metodo sovrascrive il modo in cui la vista si disegna ed è più veloce:

- (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);
}

Se questo codice viene utilizzato in una vista UIV, le coordinate in questo esempio sono relative ai limiti della vista o dell'intero schermo?
ChrisP

Non è necessario chiamare CGContextBeginPath(context);prima CGContextMoveToPoint(...);?
i_am_jorf

37
Usare una vista per farlo non è poi così orribile. Rende le cose più facili, ad esempio, quando si eseguono animazioni implicite durante i cambiamenti di orientamento. Se è solo uno, un altro UIView non è poi così costoso e il codice è molto più semplice.
i_am_jorf

Inoltre, puoi ottenere limiti e punto medio con questi codici: CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2;
coolcool1994

1
Esatto, il commento che è "lento" non è sensato. Ci sono un numero enorme di semplici visualizzazioni UIV sullo schermo in qualsiasi momento. Nota che disegnare UN carattere di testo (!), Con tutta l'elaborazione che comporta, le paludi disegnano una UIView piena.
Fattie

30

Swift 3 e Swift 4

È così che puoi disegnare una linea grigia alla fine della tua vista (stessa idea della risposta di 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()
        }
    }
}

Il "contesto se let" fallisce quando viene chiamato da viewDidLayoutSubviews.
Oscar

14

Basta aggiungere un'etichetta senza testo e con il colore di sfondo. Imposta le coordinate di tua scelta e anche altezza e larghezza. Puoi farlo manualmente o con Interface Builder.


11

Puoi usare la classe UIBezierPath per questo:

E puoi disegnare tutte le linee che vuoi:

Ho sottoclasse UIView:

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

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

E inizializzati gli oggetti pathArray e dictPAth che verranno utilizzati per il disegno delle linee. Sto scrivendo la parte principale del codice dal mio progetto:

- (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];

}

touchesBegin metodo:

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

metodo touchesMoved:

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];

metodo touchesEnded:

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

11

Un'altra (e una possibilità ancora più breve). Se sei all'interno di drawRect, qualcosa di simile al seguente:

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

0

Basato sulla risposta di Guy Daher.

Cerco di evitare di usare? perché può causare un arresto anomalo dell'applicazione se GetCurrentContext () restituisce zero.

Farei un controllo nullo se l'affermazione:

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
se il motivo della ifclausola è solo per unbox dall'opzionale, preferisci guardinvece usare un'istruzione.
Julio Flores

-1

Aggiungi un'etichetta senza testo e con il colore di sfondo corrispondente alla dimensione del frame (es: altezza = 1). Fallo tramite codice o nel generatore di interfacce.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.