Я работаю над представлением Swiftui, который отображает немного текста, который можно перемещать, изменять и повернуть. Прямо сейчас у меня есть рабочее решение, где пользователь может перетащить стрелку с изменением размера (расположенную в правом нижнем), чтобы изменить размер (и вращение) текста. < /P>
Вот упрощенная версия моего кода:
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct ResizableTextView: View {
let text: String
let isEdittable: Bool
/// Called when the edit (pen) button is tapped.
var onEdit: (() -> Void)?
/// Called when the close (delete) button is tapped.
var onDelete: (() -> Void)?
var onTap: (() -> Void)?
// MARK: - Transformation State Variables
@State private var scale: CGFloat = 1.0
@State private var rotation: Angle = .zero
// "Committed" transformation values from previous gestures.
@State private var lastScale: CGFloat = 1.0
@State private var lastRotation: Angle = .zero
// For tracking the resize gesture’s starting values.
@State private var initialDistance: CGFloat = 0
@State private var initialAngle: Angle = .zero
@State private var isDragging: Bool = false
// The intrinsic size of the text (including padding), measured before any transforms.
@State private var textSize: CGSize = .zero
// MARK: - Position (Drag-to-move) State Variables
@State private var positionOffset: CGSize = .zero
@State private var lastPositionOffset: CGSize = .zero
var body: some View {
GeometryReader { geometry in
// The container's center is used as the anchor point for the text.
let containerCenter = CGPoint(x: geometry.size.width / 2,
y: geometry.size.height / 2)
ZStack {
// Main text view with measured size.
Text(text)
.padding(20)
.background(
GeometryReader { proxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: proxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self) { newSize in
self.textSize = newSize
}
// Apply the current transformations.
.scaleEffect(scale)
.rotationEffect(rotation)
// Draw a border around the text.
.overlay(
Rectangle()
.stroke(Color.gray, lineWidth: isEdittable ? 1 : 0)
.scaleEffect(scale)
.rotationEffect(rotation)
)
// Position the text at the container center.
.position(containerCenter)
// Calculate half of the scaled text dimensions.
let halfWidth = (textSize.width * scale) / 2
let halfHeight = (textSize.height * scale) / 2
let angleRad = rotation.radians
// MARK: - Compute Control Positions
// Bottom-right (Resize control):
let arrowOffsetX = halfWidth * CGFloat(cos(angleRad)) - halfHeight * CGFloat(sin(angleRad))
let arrowOffsetY = halfWidth * CGFloat(sin(angleRad)) + halfHeight * CGFloat(cos(angleRad))
let arrowPosition = CGPoint(x: containerCenter.x + arrowOffsetX,
y: containerCenter.y + arrowOffsetY)
// Top-right (Edit/Pen control):
let penOffsetX = halfWidth * CGFloat(cos(angleRad)) + halfHeight * CGFloat(sin(angleRad))
let penOffsetY = halfWidth * CGFloat(sin(angleRad)) - halfHeight * CGFloat(cos(angleRad))
let penPosition = CGPoint(x: containerCenter.x + penOffsetX,
y: containerCenter.y + penOffsetY)
// Top-left (Close/Delete control):
let closeOffsetX = -halfWidth * CGFloat(cos(angleRad)) + halfHeight * CGFloat(sin(angleRad))
let closeOffsetY = -halfWidth * CGFloat(sin(angleRad)) - halfHeight * CGFloat(cos(angleRad))
let closePosition = CGPoint(x: containerCenter.x + closeOffsetX,
y: containerCenter.y + closeOffsetY)
// MARK: - Add Controls Using Helper Functions
if isEdittable {
closeButton(at: closePosition)
editButton(at: penPosition)
resizeButton(at: arrowPosition, containerCenter: containerCenter)
}
}
// Apply the offset to the entire structure.
.offset(x: positionOffset.width, y: positionOffset.height)
// Attach a drag gesture to reposition the whole structure.
.gesture(
DragGesture()
.onChanged { value in
positionOffset = CGSize(width: lastPositionOffset.width + value.translation.width,
height: lastPositionOffset.height + value.translation.height)
}
.onEnded { _ in
lastPositionOffset = positionOffset
}
)
.onTapGesture {
onTap?()
}
// Ensure the ZStack fills the container.
.frame(width: geometry.size.width, height: geometry.size.height)
}
// Set an arbitrary height for the view (adjust as needed).
.frame(height: 300)
}
// MARK: - Helper Functions for Control Buttons
private func closeButton(at position: CGPoint) -> some View {
Image("iconClose")
.resizable()
.scaledToFit()
.frame(width: 16, height: 16)
.foregroundStyle(.black)
.rotationEffect(.zero)
.padding(4)
.background(
Circle()
.fill(Color.white)
.frame(width: 28, height: 28)
.shadow(radius: 5)
)
.position(position)
.onTapGesture {
onDelete?()
}
}
private func editButton(at position: CGPoint) -> some View {
Image("iconPen")
.resizable()
.scaledToFit()
.frame(width: 16, height: 16)
.foregroundStyle(.black)
.rotationEffect(.zero)
.padding(4)
.background(
Circle()
.fill(Color.white)
.frame(width: 28, height: 28)
.shadow(radius: 5)
)
.position(position)
.onTapGesture {
onEdit?()
}
}
private func resizeButton(at position: CGPoint, containerCenter: CGPoint) -> some View {
Image("iconResize")
.resizable()
.scaledToFit()
.frame(width: 16, height: 16)
.foregroundStyle(.black)
.rotationEffect(Angle(degrees: 80))
.padding(4)
.background(
Circle()
.fill(Color.white)
.frame(width: 28, height: 28)
.shadow(radius: 5)
)
.position(position)
.gesture(
DragGesture()
.onChanged { value in
let currentLocation = value.location
// Compute the vector from the container's center to the current drag location.
let dx = currentLocation.x - containerCenter.x
let dy = currentLocation.y - containerCenter.y
let currentDistance = sqrt(dx * dx + dy * dy)
let currentAngle = Angle(radians: atan2(dy, dx))
if !isDragging {
isDragging = true
initialDistance = currentDistance
initialAngle = currentAngle
} else {
// Adjust scale based on the change in distance.
let scaleFactor = currentDistance / initialDistance
var newScale = lastScale * scaleFactor
newScale = min(max(newScale, 0.1), 5.0)
scale = newScale
// Adjust rotation based on the change in angle.
let angleDelta = currentAngle - initialAngle
rotation = lastRotation + angleDelta
}
}
.onEnded { _ in
isDragging = false
lastScale = scale
lastRotation = rotation
}
)
}
}
< /code>
Функциональность перетаскивания в разрешении через управление стрелкой работает отлично. Тем не менее, я также хочу, чтобы пользователь имел возможность изменять размер (и, возможно, повернуть) представление с использованием жеста с загромождением с двумя пальцами непосредственно на тексте (или во всем представлении), вместо того, чтобы перетаскивать стрелку изменения размера.
Я попытался сделать добавление увеличения (и, возможно, вращения), чтобы справиться с щепоткой, но я сталкиваюсь с несколькими проблемами:
Конфликты жестов: как мне комбинировать или различать существующие жесты перетаскивания (для перемещения и изменения размера) и новых жестов? > < /li>
реализация? Это представление, чтобы разрешить функциональность зажимания (и/или вращения)?
Подробнее здесь: https://stackoverflow.com/questions/794 ... in-my-swif
Как я могу добавить жест щепотки (увеличение и вращение) для изменения размера в моем виде Swiftui вместе с существующим ⇐ IOS
Программируем под IOS
1739043251
Anonymous
Я работаю над представлением Swiftui, который отображает немного текста, который можно перемещать, изменять и повернуть. Прямо сейчас у меня есть рабочее решение, где пользователь может перетащить стрелку с изменением размера (расположенную в правом нижнем), чтобы изменить размер (и вращение) текста. < /P>
[b] Вот упрощенная версия моего кода: [/b]
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct ResizableTextView: View {
let text: String
let isEdittable: Bool
/// Called when the edit (pen) button is tapped.
var onEdit: (() -> Void)?
/// Called when the close (delete) button is tapped.
var onDelete: (() -> Void)?
var onTap: (() -> Void)?
// MARK: - Transformation State Variables
@State private var scale: CGFloat = 1.0
@State private var rotation: Angle = .zero
// "Committed" transformation values from previous gestures.
@State private var lastScale: CGFloat = 1.0
@State private var lastRotation: Angle = .zero
// For tracking the resize gesture’s starting values.
@State private var initialDistance: CGFloat = 0
@State private var initialAngle: Angle = .zero
@State private var isDragging: Bool = false
// The intrinsic size of the text (including padding), measured before any transforms.
@State private var textSize: CGSize = .zero
// MARK: - Position (Drag-to-move) State Variables
@State private var positionOffset: CGSize = .zero
@State private var lastPositionOffset: CGSize = .zero
var body: some View {
GeometryReader { geometry in
// The container's center is used as the anchor point for the text.
let containerCenter = CGPoint(x: geometry.size.width / 2,
y: geometry.size.height / 2)
ZStack {
// Main text view with measured size.
Text(text)
.padding(20)
.background(
GeometryReader { proxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: proxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self) { newSize in
self.textSize = newSize
}
// Apply the current transformations.
.scaleEffect(scale)
.rotationEffect(rotation)
// Draw a border around the text.
.overlay(
Rectangle()
.stroke(Color.gray, lineWidth: isEdittable ? 1 : 0)
.scaleEffect(scale)
.rotationEffect(rotation)
)
// Position the text at the container center.
.position(containerCenter)
// Calculate half of the scaled text dimensions.
let halfWidth = (textSize.width * scale) / 2
let halfHeight = (textSize.height * scale) / 2
let angleRad = rotation.radians
// MARK: - Compute Control Positions
// Bottom-right (Resize control):
let arrowOffsetX = halfWidth * CGFloat(cos(angleRad)) - halfHeight * CGFloat(sin(angleRad))
let arrowOffsetY = halfWidth * CGFloat(sin(angleRad)) + halfHeight * CGFloat(cos(angleRad))
let arrowPosition = CGPoint(x: containerCenter.x + arrowOffsetX,
y: containerCenter.y + arrowOffsetY)
// Top-right (Edit/Pen control):
let penOffsetX = halfWidth * CGFloat(cos(angleRad)) + halfHeight * CGFloat(sin(angleRad))
let penOffsetY = halfWidth * CGFloat(sin(angleRad)) - halfHeight * CGFloat(cos(angleRad))
let penPosition = CGPoint(x: containerCenter.x + penOffsetX,
y: containerCenter.y + penOffsetY)
// Top-left (Close/Delete control):
let closeOffsetX = -halfWidth * CGFloat(cos(angleRad)) + halfHeight * CGFloat(sin(angleRad))
let closeOffsetY = -halfWidth * CGFloat(sin(angleRad)) - halfHeight * CGFloat(cos(angleRad))
let closePosition = CGPoint(x: containerCenter.x + closeOffsetX,
y: containerCenter.y + closeOffsetY)
// MARK: - Add Controls Using Helper Functions
if isEdittable {
closeButton(at: closePosition)
editButton(at: penPosition)
resizeButton(at: arrowPosition, containerCenter: containerCenter)
}
}
// Apply the offset to the entire structure.
.offset(x: positionOffset.width, y: positionOffset.height)
// Attach a drag gesture to reposition the whole structure.
.gesture(
DragGesture()
.onChanged { value in
positionOffset = CGSize(width: lastPositionOffset.width + value.translation.width,
height: lastPositionOffset.height + value.translation.height)
}
.onEnded { _ in
lastPositionOffset = positionOffset
}
)
.onTapGesture {
onTap?()
}
// Ensure the ZStack fills the container.
.frame(width: geometry.size.width, height: geometry.size.height)
}
// Set an arbitrary height for the view (adjust as needed).
.frame(height: 300)
}
// MARK: - Helper Functions for Control Buttons
private func closeButton(at position: CGPoint) -> some View {
Image("iconClose")
.resizable()
.scaledToFit()
.frame(width: 16, height: 16)
.foregroundStyle(.black)
.rotationEffect(.zero)
.padding(4)
.background(
Circle()
.fill(Color.white)
.frame(width: 28, height: 28)
.shadow(radius: 5)
)
.position(position)
.onTapGesture {
onDelete?()
}
}
private func editButton(at position: CGPoint) -> some View {
Image("iconPen")
.resizable()
.scaledToFit()
.frame(width: 16, height: 16)
.foregroundStyle(.black)
.rotationEffect(.zero)
.padding(4)
.background(
Circle()
.fill(Color.white)
.frame(width: 28, height: 28)
.shadow(radius: 5)
)
.position(position)
.onTapGesture {
onEdit?()
}
}
private func resizeButton(at position: CGPoint, containerCenter: CGPoint) -> some View {
Image("iconResize")
.resizable()
.scaledToFit()
.frame(width: 16, height: 16)
.foregroundStyle(.black)
.rotationEffect(Angle(degrees: 80))
.padding(4)
.background(
Circle()
.fill(Color.white)
.frame(width: 28, height: 28)
.shadow(radius: 5)
)
.position(position)
.gesture(
DragGesture()
.onChanged { value in
let currentLocation = value.location
// Compute the vector from the container's center to the current drag location.
let dx = currentLocation.x - containerCenter.x
let dy = currentLocation.y - containerCenter.y
let currentDistance = sqrt(dx * dx + dy * dy)
let currentAngle = Angle(radians: atan2(dy, dx))
if !isDragging {
isDragging = true
initialDistance = currentDistance
initialAngle = currentAngle
} else {
// Adjust scale based on the change in distance.
let scaleFactor = currentDistance / initialDistance
var newScale = lastScale * scaleFactor
newScale = min(max(newScale, 0.1), 5.0)
scale = newScale
// Adjust rotation based on the change in angle.
let angleDelta = currentAngle - initialAngle
rotation = lastRotation + angleDelta
}
}
.onEnded { _ in
isDragging = false
lastScale = scale
lastRotation = rotation
}
)
}
}
< /code>
Функциональность перетаскивания в разрешении через управление стрелкой работает отлично. Тем не менее, я также хочу, чтобы пользователь имел возможность изменять размер (и, возможно, повернуть) представление с использованием жеста с загромождением с двумя пальцами непосредственно на тексте (или во всем представлении), вместо того, чтобы перетаскивать стрелку изменения размера.
[b] Я попытался сделать добавление увеличения (и, возможно, вращения), чтобы справиться с щепоткой, но я сталкиваюсь с несколькими проблемами: [/b]
Конфликты жестов: как мне комбинировать или различать существующие жесты перетаскивания (для перемещения и изменения размера) и новых жестов? > < /li>
реализация? Это представление, чтобы разрешить функциональность зажимания (и/или вращения)?
Подробнее здесь: [url]https://stackoverflow.com/questions/79423066/how-can-i-add-a-pinch-magnification-rotation-gesture-for-resizing-in-my-swif[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия