Три способа сделать обводку границ у UIView. Плюсы и минусы.

Решил написать обзор методов для отрисовки границ обводки у представлений UIVIew. Какими из них пользуюсь сам и в каких случаях, что лучше использовать. Поехали!

Известные мне способы нарисовать у представления обводку:
1 Использовать свойства слоя CALayer
2 Использовать дополнительные UIVIew
3 Использовать шейповые слои CAShapeLayer

У каждого из способов есть свои достоинства и недостатки. Разберем каждый из них подробнее.

Способ №1. Использование свойств слоя CALayer

Каждый UIView в своей основе содержит слой с классом CALayer. А у CALayer есть 2 свойства, отвечающие за обводку — borderWidth (толщина обводки) и borderColor (цвет обводки). Задавая их вы получите замкнутую обводку по периметру представления, заданной толщины и заданного цвета. По-умолчанию, обводка будет прямоугольной формы. Если вы захотите обводку со скругленными углами, то у CALayer для этого есть другое свойство — cornerRadius (радиус скругления).

Пример:

view.layer.borderWidth = 3.0
view.layer.borderColor = UIColor.blue.cgColor


Если требуется скругление углов, то делаем так

view.layer.cornerRadius = 5.0


Достоинства: простота использования. Можно сделать простую контурную обводку с прямыми или скругленными углами.
Недостатки: Обводка рисуется только замкнутая. Нет возможности ограничить обводку только одной из сторон.
Ограничения: Используется для замкнутых контуров, например, кнопок, полей ввода, и т.п.

Способ №2. Использование дополнительных UIVIew

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

пример:

// рисуем границу сверху и справа
let viewBorderTop = UIView(frame: CGRect(x: 0, y: 0, width: view1_1.bounds.width, height: 3.0))
viewBorderTop.backgroundColor = UIColor.red
let viewBorderRight = UIView(frame: CGRect(x: view1_1.bounds.width - 3.0, y: 0, width: 3.0, height: view1_1.bounds.height))
viewBorderRight.backgroundColor = UIColor.red

view.addSubview(viewBorderTop)
view.addSubview(viewBorderRight)

Достоинства: Простота использования. Можно отрисовывать не все грани, а грани на выбор.
Недостатки: Можно использовать только для отрисовки прямых границ. При изменении размеров представления необходимо корректировать frame у дополнительных представлений или использовать констрейнты.
Усложняется иерархия UIView.
Ограничения: Используется обычно для добавления линий отсечки или линий разграничителей.

Способ №3. Использование шейпового слоя CAShapeLayer

Шейповый слой позволяет нам рисовать любые пути, какие только мы сможем вообразить.
Их можно задать как в коде, с помощью соответствующих функций класса UIBezierPath, так и импортировать из векторных редакторов. В последнем случае для этого используется формат SVG и сторонние библиотеки, например, UIBezierPath-SVG (https://github.com/ap4y/UIBezierPath-SVG)

пример:

// создаем шейповый слой
let shapeLayer = CAShapeLayer()
shapeLayer.frame = view.layer.bounds

// путь
let bounds = shapeLayer.bounds
let radius: CGFloat = 15.0

let points = [
/* 0 */ CGPoint(x: bounds.origin.x, y: bounds.origin.y + radius),
/* 1 */ CGPoint(x: bounds.origin.x + radius, y: bounds.origin.y),
/* 2 */ CGPoint(x: bounds.origin.x + bounds.width - radius, y: bounds.origin.y),
/* 3 */ CGPoint(x: bounds.origin.x + bounds.width, y: bounds.origin.y + radius),
/* 4 */ CGPoint(x: bounds.origin.x + bounds.width, y: bounds.origin.y + bounds.height - radius),
/* 5 */ CGPoint(x: bounds.origin.x + bounds.width - radius, y: bounds.origin.y + bounds.height),
/* 6 */ CGPoint(x: bounds.origin.x + radius, y: bounds.origin.y + bounds.height),
/* 7 */ CGPoint(x: bounds.origin.x, y: bounds.origin.y + bounds.height - radius)
]

let path = UIBezierPath()
path.move(to: points[0])
path.addCurve(to: points[1],
controlPoint1: CGPoint(x: points[0].x + radius*0.6, y: points[0].y),
controlPoint2: CGPoint(x: points[1].x, y: points[1].y + radius*0.6))
path.addLine(to: points[2])
path.addCurve(to: points[3],
controlPoint1: CGPoint(x: points[2].x, y: points[2].y + radius*0.6),
controlPoint2: CGPoint(x: points[3].x - radius*0.6, y: points[3].y))
path.addLine(to: points[4])
path.addCurve(to: points[5],
controlPoint1: CGPoint(x: points[4].x - radius*0.6, y: points[4].y),
controlPoint2: CGPoint(x: points[5].x , y: points[5].y - radius*0.6))
path.addLine(to: points[6])
path.addCurve(to: points[7],
controlPoint1: CGPoint(x: points[6].x, y: points[6].y - radius*0.6),
controlPoint2: CGPoint(x: points[7].x + radius*0.6, y: points[7].y))
path.close()
path.stroke()

// параметры линии и заливки
shapeLayer.lineWidth = 3.0
shapeLayer.strokeColor = UIColor.magenta.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor

// назначаем путь
shapeLayer.path = path.cgPath

// добавляем слой с путем на представление
view.layer.addSublayer(shapeLayer)
view.backgroundColor = colorBlue


Достоинства: Путь для обводки ограничен только вашим воображением. Замыкать ее тоже не обязательно. Наряду с обводкой можно использовать заливку. Также CAShapeLayer имеет параметры для управления частичной отрисовкой пути (strokeStart, strokeEnd) и это часто применяется для анимирования прорисовки обводки.
Недостатки: Реализация путей в коде не совсем тривиальная задача. Для более сложных вариантов потребуется использование сторонних библиотек.
Ограничения: не выявлены

Заключение

В своей практике я использую каждый из этих подходов в зависимости от поставленной задачи. Если надо отрисовать контур кнопки, то способ №1, если на границе представления идет линия отсечки, то способ №2, если надо нарисовать фигурную окантовку или требуется анимировать длину пути, то способ №3. В каждом конкретном случае приоритет отдается методу, который способен решить поставленную задачу проще и быстрее.

Примеры на реальных экранах:

На этом все! Всех благ!

Подписывайтесь! Будет интересно! )

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *