Проблема с масштабированием ImagePreview SwiftUIIOS

Программируем под IOS
Ответить
Anonymous
 Проблема с масштабированием ImagePreview SwiftUI

Сообщение Anonymous »

Я новичок в SwiftUI, поэтому прошу прощения, если это очень простой вопрос. В настоящее время я создаю представление, которое позволяет пользователям видеть изображения, которые они ранее добавили в приложение, в полноэкранном режиме.
У меня возникает много проблем при попытке добавить в представление функцию масштабирования ( последние 2 недели я боролся).
Мне удалось заставить работать масштабирование, но это не очень плавно, и поэтому я не могу понять, как увеличить масштаб в определенном месте, а не только по центру. Пользователи ожидают, что место, где они сжимают, будет отражать масштаб масштабирования, но у меня это не работает. Я также хочу, чтобы у пользователя была возможность перемещаться по этому увеличенному изображению, но приложению сложно отличить перетаскивание, чтобы закрыть представление, и пользователя, желающего панорамировать изображение.
В целом представление просто очень тормозит и не реагирует. и не очень хороший интерфейс. У большинства приложений есть такая возможность, поэтому я наверняка что-то упускаю, это не может быть так сложно.
Другие решения, которые я видел, имеют аналогичную проблему с моим: приложение не может одновременно перетаскивать отпустите и сведите пальцы для масштабирования/панорамирования для навигации, поскольку они не различаются.
struct FullScreenImageView: View {
let image: UIImage
@Binding var selectedImage: UIImage?
@Environment(\.presentationMode) var presentationMode
@State private var showControls = false
@State private var dragOffset = CGSize.zero
@State private var scale: CGFloat = 1.0
@State private var contentOffset = CGSize.zero // Tracks the image position when zoomed in

var body: some View {
ZStack {
// Background
Color.gray.ignoresSafeArea()
Color.black
.opacity(1 - Double(abs(dragOffset.height) / 300))
.ignoresSafeArea()

// Image
Image(uiImage: image)
.resizable()
.scaledToFit()
.ignoresSafeArea()
.offset(x: contentOffset.width + dragOffset.width, y: contentOffset.height + dragOffset.height)
.scaleEffect(scale)
.gesture(
DragGesture()
.onChanged { value in
if scale > 1.0 { // Only allow dragging when zoomed in
dragOffset = value.translation
} else {
dragOffset = CGSize(width: 0, height: value.translation.height)
}
}
.onEnded { value in
if scale > 1.0 {
// Update content offset and clamp within bounds
let newOffset = CGSize(
width: contentOffset.width + value.translation.width,
height: contentOffset.height + value.translation.height
)
contentOffset = clampOffset(newOffset, scale: scale)
dragOffset = .zero
} else {
// Handle drag-to-dismiss when not zoomed in
if abs(dragOffset.height) > 150 {
presentationMode.wrappedValue.dismiss()
} else {
withAnimation {
dragOffset = .zero
}
}
}
}
)
.gesture(
MagnificationGesture()
.onChanged { value in
scale = max(1.0, value) // Prevent scale below 1.0
}
.onEnded { _ in
withAnimation {
scale = max(1.0, scale) // Reset scale to 1.0 if too small
contentOffset = clampOffset(contentOffset, scale: scale) // Clamp offset after zooming
}
}
)
.onTapGesture {
withAnimation {
showControls.toggle()
}
}

// Control Bar
if showControls {
VStack {
HStack {
// Close Button
Button(action: {
presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "xmark")
.font(.title2)
.padding()
}
Spacer()
// Share Button
ShareLink(item: Image(uiImage: image), preview: SharePreview("Receipt")) {
Image(systemName: "square.and.arrow.up")
.font(.title2)
}
.padding()
// Trash Button
Button(action: {
selectedImage = nil
presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "trash")
.foregroundColor(.red)
.font(.title2)
.padding()
}
}
.frame(maxWidth: .infinity)
.frame(height: 45)
.background(
Color(red: 0.1, green: 0.1, blue: 0.1)
.opacity(1 - Double(abs(dragOffset.height) / 300))
)
.foregroundColor(.white)
.padding(.top, 10)
Spacer()
}
.transition(.move(edge: .top))
}
}
.statusBarHidden(true)
}

// Function to Clamp Offset to Prevent Image from Moving Out of Bounds
private func clampOffset(_ offset: CGSize, scale: CGFloat) -> CGSize {
// Calculate image dimensions based on the current scale
let imageWidth = UIScreen.main.bounds.width * scale
let imageHeight = UIScreen.main.bounds.height * scale

// Calculate horizontal and vertical bounds
let horizontalBound = (imageWidth - UIScreen.main.bounds.width) / 2
let verticalBound = (imageHeight - UIScreen.main.bounds.height) / 2

// Clamp the offset within the bounds
let clampedWidth = min(max(offset.width, -horizontalBound), horizontalBound)
let clampedHeight = min(max(offset.height, -verticalBound), verticalBound)

return CGSize(width: clampedWidth, height: clampedHeight)
}
}


Подробнее здесь: https://stackoverflow.com/questions/793 ... ue-swiftui
Ответить

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

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

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

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

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