Анимация / переход SwiftUI в режиме прокрутки ведет себя странно - PullRequest
1 голос
/ 09 мая 2020

У меня есть ScrollView в SwiftUI с несколькими элементами, некоторые из них расширяются при нажатии.

struct ExpandingView: View {

    @State var showContent = false

    var body: some View {
        VStack {
            HStack {
                Button(action: {withAnimation {
                        self.showContent.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                }
                Text("TITLE")
                    .padding(.leading, 10)
                Spacer()
            }
            if showContent {
                Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
            }
        }
    }
}

struct Test: View {

    var body: some View {
        ScrollView {
            ExpandingView()
            ExpandingView()
            ExpandingView()
            Text("Some static text")
        }
    }
}

Если вы попытаетесь открыть один из расширяющихся текстов, вы увидите, что переход не плавный, он похож на скачки, и затем переход начинается.

https://media.giphy.com/media/cjhClEVwgsEQpkBGAv/giphy.gif

Итак, вот что я пробовал:

  • Если я удалю вид прокрутки и помещу это в VStack для Например, он работает нормально, но это не вариант, потому что у меня гораздо больше элементов, которые не помещаются на экране.
  • Я пытался установить анимацию для прокрутки, потому что я читал, что он решает эту проблему своего рода проблема, например:
ScrollView {
            ExpandingView()
            ExpandingView()
            ExpandingView()
            Text("Some static text")
        }.animation(.spring())

Он отлично работает с точки зрения открывающего перехода, он даже выглядит лучше с эффектом пружины, но анимация пружины для всего прокрутки воспроизводится, когда вид появляется, чего я не хочу.

https://media.giphy.com/media/lTMG9mGD0X0qrksYtB/giphy.gif

Опять же, если я изменю ScrollView на VStack, анимация не будет воспроизводиться при появлении, что приятно, но я должен использовать scrollview . Поэтому лучшим решением для меня было бы сохранить анимацию для открытия текстов, но каким-то образом удалить ее при появлении представления.

1 Ответ

3 голосов
/ 09 мая 2020

Вот возможное решение. Читайте также встроенные комментарии. Протестировано с Xcode 11.4 / iSO 13.4

demo

struct ExpandingView: View {

    @State var showContent = false

    var body: some View {
        VStack {
            HStack {
                Button(action: {
                        self.showContent.toggle()
                }) {
                    Image(systemName: "chevron.right.circle")
                }
                Text("TITLE")
                    .padding(.leading, 10)
                Spacer()
            }
            if showContent {
                Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
                    .fixedSize(horizontal: false, vertical: true)
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
            }
        }
    }
}

struct DemoExpandingView: View {

    // initial nil to avoid initial animation
    @State private var animation: Animation? = nil
    var body: some View {
        ScrollView {
            VStack {
                ExpandingView()
                ExpandingView()
                ExpandingView()
                Text("Some static text")
            }.animation(animation) // << needed to animate static section
        }
        .onAppear {
            DispatchQueue.main.async {
                // assign in-container animation `after` container rendered
                self.animation = .default
            }
        }
    }
}
...