Help us understand the problem. What is going on with this article?

【Swift】SwiftUIのListでダイナミックな高さを実現する方法

More than 1 year has passed since last update.

SwiftUIでListを使用していて
UITableViewCellのように各行をダイナミックな高さで表示をしようとする際に
layoutPriorityを使うと簡単に実現することができます。
https://developer.apple.com/documentation/swiftui/view/3278584-layoutpriority

実際に行っているのはQiitaAPIから取得したデータをリストに表示しています。
左側にユーザのアイコン
真ん中に記事のタイトルとユーザ名
右側に静的ないいねマークの画像といいねの数
を表示します。

まずはlayoutPriorityがない状態です。

struct QiitaView: View {
    let item: QiitaItemViewModel
    var body: some View {
        HStack {
            ImageLoadingView(loader: ImagePath(path: item.profileImageURL))
                .frame(width: 44, height: 44)
                .clipShape(Circle())
                .overlay(Circle().stroke(Color.white, lineWidth: 4))
                .shadow(radius: 10)

            VStack(alignment: .leading) {
                Text(item.title)
                    .lineLimit(nil)
                    .padding([.bottom], 12)

                Text(item.userName)
                    .lineLimit(nil)
            }
            .padding([.leading, .trailing], 12)

            Spacer()

            VStack(alignment: .center) {
                Image(systemName: "faceid")
                    .resizable()
                    .frame(width: 44, height: 44)

                Text("\(item.likesCount)")
            }
            .frame(width: 60)
        }
    }
}

これを表示すると下記のようになります。
スクリーンショット 2019-09-23 14.16.15.png

真ん中のラベルの横幅は想定よりも狭くなってしまっています。

これをlayoutPriorityを用いて改善していきます。

まずは真ん中のVStacklayoutPriorityを設定します。
layoutPriorityはデフォルトが0で
1を設定することで優先度を他よりも高くすることができます。

struct QiitaView: View {
    let item: QiitaItemViewModel
    var body: some View {
        HStack {
            ImageLoadingView(loader: ImagePath(path: item.profileImageURL))
                .frame(width: 44, height: 44)
                .clipShape(Circle())
                .overlay(Circle().stroke(Color.white, lineWidth: 4))
                .shadow(radius: 10)

            VStack(alignment: .leading) {
                Text(item.title)
                    .lineLimit(nil)
                    .padding([.bottom], 12)

                Text(item.userName)
                    .lineLimit(nil)
            }
            .padding([.leading, .trailing], 12)
            .layoutPriority(1) // ← ここに追加

            Spacer()

            VStack(alignment: .center) {
                Image(systemName: "faceid")
                    .resizable()
                    .frame(width: 44, height: 44)

                Text("\(item.likesCount)")
            }
            .frame(width: 60)
        }
    }
}

すると下記のイメージのような状態になります。

スクリーンショット 2019-09-23 14.17.07.png

横幅は改善されました。

しかし、まだタイトルが切れてしまっている状態です。

そこでTextにもlayoutPriorityを設定します。

struct QiitaView: View {
    let item: QiitaItemViewModel
    var body: some View {
        HStack {
            ImageLoadingView(loader: ImagePath(path: item.profileImageURL))
                .frame(width: 44, height: 44)
                .clipShape(Circle())
                .overlay(Circle().stroke(Color.white, lineWidth: 4))
                .shadow(radius: 10)

            VStack(alignment: .leading) {
                Text(item.title)
                    .lineLimit(nil)
                    .padding([.bottom], 12)
                    .layoutPriority(1) // ← ここに追加

                Text(item.userName)
                    .lineLimit(nil)
            }
            .padding([.leading, .trailing], 12)
            .layoutPriority(1)

            Spacer()

            VStack(alignment: .center) {
                Image(systemName: "faceid")
                    .resizable()
                    .frame(width: 44, height: 44)

                Text("\(item.likesCount)")
            }
            .frame(width: 60)
        }
    }
}

すると下記のような形になります。

スクリーンショット 2019-09-23 14.18.30.png

もし何か参考になりましたら幸いです。

逆に間違いや他に良い方法があれば
教えていただけると嬉しいです🙇🏻‍♂️

shiz
iOSエンジニア 受託開発会社でモバイルアプリからインフラの構築まで行う雑多なエンジニアでしたが、 Swiftへの関心が特に強く、ご縁をいただきiOSエンジニアへと転身。日々勉強中。 開発言語経験: Swift, kotlin, Javascript(Angular, Node.js), C#, PHP, Java
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away