我注意到UIView.animate與使用withAnimation { }和 SwiftUI 中的一般影片類相比,它沒有那么古怪和“更流暢”,滯后更少。話雖如此,我有一些Flashcards我正在翻轉。問題是,當我使用 時withAnimation { },有時會出現一些延遲,這有時會讓卡片看起來甚至沒有翻轉(看起來卡片內的內容會立即改變)。我在同時呈現的 ScrollView 中有 5 個抽認卡。我如何使用UIView.animate()影片更改?
struct Flashcard<Front, Back>: View where Front: View, Back: View {
var front: () -> Front
var back: () -> Back
@State var flipped: Bool = false
@State var flashcardRotation = 0.0
@State var contentRotation = 0.0
init(@ViewBuilder front: @escaping () -> Front, @ViewBuilder back: @escaping () -> Back) {
self.front = front
self.back = back
}
var body: some View {
ZStack {
if flipped {
ZStack {
back()
VStack {
HStack {
Spacer()
Button(action: {
flipFlashcard()
}, label: {
Text("Flipper")
}).padding(5)
}
Spacer()
}
}
} else {
ZStack {
front()
VStack {
HStack {
Spacer()
Button(action: {
flipFlashcard()
}, label: {
Text("Flipper")
}).padding(5)
}
Spacer()
}
}
}
}
.rotation3DEffect(.degrees(contentRotation), axis: (x: 0, y: 1, z: 0))
.frame(height: 150)
.frame(maxWidth: .infinity)
.padding(.horizontal)
.rotation3DEffect(.degrees(flashcardRotation), axis: (x: 0, y: 1, z: 0))
}
func flipFlashcard() {
let animationTime = 0.25
// My attempt at using UIView.animate()
// UIView.animate(withDuration: 5, animations: {
// flashcardRotation = 180
// })
withAnimation(Animation.linear(duration: animationTime)) {
flashcardRotation = 180
}
// My attempt at using UIView.animate()
// UIView.animate(withDuration: 0.001, delay: animationTime / 2, animations: {
// contentRotation = 180
// flipped.toggle()
// }, completion: nil)
withAnimation(Animation.linear(duration: 0.001).delay(animationTime / 2)) {
contentRotation = 180
flipped.toggle()
}
}
}
uj5u.com熱心網友回復:
您可以使用 aUIViewRepresentable和 aViewModifier來使其用戶友好。
這是通過影響整個UIViewSwiftUI的版本來完成的View。您不會更改 SwiftUI 中的變數View。
該UIViewRepresentable是讓SwiftUI與兼容的UIKit
struct FlipWrapper<Content: View>: UIViewRepresentable{
//The content to be flipped
@ViewBuilder let content: () -> Content
//Triggers the animation
@Binding var flip: Bool
func makeUIView(context: Context) -> UIView {
//Convert SwiftUI View to UIKit UIView
UIHostingController(rootView: content()).view
}
func updateUIView(_ uiView: UIView, context: Context) {
//Variable must be used somewhere or it wont trigger
print(flip)
//Transition is a much easier way to Flip in UIKit
UIView.transition(with: uiView, duration: 0.25, options: .transitionFlipFromRight, animations: nil, completion: nil)
}
}
然后為了便于使用,將包裝器放入 a 中,ViewModifier以便可以像所有其他修飾符一樣訪問它
extension View {
func flipAnimation( flipped: Binding<Bool>) -> some View {
modifier(FlipAnimationViewModifier(flipped: flipped))
}
}
struct FlipAnimationViewModifier: ViewModifier {
@Binding var flipped: Bool
func body(content: Content) -> some View {
FlipWrapper(content: {
content
}, flip: $flipped)
}
}

uj5u.com熱心網友回復:
我不認為在 SwiftUI 中間使用 UIView 影片來影片 SwiftUI 視圖可能是富有成效的,但這不是我嘗試過的。我認為我能夠將您的 SwiftUI 影片修改為性能更高。
這有幾個有趣的方面可能有助于你的表現挑戰,但你并沒有真正說明如何觸發難度(這對我來說似乎很快):
- 這
if可能導致視圖層次結構的重建過于頻繁。你會看到我提出了一種避免使用的方法。 - 您的視圖層次結構相當復雜。我沒有您的全部要求,但我看不出有任何理由翻轉按鈕和所有這些嵌套視圖。您會看到我大大簡化了您的視圖層次結構,它只在單個
ZStack.
從您的描述中我不清楚您是想一次翻轉串列中的所有卡片,還是每張卡片都有一個按鈕并且只想翻轉關聯的卡片(后者對我來說似乎更有意義,但是...... )。
試一試,看看它是否使影片按您希望的方式作業。
在簡單的 macOS 應用程式或 iOS 應用程式 SwiftUI 模板中,將模板 ContentView.swift 替換為以下內容:
import SwiftUI
struct Heart: View {
var body: some View {
Image(systemName: "heart.fill")
.resizable()
.frame(width: 100, height: 100, alignment: .center)
.background(Color.white)
}
}
struct Eye: View {
var body: some View {
Image(systemName: "eye")
.resizable()
.frame(width: 100, height: 100, alignment: .center)
.background(Color.white)
}
}
struct Flashcard<Front, Back>: View where Front: View, Back: View {
var front: () -> Front
var back: () -> Back
@State var flipped: Bool = false
@State var flashcardRotation = 0.0
@State var contentRotation = 0.0
init(@ViewBuilder front: @escaping () -> Front, @ViewBuilder back: @escaping () -> Back) {
self.front = front
self.back = back
}
var body: some View {
VStack {
VStack {
HStack {
Spacer()
Button(action: {
flipFlashcard()
}, label: {
Text("Flipper")
}).padding(5)
}
Spacer()
}
ZStack {
back()
.opacity( Int(contentRotation)%360 >= 180 ? 0.0 : 1.0)
front()
.opacity( Int(contentRotation)%360 < 180 ? 0.0 : 1.0)
}
.frame(height: 150)
.frame(maxWidth: .infinity)
.padding(.horizontal)
.rotation3DEffect(.degrees(contentRotation), axis: (x: 0, y: 1, z: 0))
.rotation3DEffect(.degrees(flashcardRotation), axis: (x: 0, y: 1, z: 0))
}
}
func flipFlashcard() {
let animationTime = 0.25
withAnimation(Animation.linear(duration: animationTime)) {
flashcardRotation = 180
}
withAnimation(Animation.linear(duration: 0.001).delay(animationTime / 2)) {
contentRotation = 180
}
var transaction = Transaction()
transaction.disablesAnimations = true
withTransaction(transaction) {
if contentRotation == 360 { contentRotation = 0 }
if flashcardRotation == 360 { flashcardRotation = 0 }
}
}
}
struct ContentView: View {
var body: some View {
Flashcard(front: { Heart() }, back: { Eye() })
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
不要忘記在設備上試用它,因為模擬器不是衡量性能的好方法。
干杯!
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/408700.html
標籤:
下一篇:在按鈕內居中SVG圖示
