return FALSE; $r = well_tag_thread__update(array('id' => $id), $update); return $r; } function well_tag_thread_find($tagid, $page, $pagesize) { $arr = well_tag_thread__find(array('tagid' => $tagid), array('id' => -1), $page, $pagesize); return $arr; } function well_tag_thread_find_by_tid($tid, $page, $pagesize) { $arr = well_tag_thread__find(array('tid' => $tid), array(), $page, $pagesize); return $arr; } ?>ios - How to make collapsible scroll view? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - How to make collapsible scroll view? - Stack Overflow

programmeradmin2浏览0评论

I expect following code to show a scroll view that collapses/expands on button press. However after the expansion scroll position is not preserved. Is there any way to fix this?

    import SwiftUI
    
    struct CollapsibleScrollView: View {
        var items = (0..<100).map { "\($0)" }
        @State var isCollapsed: Bool = false
        var body: some View {
            ZStack {
                VStack {
                    Button {
                        withAnimation {
                            isCollapsed.toggle()
                        }
                    } label: {
                        Text(isCollapsed ? "Expand" : "Collapse")
                    }
                    Spacer()
                }
                if !isCollapsed {
                    scrollView
                }
            }
        }
    
        private var scrollView: some View {
            ScrollView {
                VStack {
                    ForEach(items, id: \.self) { item in
                        GroupBox {
                            HStack {
                                Text(item)
                            }
                                .frame(maxWidth: .infinity)
                        }
                    }
                }
            }
            .frame(maxHeight: 200)
        }
    }
    
    #Preview {
        CollapsibleScrollView()
    }

P.S. "0 height" solution works, but it doesn't work for me since I really need scroll view to be inside if-clause for animation purposes.

P.P.S. Best I could come up with is keeping track of current scroll position with .scrollPosition modifier and reset the scroll after expansion, but it looks ugly.

I expect following code to show a scroll view that collapses/expands on button press. However after the expansion scroll position is not preserved. Is there any way to fix this?

    import SwiftUI
    
    struct CollapsibleScrollView: View {
        var items = (0..<100).map { "\($0)" }
        @State var isCollapsed: Bool = false
        var body: some View {
            ZStack {
                VStack {
                    Button {
                        withAnimation {
                            isCollapsed.toggle()
                        }
                    } label: {
                        Text(isCollapsed ? "Expand" : "Collapse")
                    }
                    Spacer()
                }
                if !isCollapsed {
                    scrollView
                }
            }
        }
    
        private var scrollView: some View {
            ScrollView {
                VStack {
                    ForEach(items, id: \.self) { item in
                        GroupBox {
                            HStack {
                                Text(item)
                            }
                                .frame(maxWidth: .infinity)
                        }
                    }
                }
            }
            .frame(maxHeight: 200)
        }
    }
    
    #Preview {
        CollapsibleScrollView()
    }

P.S. "0 height" solution works, but it doesn't work for me since I really need scroll view to be inside if-clause for animation purposes.

P.P.S. Best I could come up with is keeping track of current scroll position with .scrollPosition modifier and reset the scroll after expansion, but it looks ugly.

Share Improve this question asked Mar 18 at 21:12 Vladimir NikitinVladimir Nikitin 1911 silver badge7 bronze badges 3
  • What "animation purposes" do you have? What do you mean by "but it looks ugly"? Do you feel the code looks ugly or does the effect look visually ugly? – Sweeper Commented Mar 18 at 22:00
  • @Sweeper, 1. I need to be able to apply .transition(insertion: .move(edge: .leading), removal: .move(edge: .leading)) modifier to scrollView in order to perform" slide behind the screen" effect. In fact there is quite a lot this scroll view has to do, but I assume it's irrelevant to the problem. 2. By ugly I mean both. The effect itself turns out to be scroll view expanding with first element scrolled to and then it scrolls to the tracked position, I need it to be static for my purposes. The fact that I have to add this scroll position tracking code looks ugly too. – Vladimir Nikitin Commented Mar 18 at 22:26
  • It's an incredible nuisance doing animating scroll view heights for the reasons you describe. I'm doing one where a row "slides up to the top" and it's a similar problem when you're not on the first page of the scroll :/ I don't even know if there's a good solution in the abstract, Vladimir – Fattie Commented Mar 18 at 22:48
Add a comment  | 

1 Answer 1

Reset to default 1

The easiest way to retain the scroll position is to keep the ScrollView present in the layout, instead of using an if block to remove it when collapsed. Then use maxHeight to determine whether to show it collapsed or expanded:

  • to collapse the scroll view, set maxHeight: 0
  • to show it expanded, set maxHeight: nil.

Here is the updated example to show it working this way. Other concerns are discussed below:

var body: some View {
    VStack {
        Button {
            withAnimation(.easeInOut) {
                isCollapsed.toggle()
            }
        } label: {
            Text(isCollapsed ? "Expand" : "Collapse")
        }
        scrollView
            .frame(maxHeight: isCollapsed ? 0 : nil)
            .padding(.top, 100)
    }
    .padding(.vertical, 100)
    .frame(maxHeight: .infinity, alignment: .top)
}

// private var scrollView: as before


In the question you were saying:

I really need scroll view to be inside if-clause for animation purposes

If this is the case, you will need to track the scroll position, so that it can be restored when the scroll view is made visible again. Using .scrollPosition would be a way of doing this, but you said you didn't like this either. So you might have to make a compromise somewhere.

I would have thought, a transition-like animation would be possible, without having to remove the ScrollView from the layout completely. For example, a sliding horizontal movement can be achieved by adjusting the x-offset. You might also want to chain certain animations together. Using withAnimation combined with a completion callback is one technique that can be used to do this.

发布评论

评论列表(0)

  1. 暂无评论