preface

Last time we learned how to write the basic layout. This time we have to break the list


Note: Errors in the article are expected to be corrected

A, List

Almost every large mobile App or PC chooses lists for a large amount of the same type of data or rule layout UI. Android may use ListView, GridView and RecyclerView. Flutter may use ListView and GridView, etc. Let’s try SwiftUI

1. A List of basicSliding container control

List as the basic sliding container part. When the open UI page is purely control layout [no data sources, few data sources and fixed data] then we can use List and HStack and VStack combination to draw. Below: pictures show ancient don’t care, imitate Himalayan heard write page like can go to read.

  • This is something we should see a lot123 carnivalThis level goes beyond the sliding layout.

The code analysis

List{
 HStack{
    CicleImage
    Text
 }
 HStack{
    CicleImage
    Text
 }
 HStack{
    CicleImage
    Text
 }
 HStack{
    CicleImage
    Text
 }
 HStack{
    CicleImage
    Text
 }
 HStack{
    CicleImage
    Text
 }
 .......
}

Copy the code

Take your fastest 2 minutes and write it out, then use the remaining 5 seconds CTRL + C, CTRL + V… ctrl+v… Slow down I’m afraid you can’t finish my code is as follows:

struct SwiftUIView_List: View { var body: some View { return List(){ ximalayaListenApp() } } struct ximalayaListenApp: View{ var body: some View{ VStack{ Image("laopo").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment:.center) Text(" wife ")} VStack{Image("path_img").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment: .center) Text(" hubbi ")} VStack{Image("head_coply").resizable().clipShape(Circle()).frame(width: 60, height: 0) 60, alignment:.center) Text(" parent ")} VStack{Image("head_boy").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment:.center) Text(" son ")} VStack{Image("longnv").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment:.center) Text(" wife ")} VStack{Image("laopo").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment:.center) alignment (" wife ")}}Copy the code

To see the effect,😂 low-level error, set the direction can be,😄 did not find… ! It’s fucking awkward. I have used ScrollView in Android. The ScrollView and ListView can be used in Flutter. Just set the direction.

Import SwiftUI struct SwiftUIView_List: View {var body: some View {List(){Text(" this is ok "). Frame (width: 100, height: 0) 100 , alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundcolor (.white) Text(" this is ok ").frame(width: 100, height: 100, alignment:.center).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)). ForegroundColor (.white) Text(" this is ok "). Frame (width: 100, height: 100, alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundcolor (.white) Text(" this is ok ").frame(width: 100, height: 100, alignment:.center).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)). ForegroundColor (.white) Text(" this is ok "). Frame (width: 100, height: 100, alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundcolor (.white) Text(" this is ok ").frame(width: 100, height: 100, alignment:.center).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)). ForegroundColor (.white) Text(" this is ok "). Frame (width: 100, height: 100, alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundcolor (.white) Text(" this is ok ").frame(width: 100, height: 100, alignment:.center).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)). ForegroundColor (.white) Text(" this is ok "). Frame (width: 100, height: 100, alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundcolor (.white) Text(" this is ok ").frame(width: 100, height: 100, alignment:.center).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundColor(.white) }.onAppear(){ UITableView.appearance().separatorStyle = .none } } } struct SwiftUIView_List_Previews: PreviewProvider { static var previews: some View { SwiftUIView_List() } }Copy the code

So let’s go find out if SwiftUI ScrollView is available, it’s ok and let’s bring it here and try it out. By controlling the direction of horizontal sliding

struct SwiftUIView_List: View { var body: some View { return ScrollView(.horizontal, showsIndicators: false){ HStack(){ ximalayaListenApp() } } } struct ximalayaListenApp: View{ var body: some View{ VStack{ Image("laopo").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment: .center) Text(" wife ")} VStack{Image("path_img").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment:.center) Text(" mY ")} VStack{Image("head_coply").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment: .center) Text(" father ")} VStack{Image("head_boy").resizable().clipShape(Circle()).frame(width: 60, height: 0) 60, alignment:.center) Text(" son ")} VStack{Image("longnv").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment:.center) Text(" wife ")} VStack{Image("laopo").resizable().clipShape(Circle()).frame(width: 60, height: 0) 60, alignment:.center) Text(" wife ")} VStack{Image("head_coply").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment: .center) Text(" father ")} VStack{Image("head_boy").resizable().clipShape(Circle()).frame(width: 60, height: 0) 60, alignment:.center) Text(" son ")} VStack{Image("longnv").resizable().clipShape(Circle()).frame(width: 60, height: 60, alignment:.center) Text(" wife ")} VStack{Image("laopo").resizable().clipShape(Circle()).frame(width: 60, height: 0) 60, alignment:.center) Text(" wife ")}}}Copy the code

Today’s focus is on list controls, so that’s it… We’ll definitely have a separate section on sliding controls later… The use of slip measurement and so on..

  • You can’t do it horizontally😅: Just swipe off the screen, basic and Flutter ListView[Text,Text….] The same. List is an off-screen slideable container control that can be arbitrarily placed with other controls, so try it yourself.

2. Bind the collection data source with List

  • Of course, we don’t usually write it that way. General data sources may be one hundred thousand or tens of millions [sliding my taobao is no more than 200.. I object should be thousand breaking all 】, this kind of situation we can’t to the above to write like this, but the bound data source (common collection and array for the basic swift behind language is I haven’t seen so I took a two complement, Now are using KT and feel + Baidu basic solution 】. First let’s simulate an array of data sources. The array type is defined as follows:
Similarly, I created the data source model. At first, I didn't implement Identifiable crude error, so I wrote this for the first time. struct User:Identifiable{ var id: Int var firstName: String var lastName: Struct SwiftUIView_List: View {var body: struct SwiftUIView_List: View Some View {let users=getDataList() return List(users) {user in // float {this.musser} What's the point? ContentItem (muser: user)}} struct contentItem: View{var muser: user var body: some View{ Text("\(muser.firstName)").frame(width: 100 , height: 100 , alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundColor(.white) } } func getDataList()->Array<User> { let user1 = User(id: 1, firstName: "Piper1", lastName: "Chapman") let user2 = User(id: 2, firstName: "GGloria", lastName: "Mendoza") let user3 = User(id: 3, firstName: "LGloria3", lastName: "Mendoza") let user4 = User(id: 4, firstName: "WGloria5", lastName: "SMendoza") let user5 = User(id: 5, firstName: "LGlorias", lastName: "MCendoza") let user6 = User(id: 6, firstName: "SSGAloria", lastName: "AMendoza") let user7 = User(id: 7, firstName: "LLCGloria", lastName: "CMendoza") let user8 = User(id: 8, firstName: "WGlria", lastName: "MMendoza") let user9 = User(id: 9, firstName: "GlorSSia", lastName: "LMendoza") let user10 = User(id: 10, firstName: "MGloria", lastName: "QMendoza") let user14 = User(id: 11, firstName: "WGloria", lastName: "WMendoza") let user11 = User(id: 12, firstName: "GGloria", lastName: "LJMendoza") let user12 = User(id: 13, firstName: "HGlid", lastName: "UMendoza") let user13 = User(id: 14, firstName: "Lme", lastName: "OMendoza") return [user1,user2,user3,user4,user5,user6,user7,user8,user9,user10,user11,user12,user13,user14] } struct SwiftUIView_List_Previews: PreviewProvider { static var previews: some View { Group { SwiftUIView_List() } } }Copy the code
  • There is an error here requiring User to be an Identifiable identity class. So you can click on List and see That rowContent requires that the data class needs to be able to contrarily.

A more brief way of writing

Return List(users) {user in {this.musser}} contentItem(muser: Return List(users,rowContent: contentitem.init);Copy the code

  • Next, let’s take the layout of station B from the previous section to see the effect.

import SwiftUI struct User:Identifiable{ var id: Int var firstName: String var lastName: String var image:String } struct SwiftUIView_List: View { var body: Some View {let users=getDataList() // no index initialization // return List(users) {user in // {this.musser}} // contentItem(muser: Return List(users,rowContent: contentitem.init) // Return List(users,rowContent: contentitem.init) // Return List(users,rowContent: contentitem.init) Biliblihstack.init) return List(users,rowContent: biliblihstack.init)} struct bilibliHStackItem: View{var muser:User var body: some View{HStack(){bilibliItem(User: muser)}} struct contentItem: View{ var muser:User var body: some View{ Text("\(muser.firstName)").frame(width: 100 , height: 100 , alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundColor(.white) } } //Item struct bilibliItem: View{ var user:User var body: some View { VStack{ VStack(alignment:.leading, spacing: 1){ ZStack(alignment:.bottom){ Image("\(user.image)").resizable().frame(width:190, height: 125, alignment: .center ) HStack(){ HStack(){ Image("bofang").resizable().frame(minWidth: 15, idealWidth:7, maxWidth:7, minHeight: 15, idealHeight: 5, maxHeight:5, alignment: .center ).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, trailing:1)) Text(" 355,000 ").font(.footnote).foregroundcolor (.white)}.frame(alignment: .center ) Spacer() HStack(){ Image("pinglun").resizable().frame(minWidth: 15, idealWidth:5, maxWidth:5, minHeight: 15, idealHeight: 5, maxHeight:5, alignment: .center ).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, Trailing: 1) the Text (" 28.77 "). LineLimit (1). The font (. Footnote). ForegroundColor. (white)} HStack () { Background (color.black.opacity (0.6)) // title}.frame(width: 0) Background-color (.system(size:22)).padding(edgeinset.init (top: 11.0, Leading: 11, bottom: 0, trailing: 26)). Background (Color. White) HStack (alignment: center) {Text (" thumb up "280000) Spacer () Image("ziyuan").resizable().frame(minWidth: 22, idealWidth:5, maxWidth:5, minHeight: 22, idealHeight: 5, maxHeight:5, alignment: .center ).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, trailing:0)) }.frame(width: 170,height:50).background(Color.white).padding(EdgeInsets(top: 11, leading: 11, bottom: 11, trailing:1)) } }.frame(width: 180, height:210, alignment: .center ).background(Color.white).clipShape(RoundedCorner(corners:[UIRectCorner.topLeft,UIRectCorner.topRight], CornerRaduiWidth: 30)).shadow(color: color.black.opacity (0.3), radius: 10, x: 11, y: 11).padding(EdgeInsets(top: 20, leading: 1, bottom: 11, trailing:1)) } } func getDataList()->Array<User> { let user1 = User(id: 1, firstName: "Piper1", lastName: "Chapman",image:"iimage") let user2 = User(id: 2, firstName: "GGloria", lastName: "Mendoza",image:"laopo") let user3 = User(id: 3, firstName: "LGloria3", lastName: "Mendoza",image:"path_img") let user4 = User(id: 4, firstName: "WGloria5", lastName: "SMendoza",image:"head_boy") let user5 = User(id: 5, firstName: "LGlorias", lastName: "MCendoza",image:"dao") let user6 = User(id: 6, firstName: "SSGAloria", lastName: "AMendoza",image:"head_coply") let user7 = User(id: 7, firstName: "LLCGloria", lastName: "CMendoza",image:"head_dog") let user8 = User(id: 8, firstName: "WGlria", lastName: "MMendoza",image:"head_god") let user9 = User(id: 9, firstName: "GlorSSia", lastName: "LMendoza",image:"head_godd") let user10 = User(id: 10, firstName: "MGloria", lastName: "QMendoza",image:"longnv") let user14 = User(id: 11, firstName: "WGloria", lastName: "WMendoza",image:"head_hl") let user11 = User(id: 12, firstName: "GGloria", lastName: "LJMendoza",image:"path_img") let user12 = User(id: 13, firstName: "HGlid", lastName: "UMendoza",image:"head_boy") let user13 = User(id: 14, firstName: "Lme", lastName: "OMendoza",image:"dao") return [user1,user2,user3,user4,user5,user6,user7,user8,user9,user10,user11,user12,user13,user14] } struct SwiftUIView_List_Previews: PreviewProvider { static var previews: some View { Group { SwiftUIView_List() } } } }Copy the code

3.List realizes grid layoutGridView

It’s usually a two-column list, but here it’s just one column. It’s so low that we learned this list so let’s implement it. We can think of the HStack layout as follows:

struct bilibliHStackItem: View{
    var muser:User
    var body: some View {
        HStack(){
            bilibliItem(user: muser)
            bilibliItem(user: muser)
        }
    }
}
Copy the code

The complete code

import SwiftUI struct User:Identifiable{ var id: Int var firstName: String var lastName: String } struct SwiftUIView_List: View { var body: some View { let users=getDataList() // return List(users) { user in // // contentItem(muser: user) // return List(users,rowContent: contentItem.init) //return List(users,rowContent: bilibliItem.init) return List(users,rowContent: bilibliHStackItem.init) } } struct contentItem: View{ var muser:User var body: some View{ Text("\(muser.firstName)").frame(width: 100 , height: 100 , alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundColor(.white) } } struct bilibliHStackItem: View{ var muser:User var body: some View { HStack(){ bilibliItem(user: muser) bilibliItem(user: muser) } } } //Item struct bilibliItem: View{ var user:User var body: some View { VStack{ VStack(alignment:.leading, spacing: 1){ ZStack(alignment:.bottom){ Image("iimage").resizable().frame(width:190, height: 125, alignment: .center ) HStack(){ HStack(){ Image("bofang").resizable().frame(minWidth: 15, idealWidth:7, maxWidth:7, minHeight: 15, idealHeight: 5, maxHeight:5, alignment: .center ).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, trailing:1)) Text(" 355,000 ").font(.footnote).foregroundcolor (.white)}.frame(alignment: .center ) Spacer() HStack(){ Image("pinglun").resizable().frame(minWidth: 15, idealWidth:5, maxWidth:5, minHeight: 15, idealHeight: 5, maxHeight:5, alignment: .center ).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, Trailing: 1) the Text (" 28.77 "). LineLimit (1). The font (. Footnote). ForegroundColor. (white)} HStack () { Background (color.black.opacity (0.6)) // title}.frame(width: 0) Background-color (.system(size:22)).padding(edgeinset.init (top: 11.0, Leading: 11, bottom: 0, trailing: 26)). Background (Color. White) HStack (alignment: center) {Text (" thumb up "280000) Spacer () Image("ziyuan").resizable().frame(minWidth: 22, idealWidth:5, maxWidth:5, minHeight: 22, idealHeight: 5, maxHeight:5, alignment: .center ).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, trailing:0)) }.frame(width: 170,height:50).background(Color.white).padding(EdgeInsets(top: 11, leading: 11, bottom: 11, trailing:1)) } }.frame(width: 180, height:210, alignment: .center ).background(Color.white).clipShape(RoundedCorner(corners:[UIRectCorner.topLeft,UIRectCorner.topRight], CornerRaduiWidth: 30)).shadow(color: color.black.opacity (0.3), radius: 10, x: 11, y: 11).padding(EdgeInsets(top: 20, leading: 1, bottom: 11, trailing:1)) } } func getDataList()->Array<User> { let user1 = User(id: 1, firstName: "Piper1", lastName: "Chapman") let user2 = User(id: 2, firstName: "GGloria", lastName: "Mendoza") let user3 = User(id: 3, firstName: "LGloria3", lastName: "Mendoza") let user4 = User(id: 4, firstName: "WGloria5", lastName: "SMendoza") let user5 = User(id: 5, firstName: "LGlorias", lastName: "MCendoza") let user6 = User(id: 6, firstName: "SSGAloria", lastName: "AMendoza") let user7 = User(id: 7, firstName: "LLCGloria", lastName: "CMendoza") let user8 = User(id: 8, firstName: "WGlria", lastName: "MMendoza") let user9 = User(id: 9, firstName: "GlorSSia", lastName: "LMendoza") let user10 = User(id: 10, firstName: "MGloria", lastName: "QMendoza") let user14 = User(id: 11, firstName: "WGloria", lastName: "WMendoza") let user11 = User(id: 12, firstName: "GGloria", lastName: "LJMendoza") let user12 = User(id: 13, firstName: "HGlid", lastName: "UMendoza") let user13 = User(id: 14, firstName: "Lme", lastName: "OMendoza") return [user1,user2,user3,user4,user5,user6,user7,user8,user9,user10,user11,user12,user13,user14] } struct SwiftUIView_List_Previews: PreviewProvider { static var previews: some View { Group { SwiftUIView_List() } } }Copy the code

If I hadn’t told you that 😄, the Users array as the data source, We can divide the left and right sides of the item by index into users[index] and users[index+1] so that our list can be displayed as we want it to be. Think about it. Let’s analyze a wave:

Index =0 users[0] users[1] index=1 Users [2] users[3] index=2 Users [4] users[5]..... Index =index users[index*2] users[index*2+1] Wait, we have 14 index. Index =14. User [14*2] user[14*2+1]? What? This is going to go wrong. Out of array index. I'm not going to try and you can go in. So we need [index is less than 7]. I rely on analysis perfect.. Does swift provide an initialization method for index? Don't be too embarrassed.. A frantic operation found the missing. There is no problemCopy the code

So our code should look like this:

struct SwiftUIView_List: View { var body: Some View {let users=getDataList() return list (users.indices, id: \.self) { index in bilibliHStackItems(muser:users,indexs: index) } } struct bilibliHStackItems: View{ var muser:Array<User> var indexs:Int var body: some View { if (indexs<7) { HStack(){ bilibliItem(user: muser[indexs*2]) bilibliItem(user: muser[indexs*2+1]) } } } }Copy the code

What about the grid? Let’s look at a wave. Moving on, grid layout means many rows, many columns

Index =0 users[0] users[1] user[2] index=1 Users [3] users[4] user[5] Index =2 Users [6] users[7] user[8]..... Index =index Users [index*3] users[index*3+1] users[index*3+2] users[index*3+2 Notice that this index is the index that the list traversesCopy the code
struct SwiftUIView_List: View { var body: some View { let users=getDataList() return List(users.indices, id: \.self) {index in // Limit the number of columns by customizing columCount. nColumItems(muser:users,indexs: index,columCount:1) } } struct nColumItems: View{ var muser:Array<User> var indexs:Int var columCount=4 var body: some View { HStack(alignment: .center){if(indexs<(muser.count/columCount)){//users[index*3] users[index*3+1] users[index*3+2] ForEach(0 .. < columCount) {mindex in Spacer() //Text(self.muser[indexs*columCount+mindex].firstName) contentRowItem(muser:self.muser[indexs*columCount+mindex]) Spacer() } } }Copy the code

The effect is as follows:

Careful people will find incomplete data problems. If I have 14 entries. I have 3 columns in my row, so I’m going to have 14 minus 14/3 times 3 is equal to 2 pieces of data that I haven’t drawn. Of course, we didn’t plot the last two days when we did the calculation, so let’s go ahead and plot the rest. The following

The code is as follows:

struct SwiftUIView_List: View { var body: some View { let users=getDataList() return List(users.indices, id: \.self) { index in nColumItems(muser:users,indexs: index,columCount:3) } } struct nColumItems: View{ var muser:Array<User> var indexs:Int var columCount=4 var body: some View { HStack(alignment: .center){if(indexs<(muser.count/columCount)){//users[index*3] users[index*3+1] users[index*3+2] ForEach(0 .. < columCount) {mindex in Spacer() //Text(self.muser[indexs*columCount+mindex].firstName) contentRowItem(muser:self.muser[indexs*columCount+mindex]) Spacer() } }else if(indexs==(muser.count/columCount)){ Couns =muser.count-columCount*(muser.count/columCount) var width: CGFloat = 0 ForEach(0.. <columCount){endIndex in if(endIndex<couns){ Spacer() GeometryReader(){geo in contentRowItem(muser:self.muser[indexs*columCount]).onAppear(){ width=geo.size.width } Spacer() } }else{ // We should count the number of rows that do not meet the n column requirement to draw a container of the same width to divide the list width equally. Spacer() Text("").frame(width:41) Spacer()}}}}. Frame (alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/) } } struct contentRowItem: View{ var muser:User var body: some View{ Text("\(muser.firstName)").frame(width:48 , height: 65 , alignment: .center ).shadow(radius: 10 ).background(Color.blue).clipShape(RoundedCorner(corners: [UIRectCorner.allCorners], cornerRaduiWidth: 11, cornerRaduiHeight: 11)).foregroundColor(.white) } }Copy the code

Through the above compilation we found that the List to draw the grid layout is rather tedious and need to calculate the etc. You’ll lose more than you gain. Does Swift provide an Api for that? Let’s keep exploring.

It’s 11:55 and we’ll continue tomorrow…