SwiftUI: ScrollView

通过观看WWDC2023关于ScrollView的视频,总结一下学习的知识点。

具体的使用方法可以参考下面的代码中的注释:

struct Item: Identifiable {
    var id: Int
}
struct ScrollDemoView: View {
    @State private var items: [Item] = (0 ..< 25).map { Item(id: $0) }
    @State private var scrollId: Int?
    var body: some View {
        ScrollView(.horizontal) {
            LazyHStack(content: {
                ForEach(items) { item in
                    ItemView(item: item)
                    /// 设置宽高比
                        .aspectRatio(1.5, contentMode: .fit)
                    /// 相对于最近容器的布局:此处设置在容器中展示相同宽度的2个view,间隔为5.0
                        .containerRelativeFrame(.horizontal, count: 2, spacing: 5.0)
                        .clipShape(.rect(cornerRadius: 10))
                    /// 每个Item在可见和不可见之间切换时的动画
                        .scrollTransition(axis: .horizontal) { content, phase in
                            content
                            /// 缩放动画
                                .scaleEffect(
                                x: phase.isIdentity ? 1.0 : 0.8,
                                y: phase.isIdentity ? 1.0 : 0.8)
                            /// 旋转动画
                            /*
                                .rotationEffect(.degrees(phase.isIdentity ? 0.0 : 90))
                             */
                            /// 偏移动画
                            /*
                                .offset(
                                    x: phase.isIdentity ? 0.0 : -20,
                                    y: phase.isIdentity ? 0.0 : 20
                                )
                            */
                        }
                        
                }
            })
            /// 指定哪些视图是滚动目标, 此处是指定lazy stack中的每个主视图都被视为滚动目标
            .scrollTargetLayout()
            
        }
        /// 指定scrollview content的边距,并不是scrollview本身的
        .contentMargins(.horizontal, 40.0, for: .scrollContent)
        /// 设置在指定方向的滚动行为
        ///     paging: 翻页滚动,一次滚动一页
        ///     viewAligned: 根据滑动速度滚动不同数量的滚动目标,每次停止时都是完整的展示一页内容。
        .scrollTargetBehavior(.viewAligned)
        .scrollIndicators(.never)
        /// 滑动到的item的id。通过改变当前id,可以编程控制滚动位置
        .scrollPosition(id: $scrollId)
        .overlay(alignment: .center) {
            PageControlView(items: items, scrollId: $scrollId)
                .offset(y: 100)
        }
    }
}

struct ItemView: View {
    var item: Item
    var body: some View {
        Text("\(item.id)")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(.blue)
    }
}

struct PageControlView: View {
    var items: [Item]
    @Binding var scrollId: Int?
    var body: some View {
        HStack {
            Button {
                scrollToPreviousID()
            } label: {
                Label("上一页", systemImage: "chevron.backward.circle")
                    .imageScale(.large)
                    .labelStyle(.iconOnly)

            }
            Spacer()
            Button {
                scrollToNextID()
            } label: {
                Label("下一页", systemImage: "chevron.forward.circle")
                    .imageScale(.large)
                    .labelStyle(.iconOnly)
            }
        }
        .padding(20)
    }
    
    private func scrollToNextID() {
            guard let id = scrollId, id != items.last?.id,
                  let index = items.firstIndex(where: { $0.id == id })
            else { return }

            withAnimation {
                scrollId = items[index + 1].id
            }
        }

        private func scrollToPreviousID() {
            guard let id = scrollId, id != items.first?.id,
                  let index = items.firstIndex(where: { $0.id == id })
            else { return }

            withAnimation {
                scrollId = items[index - 1].id
            }
        }
}
效果图
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容