Как создать ластик для CALayer.SubLayer с использованием CAShapeLayer в SwiftIOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 Как создать ластик для CALayer.SubLayer с использованием CAShapeLayer в Swift

Сообщение Anonymous »

Я везде искал ответ на вопрос, который задавался много раз. Я часами просматривал SO и Google. Должен быть ответ, который не потребует усилий по передвижению гор.

Я работаю над приложением для векторного рисования и наконец получил возможность рисовать и отменять действия. функционал рабочий. Теперь мне нужен ластик :-o

РЕДАКТИРОВАТЬ: Согласно замечательному отзыву @DonMag, мне удалось довольно близко подобраться к ластику. , но что-то всё равно не так. Итак, я попытаюсь объяснить, как мои представления и слои находятся в приложении и почему я сделал это именно так:

Начиная с нижнего вида/слоя и заканчивая наверх...
  • BackgroundImageView — я использую это представление изображения для хранения «фона» поверхности рисования. Это слой, который можно изменить, и в нем можно сохранять и вызывать новые «шаблоны». Я храню его отдельно, чтобы пользователь не мог стереть поверхность рисования. А фон состоит из CAShapeLayers, которые рисуются для представления различных типов бумаги.
  • MainImageView — я использую это представление изображения для выполнения всех рисунков, которые инициирует пользователь. . Поэтому я касаюсь и перетаскиваю палец, и в представление изображения добавляется новый CAShapeLayer. Благодаря этому рисунок пользователя отделяется от «поверхности рисования». Это также то место, где я хочу, чтобы произошло удаление.
    PageImagesView – я использую это представление для хранения изображений, которые пользователь может добавить на страницу и переместить/ измените их размер. Я не хочу, чтобы ластик влиял на изображение, но если линия, нарисованная в MainImageView, пересекает изображение и ее необходимо стереть, она должна пропускать изображение, а не удалять части изображения.
Я также добавил еще один слой, пытаясь заставить ластик работать, и назвал его «EraserImageView» и рисовал «маску». в него, а затем пытаюсь применить эту маску к MainImageView.

Вот мой код рисования, который вызывается каждый раз, когда вызывается touchesMoved:

< strong>РЕДАКТИРОВАНИЕ:
Добавление кода ластика в мой код рисования.

Код: Выделить всё

 if eraser {
let linePath = UIBezierPath()

for (index, point) in line.enumerated() {
if index == 0 {
midPoint = CGPoint(
x: (point.x + point.x) / 2,
y: (point.y + point.y) / 2
)
linePath.move(to: midPoint!)
} else {
midPoint = CGPoint(
x: (point.x + line[index - 1].x) / 2,
y: (point.y + line[index - 1].y) / 2
)
linePath.addQuadCurve(to: midPoint!, controlPoint: line[index - 1])
}
}

let maskLayer = CAShapeLayer()
maskLayer.lineWidth = brush
maskLayer.lineCap = .round
maskLayer.strokeColor = UIColor.black.cgColor
maskLayer.fillColor = nil
maskLayer.frame = backgroundImageView.bounds
maskLayer.path = linePath.cgPath
//eraserImageView.layer.addSublayer(backgroundImageView.layer)
eraserImageView.layer.addSublayer(maskLayer)
eraserImageView.layer.mask = mainImageView.layer
}
Приведенный выше код приводит к исчезновению всего пользовательского рисунка, за исключением той части, к которой прикасается «ластик». Я знаю, что у меня что-то не так, или я неправильно наношу маску. Есть ли у кого-нибудь решение?

Нарисовал несколько линий, и это выглядит великолепно...

[
Изображение


Когда я пытаюсь использовать ластик, происходит вот что...

Изображение


Как видите выше, я могу рисовать линии, но как только я коснусь ластика на странице он удаляет все, кроме той части, к которой я прикасаюсь ластиком.

Кто-нибудь знает, в чем я ошибаюсь??
Изменить:
SO ЗАКРЫТЬ!
Мне удалось заставить ластик удалить часть нарисованной линии, когда я двигаю пальцем. Но он не рисует с использованием размеров, а создает формы. Он также заменяет все «стертые» части, как только я касаюсь поверхности рисования после использования ластика.

Вот мой новый код ластика:

Вот мой новый код ластика:

Вот мой новый код ластика:

сильный>

Код: Выделить всё

if eraser {
//var rect: CGRect = CGRect()
let linePath = UIBezierPath(rect: mainImageView.bounds)

for (index, point) in line.enumerated() {
if index == 0 {
midPoint = CGPoint(
x: (point.x + point.x) / 2,
y: (point.y + point.y) / 2
)
//rect = CGRect(x: midPoint!.x, y: midPoint!.y, width: brush, height: brush)
linePath.move(to: midPoint!)
} else {
midPoint = CGPoint(
x: (point.x + line[index - 1].x) / 2,
y: (point.y + line[index - 1].y) / 2
)
//rect = CGRect(x: midPoint!.x, y: midPoint!.y, width: brush, height: brush)
linePath.addQuadCurve(to: midPoint!, controlPoint: line[index - 1])
}
}

let maskLayer = CAShapeLayer()
maskLayer.lineWidth = brush
maskLayer.lineCap = .round
maskLayer.strokeColor = UIColor.clear.cgColor
maskLayer.fillColor = UIColor.black.cgColor
maskLayer.opacity = 1.0
maskLayer.path = linePath.cgPath
maskLayer.fillRule = .evenOdd
mainImageView.layer.addSublayer(maskLayer)
mainImageView.layer.mask = maskLayer

}
Вот результат:
Изображение


Есть идеи, как заставить ластик рисовать так же, как линии?

РЕДАКТИРОВАНИЕ: Добавление кода для фонового «рисования» по запросу @ДонМаг[/b]

Код: Выделить всё

import Foundation
import UIKit

class DrawBulletLayer : UIView {

private var bullet: CAShapeLayer?

func drawBullets(coordinates: UIImageView, bulletColor: UIColor) -> CALayer {
let bullet = self.bullet ?? CAShapeLayer()
let bulletPath = UIBezierPath()

bullet.contentsScale = UIScreen.main.scale

var bullets: [CGPoint] = []
let width = coordinates.frame.width
let height = coordinates.frame.height

let widthBullets = CGFloat(width / 55)
let heightBullets = CGFloat(height / 39)

var hb: CGFloat?
var wb: CGFloat?

for n in 1...39 {
hb = heightBullets * CGFloat(n)
for o in 1...55 {
wb = widthBullets * CGFloat(o)
bullets.append(CGPoint(x: wb!, y: hb!))
}
}

UIColor.black.setStroke()

bullets.forEach { point in
bulletPath.move(to: point)
bulletPath.addLine(to: point)
}

bullet.path = bulletPath.cgPath
bullet.opacity = 1.0
bullet.lineWidth = 2.0
bullet.lineCap = .round
bullet.fillColor = UIColor.clear.cgColor
bullet.strokeColor = bulletColor.cgColor

if self.bullet == nil {
self.bullet = bullet
layer.addSublayer(bullet)
}

return layer
}
}
Вот как он добавляется в BackgroundImageView:

Код: Выделить всё

func updateTemplate() {
let templates = TemplatePickerData()
var loadLayer = templates.loadTemplateIds()
if loadLayer.count == 0 {
_ = templates.loadTemplates()
loadLayer = templates.loadTemplateIds()
}
print("this is the template ID: \(templateId)")
//let templateId = loadLayer[template].value(forKey: "templateId") as! Int
if template <  0 {
template = 0
}

switch template {
case 0:
//scrollView.image = UIImage(named: "habitTracker0")!
scrollView.backgroundImageView.layer.sublayers?.removeAll()
scrollView.backgroundImageView.layer.addSublayer(drawBullets.drawBullets(coordinates: scrollView.backgroundImageView, bulletColor: UIColor(red: 214.0/255.0, green: 214.0/255.0, blue: 214.0/255.0, alpha: 1.0)))
scrollView.setNeedsLayout()
scrollView.layoutIfNeeded()
scrollView.setNeedsDisplay()
case 1:
//scrollView.image = UIImage(named: "monthTemplate0")!
scrollView.backgroundImageView.layer.sublayers?.removeAll()
scrollView.backgroundImageView.layer.addSublayer(drawNotes.drawLines(coordinates: scrollView.backgroundImageView, lineColor: UIColor(red: 214.0/255.0, green: 214.0/255.0, blue: 214.0/255.0, alpha: 1.0)))
scrollView.setNeedsLayout()
scrollView.layoutIfNeeded()
scrollView.setNeedsDisplay()
case 2:
//scrollView.image = UIImage(named: "habitTracker0")!
scrollView.backgroundImageView.layer.sublayers?.removeAll()
scrollView.backgroundImageView.layer.addSublayer(drawNotes2.drawLines(coordinates: scrollView.backgroundImageView, lineColor: UIColor(red: 214.0/255.0, green: 214.0/255.0, blue: 214.0/255.0, alpha: 1.0)))
scrollView.setNeedsLayout()
scrollView.layoutIfNeeded()
scrollView.setNeedsDisplay()
default:
if loadLayer.count > template {
template = 0
}
print("this layer is named: \(loadLayer[template].value(forKey: "templateName") as! String)")
let layer = loadLayer[template].value(forKey: "templatePath") as! String
templateId = loadLayer[template].value(forKey: "templateId") as! Int
let thisTemplate = templates.loadImage(image: layer)

scrollView.backgroundImageView.layer.sublayers?.removeAll()
scrollView.backgroundImageView.layer.addSublayer(drawBullets.drawBullets(coordinates: scrollView.backgroundImageView, bulletColor: UIColor(red: 214.0/255.0, green: 214.0/255.0, blue: 214.0/255.0, alpha: 1.0)))
scrollView.backgroundImageView.layer.addSublayer(thisTemplate)
scrollView.setNeedsLayout()
scrollView.layoutIfNeeded()
scrollView.setNeedsDisplay()
}
scrollView.setNeedsDisplay()

if optionsMenuView.pageNameTextField.text != "" {
if isYear {
page = optionsMenuView.savePage(journalName: journalName, monthName: nil, weekName: nil, yearName: yearName, yearPosition: yearPosition, pageDrawingPath: pageDrawingPath, originalName: originalYearName, brushColor: 1, brushSize: brushSizeMenuView.brushSlider.value, templateId: templateId, pageDrawing: scrollView.mainImageView.layer)
} else {
page = optionsMenuView.savePage(journalName: journalName, monthName: monthName, weekName: weekName, yearName: nil, yearPosition: nil, pageDrawingPath: pageDrawingPath, originalName: originalWeekName, brushColor: 1, brushSize: brushSizeMenuView.brushSlider.value, templateId: templateId, pageDrawing: scrollView.mainImageView.layer)
}
}
optionsMenuView.templateId = templateId
}
Надеюсь, это поможет больше...

Подробнее здесь: https://stackoverflow.com/questions/573 ... r-in-swift
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • WPF: Как реализовать ластик изображений?
    Anonymous » » в форуме C#
    0 Ответы
    19 Просмотры
    Последнее сообщение Anonymous
  • Как реализовать ластик в Fabric.js 6.6.1
    Anonymous » » в форуме Javascript
    0 Ответы
    6 Просмотры
    Последнее сообщение Anonymous
  • Инвертировать маску CALayer, основанную на обводке (без заливки)
    Anonymous » » в форуме IOS
    0 Ответы
    31 Просмотры
    Последнее сообщение Anonymous
  • Как изменить размер CALayer (AVSampleBufferDisplayLayer), чтобы он соответствовал UIView, завернутый в SwiftUI
    Anonymous » » в форуме IOS
    0 Ответы
    29 Просмотры
    Последнее сообщение Anonymous
  • Почему метод рисования пользовательского CALayer не вызывается ранее?
    Anonymous » » в форуме IOS
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous

Вернуться в «IOS»