SwiftUI List、自定义cell、分组

listView在APP交互上是一个很高频的容器组件了,在传统的UIKit中一般是给tableview或者collectionView设置delegate,controller实现cell的绘制和UI约束,控制列表的滚动交互和UI风格。在swiftUI中该如何控制list的这些特性,本文做一个简单的记录。

静态的listview

如果要展示的是一些固定数据的且数据量不大的list,简单几行代码就能实现

var body: some View {
    List{
        Text("Hello, World!")
        Text("Hello, World!")
        Text("Hello, World!")
    }

}

List默认的样式是InsetGroupedListStyle,效果如下

截屏2023-06-01 13.53.14.png

分组的listview

SwiftUI里用Sectoin表示一个分组

Section {
        TextField("输入姓名", text: $username)
        Toggle(isOn: $isPrivate) {
            Text("隐私")
        }
        Button{}label: {
            Text("退出")
        }
    } header: {
        Text("个人")
    }

    Section {
        Slider(value: $fontSize, in: 1...10)
        Picker("主题", selection: $appearance) {
            Text("Dark").tag(AppearanceStyle.dark)
            Text("Light").tag(AppearanceStyle.light)
            Text("Auto").tag(AppearanceStyle.auto)
        }

    } header: {
        Text("主题")
    }
    
    Section {
        HStack{
            Text("版本")
            Spacer()
            Text("1.0.0")
        }
    } header: {
        Text("关于")
    }
}

截屏2023-06-01 14.20.03.png

动态的listview

listview的呈现大部分情况下都是根据服务的返回的数据动态表现的,这里mock一个数组模拟api的返回数据,显示一个水果的列表。

struct Food{
    var name: String
    var icon: String
    var isFavorite: Bool
    
    static func preview() -> [Food]{
        return [
            Food(name: "苹果", icon: "?", isFavorite: true),
            Food(name: "草莓", icon: "?", isFavorite: true),
            Food(name: "香蕉", icon: "?", isFavorite: true),
            Food(name: "樱桃", icon: "?", isFavorite: true),
            Food(name: "葡萄", icon: "?", isFavorite: true),
            Food(name: "西瓜", icon: "?", isFavorite: true),
        ]
    }
}

直接在List中显示一个arr会报错 「Initializer ‘init(_:rowContent:)’ requires that ‘Food’ conform to ‘Identifiable’」,意思就是你显示的Model不具有唯一性,此时可以提供一个名为id的属性,指定一个Model里的属性作为唯一标识就好了。

List{
    let fruits = Food.preview()
    List(fruits, id: \.name) { food in
        Text(food.name)
}

这里提供的id是fruit的name,mock的数据里是唯一的,但真实的项目里不会用这种性质的字段最为id,一般会给Model通过实现Identifiable的方式扩展一个UUID的id属性来解决。

struct Food: Identifiable{
    ......
   let id = UUID()
}

这个时候你的list中不提供id属性也不会报错了,页面能正常展示

截屏2023-06-01 14.53.54.png

创建自定义cell

SwiftUI里不需要像在UIKit下去创建一个集成UITableViewCell的view,只要在List中指定要显示的UI组件即可,如果UI比较复杂,可以抽取出一个独立的view。

struct FoodRow: View{
    let food: Food
    var body: some View{
        HStack{
            Text(food.icon).font(.title)
            Text(food.name)
            Spacer()
            Image(systemName: food.isFavorite ? "heart.fill" : "heart")
        }
    }
}

设置group样式,以及group的header和footer

新增一个array,分组显示为水果和零食。你可以往List里随意的添加section来实现分组,section有自定义的header和footer属性来显示组的头尾信息,使用默认的InsetGroupedListStyle样式。或者你也可以用DisclosureGroup来显示一个可折叠的分组效果

截屏2023-06-01 15.23.51.png

数据的添加和删除

先说删除,首页显示数据的array标注为@State,其次list有一个delete的方法,传入一个block回调

@inlinable public func onDelete(perform action: ((IndexSet) -> Void)?) -> some DynamicViewContent

截屏2023-06-01 15.39.03.png

添加数据,直接在barItem添加点击事件,往数据里新增一条记录就好

toolbar {
    Button {
        fruits.append(Food(name: "未知food", icon: "⚠️", isFavorite: false))
    } label: {
        Text("新增")
    }

}

截屏2023-06-01 16.04.34.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYKTnofh' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片