Как исправить прыжок текст в Draggable Element, когда текст меняется в Swiftui [Duplicate]IOS

Программируем под IOS
Ответить
Anonymous
 Как исправить прыжок текст в Draggable Element, когда текст меняется в Swiftui [Duplicate]

Сообщение Anonymous »

Я строю в Swiftui пользовательский интерфейс, похожий на Tinder, в Swiftui. На каждой карте я накладываю градиент и показываю этикетку статуса («слева», «справа», «вниз») на основе смещения перетаскивания. Чтобы отлаживать макет, я даже придаю тексту цвет фона, чтобы увидеть контейнер. Контейнер остается фиксированным, но текст, кажется, «прыгает» или сдвигается, когда он меняется (например, от пустого на «правый» или от «правого» к «вниз»). Это вызывает резкий эффект при изменении строки во время перетаскивания. < /P>
import SwiftUI

struct CardView: View {
enum SwipeDirection { case left, right, down, none }
struct Model: Identifiable, Equatable {
let id = UUID()
let text: String
var swipeDirection: SwipeDirection = .none
}

var model: Model
var size: CGSize
var dragOffset: CGSize
var isTopCard: Bool
var isSecondCard: Bool

var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(Color(cgColor: UIColor.secondarySystemBackground.cgColor))

Text(model.text)
.font(.largeTitle).bold()
.foregroundColor(.black)

if isTopCard {
let status = getStatusText()
ZStack {
LinearGradient(
gradient: Gradient(stops: [
.init(color: getShadowColor().opacity(0.6), location: 0),
.init(color: .clear, location: 1)
]),
startPoint: .top,
endPoint: .bottom
)
Text(status)
.font(.title)
.fontDesign(.monospaced).bold()
.foregroundColor(.black)
.background(Color.orange) // show container
}
.compositingGroup()
.frame(width: size.width * 0.8, height: size.height * 0.6)
.offset(y: -size.height * 0.2)
.opacity(getStatusOpacity())
}
}
.frame(width: size.width * 0.8, height: size.height * 0.6)
.cornerRadius(15)
.padding()
}

private func getShadowColor() -> Color {
if dragOffset.height > abs(dragOffset.width) {
return Color.blue.opacity(0.8)
} else if abs(dragOffset.width) > abs(dragOffset.height) {
return dragOffset.width > 0 ? Color.green.opacity(0.8) : Color.red.opacity(0.8)
}
return Color.clear
}

private func getStatusText() -> String {
let h = dragOffset.width, v = dragOffset.height
let absX = abs(h), absY = abs(v)
let threshold: CGFloat = 50
let buffer: CGFloat = 10

if absX > absY {
if absX > threshold + buffer {
return h > 0 ? "Right" : "Left"
}
} else if absY > absX {
if absY > threshold + buffer {
return "Down"
}
}
return ""
}

private func getStatusOpacity() -> Double {
let h = dragOffset.width, v = dragOffset.height
let absX = abs(h), absY = abs(v)
let threshold: CGFloat = 50
let maxDistance: CGFloat = 100

let distance = max(absX, absY)
if distance > threshold {
return Double(min((distance - threshold) / (maxDistance - threshold), 1))
}
return 0
}
}

< /code>
struct SwipeableCardsView: View {
class Model: ObservableObject {
private var originalCards: [CardView.Model]
@Published var unswipedCards: [CardView.Model]
@Published var swipedCards: [CardView.Model]

init(cards: [CardView.Model]) {
self.originalCards = cards
self.unswipedCards = cards
self.swipedCards = []
}

func removeTopCard() {
if !unswipedCards.isEmpty {
guard let card = unswipedCards.first else { return }
unswipedCards.removeFirst()
swipedCards.append(card)
print(card.swipeDirection)
}
}

func updateTopCardSwipeDirection(_ direction: CardView.SwipeDirection) {
if !unswipedCards.isEmpty {
unswipedCards[0].swipeDirection = direction
}
}

func reset() {
unswipedCards = originalCards
swipedCards = []
}
}

@ObservedObject var model: Model
@State private var dragState = CGSize.zero
@State private var cardRotation: Double = 0
@GestureState private var isDragging: Bool = false
@State private var hasTriggeredHapticForThisDrag = false

private let swipeThreshold: CGFloat = 100.0
private let rotationFactor: Double = 35.0

var action: (Model) -> Void

var body: some View {
GeometryReader { geometry in
if model.unswipedCards.isEmpty && model.swipedCards.isEmpty {
emptyCardsView
.frame(width: geometry.size.width, height: geometry.size.height)
} else if model.unswipedCards.isEmpty {
swipingCompletionView
.frame(width: geometry.size.width, height: geometry.size.height)
} else {
ZStack {
Color.white.ignoresSafeArea()

ForEach(model.unswipedCards.reversed()) { card in
let isTop = card == model.unswipedCards.first
let isSecond = card == model.unswipedCards.dropFirst().first
let generator = UIImpactFeedbackGenerator(style: .medium)

CardView(
model: card,
size: geometry.size,
dragOffset: dragState,
isTopCard: isTop,
isSecondCard: isSecond
)
.offset(x: isTop ? dragState.width : 0,
y: isTop ? dragState.height : 0)
.rotationEffect(.degrees(isTop ? Double(dragState.width) / rotationFactor : 0))
.onChange(of: isDragging) { _, dragging in
generator.prepare()
if dragging {
generator.impactOccurred()
}
}
.gesture(
DragGesture()
.updating($isDragging) { _, state, _ in
state = true
}
.onChanged { gesture in
dragState = gesture.translation
cardRotation = Double(gesture.translation.width) / rotationFactor
}
.onEnded { _ in
let absX = abs(dragState.width)
let absY = abs(dragState.height)
let horizontalThreshold: CGFloat = swipeThreshold
let verticalThreshold: CGFloat = swipeThreshold

if absX > absY && absX > horizontalThreshold {
// Horizontal swipe
let dir: CardView.SwipeDirection = dragState.width > 0 ? .right : .left
model.updateTopCardSwipeDirection(dir)
withAnimation(.easeOut(duration: 0.5)) {
self.dragState.width = dragState.width > 0 ? 1000 : -1000
self.dragState.height = 0
}
generator.prepare()
generator.impactOccurred()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.model.removeTopCard()
self.dragState = .zero
self.cardRotation = 0
}
} else if absY > absX && dragState.height > verticalThreshold {
// Vertical swipe
model.updateTopCardSwipeDirection(.down)
withAnimation(.easeOut(duration: 0.5)) {
self.dragState.height = 1000
self.dragState.width = 0
}
generator.prepare()
generator.impactOccurred()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.model.removeTopCard()
self.dragState = .zero
self.cardRotation = 0
}
} else {
// Not enough or no clear dominant direction
withAnimation(.spring()) {
self.dragState = .zero
self.cardRotation = 0
}
}
}
)
.animation(.easeInOut, value: dragState)
}
}
.padding()
}
}
}

var emptyCardsView: some View {
VStack {
Text("No Cards")
.font(.title)
.padding(.bottom, 20)
.foregroundStyle(.gray)
}
}

var swipingCompletionView: some View {
VStack {
Text("Finished Swiping")
.font(.title)
.padding(.bottom, 20)

Button(action: {
action(model)
}) {
Text("Reset")
.font(.headline)
.frame(width: 200, height: 50)
.background(Color.accentColor)
.foregroundColor(.white)
.cornerRadius(10)
}
}
}
}

struct ContentView: View {
var body: some View {
VStack {
let cards = [
CardView.Model(text: "Card 1"),
CardView.Model(text: "Card 2"),
CardView.Model(text: "Card 3"),
CardView.Model(text: "Card 4")
]

let model = SwipeableCardsView.Model(cards: cards)
SwipeableCardsView(model: model) { model in
print(model.swipedCards)
model.reset()
}
}
.padding()
}
}
< /code>
Изображение
Изображение


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

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

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

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

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

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