Рисование UIBezierPath на сгенерированном коде UIView
у меня есть UIView
добавлено в коде во время выполнения.
Я хочу нарисовать UIBezierPath
в нем, но означает ли это, что я должен переопределить drawRect
для наследник UIView?
или есть другой способ рисования на заказ UIView
?
вот код для генерации UIView
:
UIView* shapeView = [[UIView alloc]initWithFrame:CGRectMake(xOrigin,yOrigin+(i*MENU_BLOCK_FRAME_HEIGHT), self.shapeScroll.frame.size.width, MENU_BLOCK_FRAME_HEIGHT)];
shapeView.clipsToBounds = YES;
и вот функция для создания и возврата UIBezierPath
:
- (UIBezierPath*)createPath
{
UIBezierPath* path = [[UIBezierPath alloc]init];
[path moveToPoint:CGPointMake(100.0, 50.0)];
[path addLineToPoint:CGPointMake(200.0,50.0)];
[path addLineToPoint:CGPointMake(200.0, 200.0)];
[path addLineToPoint:CGPointMake(100.0, 200.0)];
[path closePath];
return path;
}
6 ответов
как сделать путь Безье в пользовательском представлении
вот основные шаги:
- дизайн контура формы, которую вы хотите.
- разделить контура на сегменты линии, дуги и кривые.
- создайте этот путь программно.
- нарисуйте путь либо в
drawRect
или черезCAShapeLayer
.
дизайн формы контура
можно делать что угодно, но в качестве примера я выбрал форму ниже. Это может быть всплывающая клавиша на клавиатуре.
разделите путь на сегменты
оглянитесь на свой дизайн формы и разбейте его на более простые элементы линий (для прямых), дуг (для окружностей и круглых углов) и кривых (для чего-либо еще).
вот как будет выглядеть наш пример дизайна:
- черный отрезков
- светло-голубые сегменты дуги
- красные кривые
- Оранжевые точки являются контрольными точками для кривых
- зеленые точки-это точки между путями сегменты
- пунктирные линии показывают прямоугольник
- темно-синие числа-это сегменты в том порядке, в котором они будут добавлены программно
построить путь программно
мы произвольно начинаем в левом нижнем углу и работать по часовой стрелке. Я буду использовать сетку на изображении, чтобы получить значения x и y для точек. Я закодирую все здесь, но, конечно, вы не сделаете этого в реальном проект.
основной процесс:
- создать новый
UIBezierPath
- выберите начальную точку на пути с
moveToPoint
- добавить сегменты в путь
- строку:
addLineToPoint
- arc:
addArcWithCenter
- кривой:
addCurveToPoint
- строку:
- закрыть путь с
closePath
вот код, чтобы сделать путь в образе выше.
func createBezierPath() -> UIBezierPath {
// create a new path
let path = UIBezierPath()
// starting point for the path (bottom left)
path.move(to: CGPoint(x: 2, y: 26))
// *********************
// ***** Left side *****
// *********************
// segment 1: line
path.addLine(to: CGPoint(x: 2, y: 15))
// segment 2: curve
path.addCurve(to: CGPoint(x: 0, y: 12), // ending point
controlPoint1: CGPoint(x: 2, y: 14),
controlPoint2: CGPoint(x: 0, y: 14))
// segment 3: line
path.addLine(to: CGPoint(x: 0, y: 2))
// *********************
// ****** Top side *****
// *********************
// segment 4: arc
path.addArc(withCenter: CGPoint(x: 2, y: 2), // center point of circle
radius: 2, // this will make it meet our path line
startAngle: CGFloat(M_PI), // π radians = 180 degrees = straight left
endAngle: CGFloat(3*M_PI_2), // 3π/2 radians = 270 degrees = straight up
clockwise: true) // startAngle to endAngle goes in a clockwise direction
// segment 5: line
path.addLine(to: CGPoint(x: 8, y: 0))
// segment 6: arc
path.addArc(withCenter: CGPoint(x: 8, y: 2),
radius: 2,
startAngle: CGFloat(3*M_PI_2), // straight up
endAngle: CGFloat(0), // 0 radians = straight right
clockwise: true)
// *********************
// ***** Right side ****
// *********************
// segment 7: line
path.addLine(to: CGPoint(x: 10, y: 12))
// segment 8: curve
path.addCurve(to: CGPoint(x: 8, y: 15), // ending point
controlPoint1: CGPoint(x: 10, y: 14),
controlPoint2: CGPoint(x: 8, y: 14))
// segment 9: line
path.addLine(to: CGPoint(x: 8, y: 26))
// *********************
// **** Bottom side ****
// *********************
// segment 10: line
path.close() // draws the final line to close the path
return path
}
Примечание: некоторые из вышеперечисленных кодов можно уменьшить, добавив строку и дугу в одной команде (поскольку дуга имеет подразумеваемую начальную точку). См.здесь для получения более подробной информации.
контур
мы можем нарисовать путь либо в слое, либо в drawRect
.
метод 1: Нарисуйте путь в слое
наш пользовательский класс выглядит так. Мы добавляем наш путь Безье к новому CAShapeLayer
когда представление инициализируется.
import UIKit
class MyCustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
// Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
// The Bezier path that we made needs to be converted to
// a CGPath before it can be used on a layer.
shapeLayer.path = createBezierPath().cgPath
// apply other properties related to the path
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.position = CGPoint(x: 10, y: 10)
// add the new layer to our custom view
self.layer.addSublayer(shapeLayer)
}
func createBezierPath() -> UIBezierPath {
// see previous code for creating the Bezier path
}
}
и создание нашего представления в контроллере вида, как это
override func viewDidLoad() {
super.viewDidLoad()
// create a new UIView and add it to the view controller
let myView = MyCustomView()
myView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
myView.backgroundColor = UIColor.yellow
view.addSubview(myView)
}
мы получаем...
Хм, это немного мало, потому что я жестко закодировал все цифры. Я могу масштабировать размер пути вверх, хотя, вот так:
let path = createBezierPath()
let scale = CGAffineTransform(scaleX: 2, y: 2)
path.apply(scale)
shapeLayer.path = path.cgPath
Метод 2: Нарисуйте путь в draw
используя draw
медленнее, чем рисование слоя, поэтому это не рекомендуемый метод, если он вам не нужен.
вот пересмотренный код для нашего пользовательского представления:
import UIKit
class MyCustomView: UIView {
override func draw(_ rect: CGRect) {
// create path (see previous code)
let path = createBezierPath()
// fill
let fillColor = UIColor.white
fillColor.setFill()
// stroke
path.lineWidth = 1.0
let strokeColor = UIColor.blue
strokeColor.setStroke()
// Move the path to a new location
path.apply(CGAffineTransform(translationX: 10, y: 10))
// fill and stroke the path (always do these last)
path.fill()
path.stroke()
}
func createBezierPath() -> UIBezierPath {
// see previous code for creating the Bezier path
}
}
что дает нам тот же результат...
дальнейшего изучения
я действительно рекомендуем ознакомиться со следующими материалами. Это то, что наконец сделало пути Безье понятными для меня. (И научил меня произносить это: /bbɛ zi eɪ/.)
- думая, как путь Безье (все, что я когда-либо читал от этого автора, хорошо, и вдохновение для моего примера выше пришло отсюда.)
- Математика Кодирования: Эпизод 19-Кривые Безье (развлекательные и хорошие визуальные иллюстрации)
- Кривые Безье (как они используются в графических приложениях)
- Кривые Безье (хорошее описание как выводятся математические формулы)
было бы проще, если бы вы использовали CAShapeLayer
, например:
CAShapeLayer *shapeView = [[CAShapeLayer alloc] init];
и установить его path
:
[shapeView setPath:[self createPath].CGPath];
наконец-то добавить это:
[[self.view layer] addSublayer:shapeView];
можно использовать CAShapeLayer
для этого.
такой...
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [self createPath].CGPath;
shapeLayer.strokeColor = [UIColor redColor].CGColor; //etc...
shapeLayer.lineWidth = 2.0; //etc...
shapeLayer.position = CGPointMake(100, 100); //etc...
[self.layer addSublayer:shapeLayer];
Это затем добавит и нарисует путь без необходимости переопределять drawRect
.
есть несколько способов выполнить то, что вы хотите. Те, которые я видел больше всего: переопределите drawRect, нарисуйте свою форму в CAShapeLayer а затем добавьте его в качестве подслоя к вашему представлению или нарисуйте свой путь в другой контекст, сохранить как изображение, а затем добавить его в свой вид.
все эти разумные варианты, и какой из них лучше зависит от многих других факторов, таких как вы собираетесь постоянно добавлять фигуры, как часто это называется и т. д.
как указывали другие плакаты, использование слоя формы-хороший способ пойти.
слои формы a, вероятно, дадут вам лучшую производительность, чем переопределение drawRect.
Если вы хотите нарисовать свой путь самостоятельно, то да, вам нужно переопределить drawRect для вашего пользовательского класса представления.
Да, вы должны переопределить drawrect, если хотите что-то нарисовать.Создание UIBezierPath можно сделать в любом месте, но чтобы нарисовать что-то, вы должны сделать это внутри drawrect
метод
вы должны звонить setNeedsDisplay
Если вы переопределите drawRect в подклассе UIView, который в основном представляет собой пользовательский вид, рисующий что-то на экране, например линии,изображение , прямоугольник.