Рисовать линию в UIView

86

Мне нужно нарисовать горизонтальную линию в UIView. Как это сделать проще всего. Например, я хочу нарисовать черную горизонтальную линию с координатой y = 200.

Я НЕ использую Interface Builder.

Джон Смит
источник
1
Вот полное и простое решение для правильного создания однопиксельной линии во всех iOS и упрощения работы в раскадровке: stackoverflow.com/a/26525466/294884
Fattie

Ответы:

122

Самый простой способ в вашем случае (горизонтальная линия) - добавить подпредставление с черным цветом фона и рамкой [0, 200, 320, 1].

Пример кода (надеюсь, ошибок нет - написал без 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...

Другой способ - создать класс, который будет рисовать линию в своем методе drawRect (вы можете увидеть мой пример кода для этого здесь ).

Майкл Кесслер
источник
Сделайте это без кода в раскадровке. Так проще и лучше.
coolcool1994 06
3
@ coolcool1994, разве вы не заметили: «Я НЕ использую Interface Builder». требование в вопросе?
Майкл Кесслер
312

Возможно, это немного поздно, но я хочу добавить, что есть способ получше. Использовать UIView просто, но относительно медленно. Этот метод переопределяет способ отрисовки представления и работает быстрее:

- (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
источник
Если этот код используется в UIView, будут ли координаты в этом примере относительно границ представления или всего экрана?
ChrisP
Есть ли один не нужно позвонить , CGContextBeginPath(context);прежде чем CGContextMoveToPoint(...);?
i_am_jorf 09
37
Использование представления для этого не так уж и ужасно. Это упрощает работу, например, при выполнении неявной анимации во время изменения ориентации. Если это всего лишь один, другой UIView не так уж и дорог, а код намного проще.
i_am_jorf 02
Кроме того, вы можете получить границы и среднюю точку с помощью этих кодов: CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2;
coolcool1994
1
Да, комментарий о том, что он "медленный", не имеет смысла. На экране в любое время появляется огромное количество простых UIView. Обратите внимание, что рисование ОДНОГО (!) Текстового символа со всей необходимой обработкой заменяет рисование заполненного UIView.
Fattie
30

Swift 3 и Swift 4

Вот как вы можете нарисовать серую линию в конце вашего представления (та же идея, что и ответ 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()
        }
    }
}
Гай Дахер
источник
«Если разрешить контекст» не работает при вызове из viewDidLayoutSubviews.
Оскар
14

Просто добавьте метку без текста и с цветом фона. Установите координаты по вашему выбору, а также высоту и ширину. Вы можете сделать это вручную или с помощью Interface Builder.

Фаниндра
источник
11

Вы можете использовать класс UIBezierPath для этого:

И можете нарисовать столько линий, сколько захотите:

Я создал подкласс UIView:

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

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

И инициализировал объекты pathArray и dictPAth, которые будут использоваться для рисования линий. Я пишу основную часть кода из собственного проекта:

- (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 метод:

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

touchMoved Метод:

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 Метод:

        NSDictionary *tempDict = [NSDictionary dictionaryWithDictionary:dict_path];
        [pathArray addObject:tempDict];
        [dict_path removeAllObjects];
        [self setNeedsDisplay];
ЙогиАР
источник
11

Еще одна (и даже более короткая) возможность. Если вы находитесь внутри drawRect, что-то вроде следующего:

[[UIColor blackColor] setFill];
UIRectFill((CGRect){0,200,rect.size.width,1});
hkatz
источник
0

На основе ответа Гая Дахера.

Я стараюсь избегать использования? потому что это может вызвать сбой приложения, если GetCurrentContext () вернет ноль.

Я бы сделал нулевую проверку, если утверждение:

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
если причиной ifпредложения является просто распаковка из необязательного, лучше использовать guardвместо этого оператор.
Хулио Флорес
-1

Добавьте метку без текста и с цветом фона, соответствующим размеру кадра (например, высота = 1). Сделайте это через код или в построителе интерфейса.

Редди
источник