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)
}
}
}
真ん中のラベルの横幅は想定よりも狭くなってしまっています。
これをlayoutPriority
を用いて改善していきます。
まずは真ん中のVStack
にlayoutPriority
を設定します。
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)
}
}
}
すると下記のイメージのような状態になります。
横幅は改善されました。
しかし、まだタイトルが切れてしまっている状態です。
そこで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)
}
}
}
すると下記のような形になります。
もし何か参考になりましたら幸いです。
逆に間違いや他に良い方法があれば
教えていただけると嬉しいです🙇🏻♂️