Dibujar línea en UIView

86

Necesito dibujar una línea horizontal en una UIView. ¿Cuál es la forma más sencilla de hacerlo? Por ejemplo, quiero dibujar una línea horizontal negra en y-coord = 200.

NO estoy usando Interface Builder.

John Smith
fuente
1
Aquí está la solución completa y fácil para tener correctamente una línea de un solo píxel, en todo iOS, y hacerlo fácil en el guión gráfico: stackoverflow.com/a/26525466/294884
Fattie

Respuestas:

122

La forma más sencilla en su caso (línea horizontal) es agregar una subvista con un marco y un color de fondo negro [0, 200, 320, 1].

Ejemplo de código (espero que no haya errores, lo escribí sin 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...

Otra forma es crear una clase que dibujará una línea en su método drawRect (puedes ver mi ejemplo de código para esto aquí ).

Michael Kessler
fuente
Haga esto sin ningún código en Storyboard. Es más fácil y mejor.
coolcool1994
3
@ coolcool1994, ¿no te has dado cuenta de que "NO estoy usando Interface Builder"? requisito en la pregunta?
Michael Kessler
312

Quizás esto sea un poco tarde, pero quiero agregar que hay una mejor manera. Usar UIView es simple, pero relativamente lento. Este método anula cómo se dibuja la vista y es más rápido:

- (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
fuente
Si este código se usa en una UIView, ¿las coordenadas de esta muestra son relativas a los límites de la vista o a toda la pantalla?
ChrisP
¿No hace falta llamar CGContextBeginPath(context);antes CGContextMoveToPoint(...);?
i_am_jorf
37
Usar una vista para hacerlo no es demasiado horrible. Facilita las cosas, por ejemplo, al hacer animaciones implícitas durante los cambios de orientación. Si es solo una, otra UIView no es tan cara y el código es mucho más simple.
i_am_jorf
Además, puede obtener límites y puntos medios con estos códigos: CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2;
coolcool1994
1
Bien, el comentario de que es "lento" no tiene sentido. Hay una gran cantidad de UIViews simples en la pantalla en cualquier momento. Tenga en cuenta que dibujar UN carácter de texto (!), Con todo el procesamiento que implica, los pantanos dibujan una UIView llena.
Fattie
30

Swift 3 y Swift 4

Así es como puede dibujar una línea gris al final de su vista (la misma idea que la respuesta 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
fuente
El "contexto si se deja" falla cuando se llama desde viewDidLayoutSubviews.
Oscar
14

Simplemente agregue una etiqueta sin texto y con color de fondo. Establezca las coordenadas de su elección y también la altura y el ancho. Puede hacerlo manualmente o con Interface Builder.

Phanindra
fuente
11

Puede usar la clase UIBezierPath para esto:

Y puede dibujar tantas líneas como desee:

He subclasificado UIView:

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

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

E inicializó los objetos pathArray y dictPAth que se utilizarán para el dibujo lineal. Estoy escribiendo la parte principal del código de mi propio proyecto:

- (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étodo touchesBegin:

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

touchchesMoved Método:

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

método touchesEnded:

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

Otra posibilidad (y aún más corta). Si está dentro de drawRect, algo como lo siguiente:

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

Basado en la respuesta de Guy Daher.

Trato de evitar usar? porque puede provocar un bloqueo de la aplicación si GetCurrentContext () devuelve nil.

No haría ninguna comprobación si la declaración:

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
fuente
2
si el motivo de la ifcláusula es simplemente desempaquetar de lo opcional, prefiera usar una guarddeclaración en su lugar.
Julio Flores
-1

Agregue una etiqueta sin texto y con el color de fondo correspondiente al tamaño del marco (p. Ej., Altura = 1). Hágalo a través del código o en el generador de interfaces.

Reddy
fuente