SwiftUIの登場で画面の開発効率はあがりましたが、一方で今まで普通に出来ていたことがすぐ出来ず戸惑う場面も増えました。
この記事ではSwiftUIの微妙な所とその対処法を紹介していきます。
新しい微妙な所を発見したら随時追加していきます。
Listの罫線が勝手に短くなる問題
Listはとても簡単に表を作ってくれて便利なのですが左寄りになるため、ちょっと不格好なレイアウトになってしまいます。
そこで次のようなコードを書くとセンタリングにできますが、罫線が微妙なことになります。
let fruits = [
"りんご", "バナナ", "みかん", "イチゴ"
]
var body: some View {
List {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
.frame(maxWidth: .infinity, alignment: .center) // コレ追加
}
}
}
なぜか罫線が短く….
罫線は最初に出てくるTextの位置に反応しているようなので次のようにコードを書き直すといい感じになります。
List {
ForEach(fruits, id: \.self) { fruit in
HStack {
Text("") // ダミー
Text(fruit)
.frame(maxWidth: .infinity, alignment: .center)
}
}
}
同様に、Imageを最初に置いたListでも罫線が短くなりますが、
次のようにコードを書けば全体に罫線が引かれます。
List {
ForEach(fruits, id: \.self) { fruit in
HStack {
Text("") // ダミー
Image(systemName: "star.leadinghalf.filled")
Text(fruit)
.frame(maxWidth: .infinity, alignment: .center)
}
}
}
これを応用すれば間延びになりがちなToggle(Switch)も
こう書けば
List {
ForEach(fruits, id: \.self) { fruit in
HStack {
Text("")
Toggle(isOn: $dummy) {
Text(fruit)
.frame(maxWidth: .infinity, alignment:
.center)
}
}
}
}
Listのcellのタップ範囲が狭い問題
一番シンプルなListはこんなコードになるけど、これだと文字の部分しかタップが反応しません。
struct ContentView: View {
let fruits = [
"りんご", "バナナ", "みかん", "イチゴ"
]
var body: some View {
List {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
.onTapGesture {
print(fruit)
}
}
}
}
}
行のどこを押しても反応するようにするには、コードをこう変えるとOKです。
List {
ForEach(fruits, id: \.self) { fruit in
HStack {
Text(fruit)
Spacer() //これ足す
}
.contentShape(Rectangle()) // これも足す
.onTapGesture {
print(fruit)
}
}
}
これでもOK
List {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
.frame(maxWidth: .infinity, alignment: .leading)
.contentShape(Rectangle())
.onTapGesture {
print(fruit)
}
}
}
Listのタップ処理に飲み込まれてcellに置いたボタンが反応しない問題
Listの中にボタンも配置するのは良くあると思いますが、Listのタップ判定が優先されてボタンが反応しません。
List {
ForEach(fruits, id: \.self) { fruit in
HStack {
Text(fruit)
Spacer()
Button(action: {
print("ボタンタップだよ")
}) {
Image(systemName: "bitcoinsign.circle")
}
}
.contentShape(Rectangle())
.onTapGesture {
print("行タップだよ")
}
}
}
こんな時は、コードをこう変えるとボタンがちゃんと反応するようになります。
(.buttonStyle(PlainButtonStyle())をButtonに足す)
List {
ForEach(fruits, id: \.self) { fruit in
HStack {
Text(fruit)
Spacer()
Button(action: {
print("ボタンタップだよ")
}) {
Image(systemName: "bitcoinsign.circle")
}
.buttonStyle(PlainButtonStyle()) // コレ足す
}
.contentShape(Rectangle())
.onTapGesture {
print("行タップだよ")
}
}
}
Buttonのタップ範囲が文字だけ問題
Buttonのframeを大きくセットしてみためを大きくしてもButtonのタップ範囲は文字の部分だけになります。
Button(action: {
print("押した!")
}) {
Text("押してください!")
}
.frame(maxWidth: .infinity, maxHeight: 44)
.background(Color.orange)
ボタン全体をタップ範囲にするには文字列の部分にframeをセットするとOKです。
Button(action: {
print("押した!")
}) {
Text("押してください!")
.frame(maxWidth: .infinity, maxHeight: .infinity) //
コレ足す
}
.frame(maxWidth: .infinity, maxHeight: 44)
.background(Color.orange)
Buttonを押しても文字しか半透明にならない問題
おしゃれなButtonにしようと思って、Buttonに枠線や角丸をセットしても、押した時には文字の部分しか半透明にならず、押したかどうかが視覚的に分かりづらくなります。
Button(action: {
print("押した!")
}) {
Text("押してください!")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.frame(width: UIScreen.main.bounds.width-40, height: 60)
.foregroundColor(Color(UIColor.darkGray))
.background(Color.white)
.cornerRadius(30)
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(Color(UIColor.darkGray), lineWidth: 1.0)
)
こういう場合は、ボタンの装飾をButton側ではなくText側に適用することでButton全体を半透明にできるようになります。
Button(action: {
print("押した!")
}) {
Text("押してください!")
.frame(width: UIScreen.main.bounds.width-40, height:
60)
.foregroundColor(Color(UIColor.darkGray))
.background(Color.white)
.cornerRadius(30)
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(Color(UIColor.darkGray), lineWidth:
1.0)
)
}