75142913在线留言
【SwiftUI实战】下拉更新(追加)列表项_IOS开发_网络人

【SwiftUI实战】下拉更新(追加)列表项

Kwok 发表于:2021-03-31 16:31:49 点击:66 评论: 0

本例主要是根据判断GeometryReader距离系统顶部实时监听用户下拉操作。

SwiftUI实战下拉更新追加列表项

源代码地址:https://github.com/Zyf210304/TopRefreshSwiftUI

// TopRefresh Created by 张亚飞 on 2021/1/24.

import SwiftUI
struct ContentView: View {
    //准备一个菜谱列表显示数组
    @State private var recipeData = ["豉椒炒花甲", "招待宾客的高配菜", "莲藕炖肉", "板栗焖排骨", "农家小炒牛肉丝", "招待宾客的高配菜"]
    @State private var isRefresh = Refresh(started: false, released: false) //刷新状态
    var body: some View {
        VStack (spacing: 0){
            TopTitle(title: "下拉更新列表")
            /*Divider 当包含在stack中时,Divider横跨stack的短轴;当不在stack中时则水平延伸。*/
            Divider()//分频器:可用于分隔其他内容。
            ScrollView{
                //监听下拉事件
                GeometryReader { reader -> AnyView in
                    //利用GeometryReader监听容器向下拉的距离
                    DispatchQueue.main.async {
                        //更新黑夜开始偏移值为距离顶部值
                        if isRefresh.startOffset == 0 {
                            isRefresh.startOffset = reader.frame(in: .global).minY//当前reader距离系统顶部的值:120
                            print("起始偏移量(startOffset):",isRefresh.startOffset) //DeBug:打印全局Y轴偏移量(被更新为了120)
                        }
                        isRefresh.offset = reader.frame(in: .global).minY //实时记录偏移(用户下拉实时更新)
                        //print("偏移量(offset):",isRefresh.offset) //DeBug:打印全局Y轴偏移量(实时打印)
                        if isRefresh.offset - isRefresh.startOffset > 80 && !isRefresh.started {
                            print("偏移差:",isRefresh.offset - isRefresh.startOffset)//偏移差超过80更新started状态
                            isRefresh.started = true //拉得够长(超过80)更新started状态
                        }
                        //用户松手offset == startOffset(偏移位置 == 初始偏移的位置)&&下拉超过80&&未发布状态(released == false)
                        if isRefresh.startOffset == isRefresh.offset && isRefresh.started && !isRefresh.released {
                            withAnimation(Animation.linear) {//启用动画
                                isRefresh.released = true //更新数据(允许追加数据)
                            }
                            updateData()//更新数据
                        }
                        //存在无效下拉时,重新激活更新一次数据
                        if isRefresh.startOffset == isRefresh.offset && isRefresh.started && isRefresh.released && isRefresh.invalid {
                            isRefresh.invalid = false //设置为有效状态
                            updateData()
                        }
                    }
                    return AnyView(Color.black.frame(width: 0, height: 0))
                }
                .frame(width: 0, height: 0)
                //视图显示
                ZStack(alignment: Alignment(horizontal: .center, vertical: .top)) {
                    
                    if isRefresh.started && isRefresh.released {
                        ProgressView()
                            .offset(y : -35)
                    }else {
                        Image(systemName: "arrow.down")
                            .font(.system(size: 16, weight: .heavy))
                            .foregroundColor(.gray)
                            .rotationEffect(.init(degrees: isRefresh.started ? 180 : 0))
                            .offset(y : -25)
                            .animation(.easeIn)
                    }
                    
                    VStack {
                        ForEach(recipeData, id:.self) { title in
                            singleRecipeList(title:title) //列表项
                        }
                    }
                    .background(Color.white)
                }
                .offset(y : isRefresh.released ? 40 : -10)
            }
        }
        .background(Color.black.opacity(0.06).ignoresSafeArea())
    }
    
    //向数组里追回数据
    func updateData() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            withAnimation(Animation.linear) {
                //用户松手(列表弹回去了)
                if isRefresh.startOffset == isRefresh.offset {
                    recipeData.append("追加菜谱" + String(recipeData.count))//向数组里追加数据
                    isRefresh.released = false//发布完成改状态(下次重用)
                    isRefresh.started = false//改状态下次用
                }else {
                    print("updateData()无效下拉")
                    isRefresh.invalid = true //无效下拉(还没有弹回顶部又拉了),因为上次的数据还没有追加完成呢!
                }
            }
        }
    }
}

//刷新状态
struct Refresh {
    var startOffset : CGFloat = 0 //开始偏移位置默认为0
    var offset : CGFloat = 0 //偏移量
    var started : Bool//初始状态
    var released : Bool//刷新结果状态
    var invalid : Bool = false //验证下拉是否有效,未回到起始位置为true
}
//顶部标题
struct TopTitle:View {
    var title:String
    var body: some View{
        HStack {
            Spacer()
            Text(title)
                .font(.largeTitle)
                .fontWeight(.heavy)
                .foregroundColor(.orange)
            Spacer()
        }
        .padding()
        .background(Color.white.ignoresSafeArea(.all, edges: .top))
    }
}
//单个菜谱项
struct singleRecipeList:View {
    var title:String
    var body: some View{
        HStack {
            Image(systemName: "bookmark.circle.fill")
                .renderingMode(.original)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 40)
                .padding(.trailing)
            Text(title)
                .font(.title3)
            Spacer()
            Image(systemName: "chevron.right")
                .foregroundColor(.black)
        }
        .padding()
    }
}

//预览视图
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/115
标签:下拉列表Kwok最后编辑于:2021-04-01 09:01:57
0
感谢打赏!

《【SwiftUI实战】下拉更新(追加)列表项》的网友评论(0)

本站推荐阅读

热门点击文章