Парку, чтобы применить перспективную варку к текстовому пути в Swiftui, текст просто движется вместо растяжения или сжимIOS

Программируем под IOS
Ответить
Anonymous
 Парку, чтобы применить перспективную варку к текстовому пути в Swiftui, текст просто движется вместо растяжения или сжим

Сообщение Anonymous »

Я пытаюсь реализовать эффект перспективы варп на текст в Swiftui. Однако, когда я пытаюсь преобразовать текстовый путь, он только перемещает текст, а не растягивая или сжимая его, как и ожидалось в перспективной трансформации. Моя цель состоит в том, чтобы исказить текст вдоль набора точек (левый верхний, верхний, правый, правый нижний и нижний левый), чтобы создать перспективный эффект, аналогичный редактору фото. < /P>
Вот код, который я использую для достижения эффекта:
import SwiftUI

struct PerspectiveWarpView: View {
@State private var points: [CGPoint] = [] // Initially empty
@State var color: Color = .white
@State var position: CGPoint = CGPoint(x: 100, y: 300)
@State var position2: CGPoint = CGPoint(x: 100, y: 250)
@State private var initialPosition: CGPoint = .zero

var body: some View {
GeometryReader { geometry in
ZStack {
Color.black.edgesIgnoringSafeArea(.all)

if !points.isEmpty, let warpedPath = transformTextPath() {
warpedPath
.fill(color)
.position(position)
.gesture(DragGesture().onChanged { value in
if initialPosition == .zero {
initialPosition = position
}
let newPosition = CGPoint(
x: initialPosition.x + value.translation.width,
y: initialPosition.y + value.translation.height
)
DispatchQueue.main.async {
position = newPosition
position2 = CGPoint(x: newPosition.x, y: newPosition.y - 50)
}
}.onEnded({ _ in
initialPosition = .zero
})
)

PointsView(points: $points, path: warpedPath)
.position(position2)
.onAppear(){
points = getCorners(of: warpedPath)
}
}
}
.onAppear {
// Initialize points based on the screen size
let screenWidth = geometry.size.width
let screenHeight = geometry.size.height
let offsetX = (screenWidth - 300) / 2 // Center horizontally
let offsetY = (screenHeight - 200) / 2 // Center vertically

points = [
CGPoint(x: offsetX + 0, y: offsetY + 0), // Top-left
CGPoint(x: offsetX + 300, y: offsetY + 0), // Top-right
CGPoint(x: offsetX + 300, y: offsetY + 200), // Bottom-right
CGPoint(x: offsetX + 0, y: offsetY + 200) // Bottom-left
]
}
}
}

func getCorners(of path: Path) -> [CGPoint] {
let boundingBox = path.boundingRect
return [
CGPoint(x: boundingBox.minX, y: boundingBox.minY - 10), // Top-left
CGPoint(x: boundingBox.maxX, y: boundingBox.minY - 10), // Top-right
CGPoint(x: boundingBox.maxX, y: boundingBox.maxY + 10), // Bottom-right
CGPoint(x: boundingBox.minX, y: boundingBox.maxY + 10) // Bottom-left
]
}

func transformTextPath() -> Path? {
guard !points.isEmpty else { return nil } // Ensure points are not empty
guard let originalPath = textToPath(text: "ELEVATED", font: .systemFont(ofSize: 80, weight: .bold)) else {
return nil
}

// Apply perspective transform to the path
return warpPath(originalPath, from: defaultRect(), to: points)
}

func textToPath(text: String, font: UIFont) -> Path? {
let attributedString = NSAttributedString(string: text, attributes: [.font: font])
let line = CTLineCreateWithAttributedString(attributedString)
let runArray = CTLineGetGlyphRuns(line) as NSArray

let path = CGMutablePath()
for run in runArray {
let run = run as! CTRun
let count = CTRunGetGlyphCount(run)

for index in 0.. [CGPoint] {
return [
CGPoint(x: 0, y: 0), // Top-left
CGPoint(x: 300, y: 0), // Top-right
CGPoint(x: 300, y: 200), // Bottom-right
CGPoint(x: 0, y: 200) // Bottom-left
]
}

func warpPath(_ path: Path, from src: [CGPoint], to dst: [CGPoint]) -> Path {
var newPath = Path()
let transform = computePerspectiveTransform(from: src, to: dst)

path.forEach { element in
switch element {
case .move(to: let point):
newPath.move(to: applyPerspective(point, using: transform))
case .line(to: let point):
newPath.addLine(to: applyPerspective(point, using: transform))
case .quadCurve(to: let point, control: let control):
newPath.addQuadCurve(to: applyPerspective(point, using: transform),
control: applyPerspective(control, using: transform))
case .curve(to: let point, control1: let control1, control2: let control2):
newPath.addCurve(to: applyPerspective(point, using: transform),
control1: applyPerspective(control1, using: transform),
control2: applyPerspective(control2, using: transform))
case .closeSubpath:
newPath.closeSubpath()
}
}
return newPath
}

func computePerspectiveTransform(from src: [CGPoint], to dst: [CGPoint]) -> [[CGFloat]] {
let x0 = src[0].x, y0 = src[0].y
let x1 = src[1].x, y1 = src[1].y
let x2 = src[2].x, y2 = src[2].y
let x3 = src[3].x, y3 = src[3].y

let X0 = dst[0].x, Y0 = dst[0].y
let X1 = dst[1].x, Y1 = dst[1].y
let X2 = dst[2].x, Y2 = dst[2].y
let X3 = dst[3].x, Y3 = dst[3].y

let A = [
[x0, y0, 1, 0, 0, 0, -X0*x0, -X0*y0],
[x1, y1, 1, 0, 0, 0, -X1*x1, -X1*y1],
[x2, y2, 1, 0, 0, 0, -X2*x2, -X2*y2],
[x3, y3, 1, 0, 0, 0, -X3*x3, -X3*y3],
[0, 0, 0, x0, y0, 1, -Y0*x0, -Y0*y0],
[0, 0, 0, x1, y1, 1, -Y1*x1, -Y1*y1],
[0, 0, 0, x2, y2, 1, -Y2*x2, -Y2*y2],
[0, 0, 0, x3, y3, 1, -Y3*x3, -Y3*y3]
]

let B = [X0, X1, X2, X3, Y0, Y1, Y2, Y3]

guard let h = solveLinearSystem(A: A, B: B) else {
return [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
}

return [
[h[0], h[1], h[2]],
[h[3], h[4], h[5]],
[h[6], h[7], 1]
]
}

func solveLinearSystem(A: [[CGFloat]], B: [CGFloat]) -> [CGFloat]? {
let rowCount = A.count
var matrix = A
var result = B

for i in 0..


Подробнее здесь: https://stackoverflow.com/questions/794 ... t-moves-in
Ответить

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

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

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

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

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