点击list view中一行内容可以在combox中显示_SwiftUI List (3) —— List、Form、VStack

f7abcc779c217fb39bff687beaefd543.png

SwiftUI List (1) —— 基本用法

SwiftUI List (2) —— 定制化显示

三、List、Form、VStack+ScrollView 之间的比较

苹果对List的基本定义是在单列中排列显示数据行的容器。能够符合这个定义的其实还有Form,和 VStack+ScrollView的组合。在不少场景下,这三者其实都是能够符合使用要求的,不过他们也有各自的特点,及更加适合的用途。

(1)List VS Form

List 和 Form 其实都是SwiftUI对UITableView的一个封装,他们在内部实现的机理基本上是一样的。尤其在List使用 GroupListStyle的情况下,其视觉呈现也基本一致。不过苹果还是给了他们不同的定位,因此无论是在功能还是视觉呈现上的细节仍有值得研究的必要。

功能:

由于构造的不同,List上可以直接使用快捷数据源方式,不过Form在配合ForEach的情况下,该区别基本可以忽略。

基于ForEach的DynamicViewContent因素,Form和List都可以实现对列表中的数据进行删除、移动,在PadOS下也同样都支持onInsert。不过由于Form不支持绑定Selection,因此Form无法实现选择功能,这也是两者功能上最大的一点区别。

a2dbd0f3b4674de806d947b0529cc6af.png

视觉:

List有多种风格,Form只有一种。Form和List一样,同样可以使用上节介绍的定制属性来进行定制化显示。不过可能苹果考虑到两者的定位,在其中一个关键的地方作出了明显的区别。

在Form中内嵌List,Form会将List中的内容直接展开。这种设计应该是充分考虑了Form的适用场景而做出的特别设定。

struct ListForm: View {
    var body: some View {
        VStack{
            Form{
                Text("选项一")
                Section(header:Text("自动展开的List")){
                    List{
                        Text("List中的选项一")
                        Text("List中的选项二")
                    }
                }
            }
        }
    }
}

de96c11d8269271346595fd698a75449.png

除了此种情况外,如果在List中嵌入Form或List,再或者在Form中嵌入Form,嵌入的全部内容都会被当做一个Row来看待。

将上述代码中Form替换成List后效果如下:

3d51b9f7ac1fa65a96eabfea9a94b7a7.png
https://www.zhihu.com/video/1219176452383821824

这两种显示情况无所谓好坏,可以根据实际的需要灵活选择。

除了上述的几点外,List和Form不愧为同胞兄弟。

(2)List VS VStack + ScrollView

本文写作时,SwiftUI2.0尚未发布。在SwiftUI2.0中,苹果通过LazyVStack、LazyHStack等Lazy特性,解决了下面的问题。

在数据量不太大,并且没有太多其他功能要求的情况下,VStack+ScrollView同样可以实现List的功能,而且由于不受UITableView的一些限制,在布局及视觉呈现上有更高的灵活性。

VStack+ScrollView无法享受List中ForEach提供的onMove,onDelete等功能,只能自己手动编程来提供上述功能。

不过相较于功能上的不同,VStack 同 List(或Form)最大的区别还是在效率方面。

由于List和Form是通过UITableView来完成Render的,因而很好的支持了Lazy特性,而VStack需要将所有的数据都Render后才能进行显示,这使得List在大量的数据呈现上有着绝对的优势。

import SwiftUI

struct VStackVSLIstVSForm: View {
    var number = 3000
    var body: some View {
        NavigationView{
            List{
                NavigationLink("List",destination: ListSpeedTest(number: number))
                NavigationLink("Form",destination: FormSpeedTest(number: number))
                NavigationLink("VStack + ScrollView",destination: VStackSpeedTest(number: number))
            }
            
            .navigationBarTitle("数据集大小:(number)",displayMode: .inline)
        }
    }
}

fileprivate struct ListSpeedTest:View{
    var number:Int
    var body:some View{
        List{
            ForEach(0..<number){ i in
                Text("ID:(i)").padding().background(LinearGradient(gradient: Gradient(colors: [.red,.yellow,.purple,.blue]), startPoint: .zero, endPoint: .bottomTrailing))
            }
        }
    }
}

fileprivate struct VStackSpeedTest:View{
    var number:Int
    var body:some View{
        ScrollView{
            VStack{
                ForEach(0..<number){ i in
                    Text("ID:(i)").padding().background(LinearGradient(gradient: Gradient(colors: [.red,.yellow,.purple,.blue]), startPoint: .zero, endPoint: .bottomTrailing))
                }
            }
        }
    }
}

fileprivate struct FormSpeedTest:View{
    var number:Int
    var body:some View{
        Form{
            ForEach(0..<number){ i in
                Text("ID:(i)").padding().background(LinearGradient(gradient: Gradient(colors: [.red,.yellow,.purple,.blue]), startPoint: .zero, endPoint: .bottomTrailing))
            }
        }
    }
}

上述代码都是显示3000条数据,通过视频可以看出两者间的巨大差距。

4dd00e1ed63ca88c57a90bac78a1fbea.png
https://www.zhihu.com/video/1219183181674840064

如果你的数据量较大,即使牺牲一定的显示控制力也应该首选List或Form。

(3)List动态显示上的性能上的一点小问题

List对数据的显示效率极高,而且还支持数据变化的动态显示效果,在程序对数据进行删减、增加、排序等情况下都会提供美观的动态显示。不过恰恰是由于这种动态的显示效果,在某些特殊的情况下,会产生非常严重的效率问题。

struct ListDynamic: View {
    @State var list = (0...500).map{$0}
    @State var id = UUID()

    var body: some View {
        VStack{
            Text("数据量:500")
            List(list,id:.self){ i in
                Text("(i)")
            }.id(self.id)
            
            HStack{
                Button("shuffle"){
                    self.list.shuffle()
                }.frame(maxWidth:.infinity)
                Button("Shuffle with new ID"){
                    self.list.shuffle()
                    self.id = UUID()
                }.frame(maxWidth:.infinity)
            }.padding(.bottom,20)
        }
    }
}
946a6206144fca1f553a24e052d9915b.png
https://www.zhihu.com/video/1219189826559578112

可以看出来,在了数据量较小的情况下,list可以展示出很好的数据动态转换效果,但当数据量增大后,可能由于内部算法的效率问题,动态转换的计算反倒阻滞了整个app。由于目前没有方法可能禁止List的animation,所以暂时只能通过使用.id(hash:Value)的方式强制重绘来解决以上的问题。希望将来内部算法上能够有所改善。

在基本掌握了List的用法后,在下一篇我们来完成最初设定的目标,仿制一个Mail程序的首页。

更新:

对于该如何在List中使用ForEach的问题,我的另一篇文章有提及

东坡肘子:聊一下SwiftUI中的List和ForEach​zhuanlan.zhihu.com
525c23d6e0afea2d3b983301b40ccc52.png

看下篇:

东坡肘子:SwiftUI List (4) —— 仿制Mail首页​zhuanlan.zhihu.com
bb99adfec0aa46f00e4c55d49fb4644a.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值