Desenhar linha em UIView


86

Eu preciso desenhar uma linha horizontal em um UIView. Qual é a maneira mais fácil de fazer isso. Por exemplo, eu quero desenhar uma linha horizontal preta em y-coord = 200.

NÃO estou usando o Interface Builder.


1
Esta é a solução completa e fácil para ter corretamente uma linha de pixel único, em todos os iOS, e facilitar no storyboard: stackoverflow.com/a/26525466/294884
Fattie

Respostas:


122

A maneira mais fácil no seu caso (linha horizontal) é adicionar uma subvisualização com fundo preto e moldura [0, 200, 320, 1].

Amostra de código (espero que não haja erros - escrevi sem o 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...

Outra maneira é criar uma classe que desenhará uma linha em seu método drawRect (você pode ver meu exemplo de código para isso aqui ).


Faça isso sem nenhum código no Storyboard. É mais fácil e melhor.
coolcool1994

3
@ coolcool1994, você não percebeu "NÃO estou usando o Interface Builder." requisito na questão?
Michael Kessler

312

Talvez seja um pouco tarde, mas quero acrescentar que existe uma maneira melhor. Usar o UIView é simples, mas relativamente lento. Este método substitui a forma como a visualização se desenha e é mais 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);
}

Se este código for usado em um UIView, as coordenadas neste exemplo são relativas aos limites da visualização ou da tela inteira?
ChrisP de

Não é preciso ligar CGContextBeginPath(context);antes CGContextMoveToPoint(...);?
i_am_jorf

37
Usar uma visão para fazer isso não é tão horrível. Isso torna as coisas mais fáceis, por exemplo, ao fazer animações implícitas durante mudanças de orientação. Se for apenas um, outro UIView não é tão caro e o código é muito mais simples.
i_am_jorf

Além disso, você pode obter limites e pontos médios com estes códigos: CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2;
coolcool1994,

1
Certo, o comentário de que é "lento" não faz sentido. Há um grande número de UIViews simples na tela a qualquer momento. Observe que desenhar UM (!) Caractere de texto, com todo o processamento que envolve, atrapalha o desenho de um UIView preenchido.
Fattie

29

Swift 3 e Swift 4

É assim que você pode desenhar uma linha cinza no final de sua visualização (mesma ideia da resposta 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()
        }
    }
}

O "contexto if let" falha quando chamado de viewDidLayoutSubviews.
Oscar

14

Basta adicionar um rótulo sem texto e com a cor de fundo. Defina as coordenadas de sua escolha e também a altura e largura. Você pode fazer isso manualmente ou com o Interface Builder.


11

Você pode usar a classe UIBezierPath para isso:

E pode desenhar quantas linhas você quiser:

Eu criei uma subclasse de UIView:

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

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

E inicializou os objetos pathArray e dictPAth que serão usados ​​para desenho de linha. Estou escrevendo a parte principal do código do meu próprio projeto:

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

Método 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];

Método touchesEnded:

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

11

Uma outra possibilidade (e ainda mais curta). Se você estiver dentro de drawRect, algo como o seguinte:

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

0

Baseado na resposta de Guy Daher.

Tento evitar usar? porque pode causar um travamento do aplicativo se GetCurrentContext () retornar nulo.

Eu não faria nada verificar se a declaração:

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 o motivo da ifcláusula for apenas desencaixotar do opcional, prefira usar uma guardinstrução.
Julio Flores

-1

Adicionar rótulo sem texto e com a cor de fundo do tamanho do quadro correspondente (ex: altura = 1). Faça isso por meio de código ou no construtor de interface.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.