Как рисовать одну точку в iOS

Мне было интересно, как лучше всего нарисовать одну точку? Моя цель - нарисовать эту строку в tableViewCell, чтобы она выглядела так же, как собственный разделитель ячеек. Я не хочу использовать собственный разделитель, потому что хочу сделать другой цвет и в другом положении (не внизу..).

Сначала я использовал 1px UIView и окрасил его в серый цвет. Но на дисплеях Retina это выглядит как 2px. Также попытался использовать этот метод:

- (void)drawLine:(CGPoint)startPoint endPoint:(CGPoint)endPoint inColor:(UIColor *)color {

    CGMutablePathRef straightLinePath = CGPathCreateMutable();
    CGPathMoveToPoint(straightLinePath, NULL, startPoint.x, startPoint.y);
    CGPathAddLineToPoint(straightLinePath, NULL, endPoint.x, endPoint.y);

    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = straightLinePath;
    UIColor *fillColor = color;
    shapeLayer.fillColor = fillColor.CGColor;
    UIColor *strokeColor = color;
    shapeLayer.strokeColor = strokeColor.CGColor;
    shapeLayer.lineWidth = 0.5f;
    shapeLayer.fillRule = kCAFillRuleNonZero;
    [self.layer addSublayer:shapeLayer];
}

По какой-то причине он работает примерно в 60% случаев. Что-то не так с ним? Во всяком случае, я был бы рад услышать о лучшем способе.

Спасибо.

Ответ 1

Я сделал то же самое с категорией UIView. Вот мои методы:

#define SEPARATOR_HEIGHT 0.5

- (void)addSeparatorLinesWithColor:(UIColor *)color
{
    [self addSeparatorLinesWithColor:color edgeInset:UIEdgeInsetsZero];
}


- (void)addSeparatorLinesWithColor:(UIColor *)color edgeInset:(UIEdgeInsets)edgeInset
{

    UIView *topSeparatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, - SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
    [topSeparatorView setBackgroundColor:color];
    [self addSubview:topSeparatorView];

    UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, self.frame.size.height + SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
    [separatorView setBackgroundColor:color];
    [self addSubview:separatorView];
}

Просто чтобы добавить к Реми большой ответ, возможно, даже проще сделать это. Сделать класс UILine.m

@interface UILine:UIView
@end
@implementation UILine
-(id)awakeFromNib
    {
    // careful, contentScaleFactor does NOT WORK in storyboard during initWithCoder.
    // example, float sortaPixel = 1.0/self.contentScaleFactor ... does not work.
    // instead, use mainScreen scale which works perfectly:
    float sortaPixel = 1.0/[UIScreen mainScreen].scale;
    UIView *topSeparatorView = [[UIView alloc] initWithFrame:
        CGRectMake(0, 0, self.frame.size.width, sortaPixel)];

    topSeparatorView.userInteractionEnabled = NO;
    [topSeparatorView setBackgroundColor:self.backgroundColor];
    [self addSubview:topSeparatorView];

    self.backgroundColor = [UIColor clearColor];
    self.userInteractionEnabled = NO;
    }
@end

В IB, запустите UIView, щелкните идентификатор инспектора и переименуйте класс в UILine. Установите ширину, которую вы хотите в IB. Установите высоту в 1 или 2 пикселя - просто чтобы вы могли видеть ее в IB. Установите цвет фона, который вы хотите в IB. Когда вы запустите приложение, оно станет 1-пиксельной линией шириной этого цвета. (Наверное, вам не следует подвергать никаким настройкам по умолчанию для автоматической настройки в раскадровке /xib, я не мог заставить его сломаться.) Все готово.

Примечание: вы можете подумать: "Почему не просто изменить размер UIView в коде в awakeFromNib?" Изменение размера просмотров при загрузке в приложении раскадровки проблематично - см. Здесь много вопросов!

Интересный gotchya: скорее всего, вы просто сделаете UIView, скажем, 10 или 20 пикселей на раскадровке, просто чтобы вы могли это увидеть. Конечно, он исчезает в приложении, и вы получаете красивую одну пиксельную линию. Но! обязательно запомните self.userInteractionEnabled = NO, или он может перехватить ваши другие, скажем, кнопки!


2016 решение! fooobar.com/questions/75169/...

Ответ 2

shapeLayer.lineWidth = 0.5f;

Это распространенная ошибка и причина, по которой это работает только некоторое время. Иногда это будет точно перекрывать пиксели на экране, а иногда это не будет. Способ рисования одноточечной линии, которая всегда работает, состоит в том, чтобы нарисовать прямоугольник с одной точкой на целочисленных границах и заполнить его. Таким образом, он всегда будет точно соответствовать пикселям на экране.

Для преобразования из точек в пиксели, если вы хотите это сделать, используйте коэффициент масштабирования вида.

Таким образом, это всегда будет шириной в один пиксель:

CGContextFillRect(con, CGRectMake(0,0,desiredLength,1.0/self.contentScaleFactor));

Здесь показан снимок экрана, показывающий линию, используемую в качестве разделителя, нарисованную в верхней части каждой ячейки:

enter image description here

В самом представлении таблицы нет разделителей (как показано белым пространством ниже трех существующих ячеек). Я не могу рисовать линию в позиции, длине и цвете, которую вы хотите, но это ваша забота, а не моя.

Ответ 3

Метод AutoLayout:

Я использую простой старый UIView и устанавливаю его ограничение по высоте на 1 в Interface Builder. Привязали его к нижней части с помощью ограничений. Конструктор интерфейсов не позволяет установить ограничение по высоте на 0,5, но вы можете сделать это в коде.

Создайте соединитель для ограничения высоты, затем вызовите это:

// Note: This will be 0.5 on retina screens
self.dividerViewHeightConstraint.constant =  1.0/[UIScreen mainScreen].scale 

Работал для меня.

FWIW Я не думаю, что нам нужно больше поддерживать сетки сетчатки. Тем не менее, я все еще использую основной экран для будущего доказательства приложения.

Ответ 5

Дополнение к Реми Вирину, используя Swift 3.0 Создание класса LineSeparator:

import UIKit

class LineSeparator: UIView {

override func awakeFromNib() {

    let sortaPixel: CGFloat = 1.0/UIScreen.main.scale

    let topSeparatorView = UIView()
    topSeparatorView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: sortaPixel)

    topSeparatorView.isUserInteractionEnabled = false
    topSeparatorView.backgroundColor = self.backgroundColor

    self.addSubview(topSeparatorView)
    self.backgroundColor = UIColor.clear

    self.isUserInteractionEnabled = false   
    }
}