UIBezierPath рендерит часть в прямоугольнике клипа только при рисовании из drawRect/draw представления (_:)?
Я работаю над тестовой программой для рисования рисунков произвольной формы, сглаженных с помощью сплайнов Catmull-Rom. (ссылка) См. "Поваренную книгу " Эрики Садун, разработанную Core iOS Developer для получения "рецепта", показывающего, как рисовать плавные кривые, используя сплайны Catmull-Rom. (Раскрытие информации: я был техническим обозревателем нескольких книг доктора Садуна.)
Образец кода доктора Садуна, написанный на Objective-C, рисует серию отрезков между точками ввода, когда пользователь проводит пальцем, и сглаживает кривую, только когда он отпускает палец.
Я переработал код в Swift 3.
Я также изменил алгоритм так, чтобы он генерировал плавные кривые "вживую", когда пользователь рисует. Выходные данные алгоритма сглаживания представляют собой серию точек, которые необходимо соединить с крошечными отрезками, чтобы создать вид плавной кривой.
Я преобразовываю полученную "полилинию" в UIBezierPath и рисую ее в методе drawRect моего пользовательского подкласса UIView.
Я обнаружил, что математика для создания плавных кривых на самом деле очень быстрая. То, что отнимает много времени, это рисование большого, сложного UIBezierPath
, Когда вы добавляете новую точку в массив входных точек, которые сглаживаются, последняя часть кривой должна быть изменена, чтобы создать плавную кривую вокруг предыдущей контрольной точки, а не "излом".
В результате самое простое, что нужно сделать - просто нарисовать весь путь Безье в каждом вызове DrawRect. Тем не менее, по мере увеличения объекта Bezier Path приложение тратит все больше времени на обслуживание drawRect()
и поэтому отслеживание пути пальца пользователя становится все более и более вялым, а точки, которые он регистрирует по движениям пользователя, становятся все дальше и дальше друг от друга.
Я реализовал ряд оптимизаций. Один из тех, чтобы позвонить setNeedsDisplayInRect()
(Или скорее setNeedsDisplay(_:)
, поскольку это Swift 3), чтобы отметить только небольшую часть вида, которая фактически изменилась как нуждающаяся в перерисовке.
Я был удивлен, обнаружив, что мой drawRect()
(Эр, draw(_:)
функция теперь очень быстрая и больше не застревает.
Кажется, что рендеринг UIBezierPath
Объекты в drawRect() оптимизированы так, что он пропускает части пути, которые находятся за пределами "грязной области" представления (области клипа, которая фактически нуждается в обновлении.)
Это удивило меня. Я ожидал отказаться от рисования с UIBezierPath
и написать собственный код, который нашел части моего рисунка, которые пересекают текущую область клипа, но похоже, что мне не нужно будет этого делать.
Может кто-нибудь подтвердить, что рисование Quartz оптимизирует отрисовку UIBezierPaths внутри метода drawrect() представления, чтобы они эффективно отображали только части пути, которые пересекают текущую обтравочную маску?