SwiftUIミニマリストチュートリアル12:リストとForEachループの使用

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して12日目です。クリックしてイベントの詳細をご覧ください

序文:この記事の執筆は12時近くで、2時間近く書かれています。一般的に、知識のポイントを明確に説明するのはそれほど簡単ではありません。まず、言語もそうすべきではありません。複雑で、適切な名詞が多すぎないようにする必要があります。避けられない名詞がある場合は、例を示す方法を見つけてください。案の定、変革への道は常に困難で孤独です。

今日の言葉:読者を説得しようとしないでください、賢明な方法でトピックを進めないでください。

この章では、ループトラバーサルを使用してリストを作成し、カスタムパラメーターを使用してリストを動的に生成する方法を学習します。

UIKitに触れたことがある場合は、tableViewコンポーネントを使用してリストを作成する必要があります。私たちが生活で使用するアプリの多くは、基本的にリストの形式です。

たとえば、ナゲットの情報リスト、携帯電話のシステム設定、音楽リストなど...

214.png

基本的に、ほとんどのアプリ、特に情報アプリにはリストがあります。

SwiftUIでは、元のtableViewをListに置き換えます。これにより、コードがより簡潔で理解しやすくなります。

さまざまなシナリオでのリストコンポーネントのさまざまなアプリケーションのため、この章は4つの部分に分かれて説明します。

1.シンプルなテキストリスト。

2.画像​​+テキストリスト;

3.データ統合を一覧表示します。

4.識別可能なプロトコルの使用。

パート1:シンプルなテキストリスト

まず、SwiftUIListという新しいプロジェクトを作成しましょう。

194.png

ContentView.swiftファイルに簡単なリストを作成します。

Listの構成は、前に学習したVStackと非常によく似ており、その中のコンテンツをラップしてリストを形成します。

struct ContentView: View {
    var body: some View {

        //简单的列表
        List {
            Text(“第1页")
            Text(“第2页")
            Text(“第3页")
            Text(“第4页")
        }
    }
}
复制代码

195.png

リストはテキストテキストでいっぱいで、内容だけが異なります。

現時点では、ForEachを使用してコードを抽出できるため、同様のコードをそれほど多く記述する必要はありません。

struct ContentView: View {
    var body: some View {

        // 简单的列表
        List {
            ForEach(1 ... 4, id: \.self) { index in
                Text("第 \(index)页")
            }
        }
    }
}
复制代码

196.png

ForEachを使用してトラバースしてビューを作成する場合は、idを使用してコンテンツを識別する必要があります。内部のコンテンツが変更されると、ForEachはUIを自動的に更新できます。

コードの内容を読んでください。

ForEachに値の範囲を渡して、生成されたリストをループします。

そして、そのID(識別子)は、前に設定された1、2、3、4である値自体に設定されます。

然后用index参数存储循环的值。

我们在这里遍历了4次,每一次展示一个Text,Text里面的文字是“第”+{index}+“页”,index的参数值从1~4;

这样,我们就得到了一个列表。

当然,还有更简单的遍历方法。

struct ContentView: View {
    var body: some View {

        // 简单的列表
        List {
            ForEach(1 ... 4, id: \.self) {
                Text("第 \($0)页")
            }
        }
    }
}
复制代码

197.png

在这里,我们省略索引参数index,而使用简化的$0,它引用闭包的第一个参数,直接将数据集合传递给List。

这样,也可以达到列表的效果,而且使得代码更加简单。

第二部分:图片+文字列表

好,下面进阶一下,我们尝试完成下面的UI设计稿。

207.png

首先分析下它的结构。

一个列表里,有Image、Text,他们是横向HStack排布。

我们先在Assets.xcassets导入我们所需的图片。

199.png

200.png

并且我们已经提前给图片命好名了,方便我们接下来使用它们。

我们回到ContentView.swift文件中,创建2个数组,存放我们的图片和文字。

//定义数组,存放数据

var myImages = ["weixin","weibo","qq","phone","mail"]
var myNames = ["这是微信","这是微博","这是QQ","这是电话","这是邮箱"]
复制代码

208.png

我们看到报错了,但又没有完全报错。

这是因为我们定义了一个动态数组,但在代码中没有用到,所以系统告诉我们定义的数组名称没有被使用罢了。

没事的,我们继续。

我们在body里面创建我们需要的代码。

struct ContentView: View {

    //定义数组,存放数据
    var myImages = ["weixin","weibo","qq","phone","mail"]
    var myNames = ["这是微信","这是微博","这是QQ","这是电话","这是邮箱"]
    
    var body: some View {


        // 列表
        List(myImages.indices, id: \.self) { index in
            HStack {
                Image(self.myImages[index])
                    .resizable()
                    .frame(width: 40, height: 40)
                    .cornerRadius(5)
                Text(self.myNames[index])
            }
        }
    }
}
复制代码

209.png

我们还是构建了一个列表,不过使用myImages作为目录,也就是myImages.indices。

然后图片遍历用myImages数组,文字遍历用myNames数组。

是不是很简单,比起以前用UIKit的时候,要给cell协议和声明,SwiftUI几行代码就搞定了。

第三部分:列表数据整合

下面,我们再进阶一下。

上面的代码中,我们发现如果是图片+文字,那么我们创建了2个数组,如果是更加复杂的场景,我们岂不是要建立一堆的数组数据?

不不不,这肯定不够优雅。

最好的方式应该是,无论我们多少数组数据,我们都用一个数组包裹住。

我们回到UI稿中。

207.png 有没有办法,把Image和Text定义出来,然后Image和Text是一个数组?

有的!这时候,我们需要创建一个结构体,叫做Message,并定义好里面的变量。

代码如下:

struct Message {
    var name: String
    var image: String
}
复制代码

使用这个Message结构体,我们将原来的myImages、myNames数组组合成一个数组。

我们定义了一个数组Messages,它里面的内容是Message结构体。

代码如下:

// 定义数组,存放数据
    var Messages = [
        Message(name: "这是微信", image: "weixin"),
        Message(name: "这是微博", image: "weibo"),
        Message(name: "这是QQ", image: "qq"),
        Message(name: "这是电话", image: "phone"),
        Message(name: "这是邮箱", image: "mail")
    ]
复制代码

构建好了以后,我们回到body里面,把里面的引用的参数值换成数组Messages,使用结构体Message遍历数据,List中使用image属性作为唯一的标识符。

同时,要把里面Image的参数引用结构体Message的image参数,Text引用结构体Message的name参数。

代码如下:

// 列表

List(Messages, id: \.image) { Message in
    HStack {
        Image(Message.image)
            .resizable()
            .frame(width: 40, height: 40)
            .cornerRadius(5)
        Text(Message.name)
    }
}
复制代码

那么,最终的结果和我们之前做的效果是一样的。

唯一不一样的是,我们的代码看起来优雅多了。

210.png

小结一下:

我们创建了一个结构体Message,它定义了2个变量,1个是image图片,是Strring类型,另一个是name名称,也是Strring类型。

然后我们定义个一个数组Messages(注意加了S),这个数组里面是结构体Message,并赋予了结构体里面2个变量的值;

然后在在body主代码块List里面,用Messages数据作为引用值数据,然后用结构体Message遍历数据。

最后把里面的Image和Text中的值换成结构体中变量的值。

第四部分:Identifiable协议的使用

完成第三部分以后,我们的代码List就完美了么?

并不!

因为这个:

List(Messages, id: \.image)
复制代码

我们使用了image为Messages数组的唯一标识符,也就是List是通过image的唯一性找到对应数组的数据。

这样,我们会面临一个问题,如果我有2个图片是一样的,但是它的name不一样。

我们尝试把Messages数组的数据换成下面这样:

// 定义数组,存放数据

var Messages = [
    Message(name: "这是微信", image: "weixin"),
    Message(name: "这是第二个微信号", image: "weixin")
]
复制代码

211.png

我们发现,如果我们使用image作为id,也就是唯一标识符的话。

如果我的数组里有2个image,如果它们的值相同,那么SwiftUI会认为这两个是同一个东西。

也就是,我都是图片都是“微信”,但名称不一样,但计算机认为两个都是微信,而且值一样,这是因为image作为id是唯一的。

这时候,我们该怎么办?

我们期望的结果是,Messages数组里,每一个结构体的数据都是唯一的。

那么我们就不能在body构建唯一的标识符,应该在传值之前就在Message结构体里构建唯一的id。

struct Message {
    var id = UUID()
    var image: String
    var name: String
}
复制代码

コードでは、idプロパティを追加し、一意の識別子で初期化します。

UUID()関数は、グローバル一意ランダム識別子を生成するために使用されます。

UUIDは128ビットの数値で構成されているため、理論的には、2つの同一の識別子を持つ可能性は事実上ゼロです。

次に、本文コードのIDを使用して、メッセージ構造のIDを参照します。

// 列表

List(Messages, id: \.id) { Message in
    HStack {
        Image(Message.image)
            .resizable()
            .frame(width: 40, height: 40)
            .cornerRadius(5)
    Text(Message.name)
    }
}
复制代码

このようにして、リストデータソースの一意性が完成しました。

212.png

もう1つの知識ポイント。

識別可能なプロトコルに従うように構造メッセージを設定することもできます。

このように、Identizableに準拠する構造体は、そのIDを一意の識別子として自動的に追跡でき、本文でIDを指定する必要はありません。

完全なコードは次のとおりです。

import SwiftUI

struct ContentView: View {

    // 定义数组,存放数据
    var Messages = [
        Message(image: "weixin", name: "这是微信"),
        Message(image: "weixin", name: "我的第二个微信号")
    ]

    var body: some View {

        // 列表
        List(Messages) { Message in
            HStack {
                Image(Message.image)
                    .resizable()
                    .frame(width: 40, height: 40)
                    .cornerRadius(5)
                Text(Message.name)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct Message: Identifiable {
    var id = UUID()
    var image: String
    var name: String
}
复制代码

213.png

おめでとう!リストの学習を完了しました!

このコラムがお役に立てば、いいね、コメント、フォローしてください〜

おすすめ

転載: juejin.im/post/7085515068586065950