Когда я перемещаю палец по изображению с помощью SwiftUI, я хочу сканировать перемещаемую область, я хочу, чтобы она была полой и имела края. Я пробовал много способов сделать это с помощью контура или холста, множество видов перетаскивания, но я не смог добавить рамку по краям и не смог сделать это задав диаметр, могу только нарисовать линию, как это сделать, прилагаю образец изображения.
Я перемещаю палец по изображению, и когда я отпускаю его, я хочу, чтобы область, которую я прохожу, выглядела следующим образом: я пробовал такие алгоритмы, как выпуклая оболочка, и не смог найти решение.
Вот что я попробовал.
struct Circular: View {
@State private var erasedPoints: [CGPoint] = []
var body: some View {
ZStack {
Image("img4")
.resizable()
.scaledToFit()
.overlay(
Color.red
.mask(eraserShape())
.blendMode(.colorDodge)
)
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { value in
erasedPoints.append(value.location)
}
)
}
}
func eraserShape() -> Path {
var path = Path()
for point in erasedPoints {
let rect = CGRect(x: point.x - 15, y: point.y - 15, width: 30, height: 30)
path.addEllipse(in: rect)
}
return path
}
}
Мой результат.
чего я хочу достичь
обновлено, в основном то, что я сделал.
Вместо добавления эллипсов к пути вам следует нарисовать линию, соединяющую erasedPoints
.
Затем создайте форму, которая будет сформирована, если эту линию нужно обвести, используя ширину линии 30 пунктов, используя strodPath .
Поглаживание этой формы дает желаемый результат. Но перед этим вам также следует нормализовать(eoFill: false), потому что, видимо, путь, созданный strokedPath
, немного беспорядочный.
func eraserShape() -> Path {
var path = Path()
path.addLines(erasedPoints)
return path
.strokedPath(.init(lineWidth: 30, lineCap: .round, lineJoin: .round))
.normalized(eoFill: false)
}
и измените наложение изображения на:
.overlay {
eraserShape().stroke(.blue, lineWidth: 3)
}
В iOS 16 вместо этого вы можете работать напрямую с CGPath
:
func eraserShape() -> Path {
var path = Path()
path.addLines(erasedPoints)
return Path(
path.cgPath
.copy(strokingWithWidth: 30, lineCap: .round, lineJoin: .round, miterLimit: 10)
.normalized(using: .winding)
)
}
Спасибо! он работает, но нужно небольшое обновление. func EraserShape() -> Path { var path = Path() path.addLines(erasedPoints) путь возврата .strokedPath(.init(lineWidth: 30, lineCap: .round, lineJoin: .round)) .normalized(eoFill: false) } он также рисовал случайные прямые линии, если мы сделаем параметр lineJoin равным .round, мы решим и эту проблему. еще раз спасибо.
@dshn Правда? Я знаю, что он рисует случайные прямые линии без normalized
, но в ходе моего тестирования этого не произошло. В любом случае я обновил ответ.
сделанный! Итак, у меня есть еще один вопрос. Как я могу использовать эту нарисованную область как форму клипа? Я хочу вырезать любой вид с помощью clipShape, как я нарисовал.
@dshn Просто передайте eraserShape()
прямо на clipShape
, без поглаживания.
мне очень жаль, но мне это нужно в iOS 15, .нормализовано в iOS 17...
@dshn К сожалению, CGPath.normalized
доступен начиная с iOS 16. Я не знаю, как это сделать на iOS 15, извините.
Мы не сможем помочь вам устранить неполадки, если вы не поделитесь тем, что у вас есть, и не расскажете нам, что не работает.