SwiftUI入門-勉強メモ013- 【Picker】

SwiftUI


Viewの上にこれらのコントロール(UI部品)を配置してアプリを作成していきます. 今回は基本部品の一つPickerです.

環境は,

  • macOS Catalina 10.15.7
  • Xcode 12.0.1
  • Swift 5.3
  • iOS 14.0

です.

目次

Pickerとは

複数の選択肢の中から1つを選ぶことができるViewです.

SwiftUI
Pickerの基本的なinitializer
init(selection: Binding<SelectionValue>, label: Label, content: () -> Content)
  • selection: Pickerで選んだ値をこの状態変数で受け取ることができます
  • label: Pickerのラベルに表示されるView
  • content:選択項目をここに書きます

Pickerの具体例

簡単な例

import SwiftUI

struct ContentView: View {
    
    @State var selectedText = "赤"
    
    var body: some View {
        VStack{
            Picker(
                selection: $selectedText,
                label: Text("色を選んでください")
            ){
                Text("赤").tag("赤")
                Text("青").tag("青")
                Text("黄").tag("黄")
                Text("緑").tag("緑")
                Text("紫").tag("紫")
            }
            Text(selectedText)
        }
    }
}

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

現在のmacOS Catalina 10.15.7, Xcode 12.0.1, Swift 5.3, iOS 14.0という環境では, labelが表示されません. コードの書き方が間違っているんでしょうか…

SwiftUI
2020/10/13現在

PickerStyleを変える

Pickerにはいくつかのスタイルが用意されています.

スタイル説明
DefaultPickerStyleデフォルト
SegmentedPickerStyleセグメント型のPicker
WheelPickerStyleホイール型のPicker

ただ, DefaultPickerStyleはWheelPickerStyleなので, 他のタイプはSegmentedPickerStyleになります.

次のようなものがSegmentedPickerStyleです.

import SwiftUI

struct ContentView: View {
    
    @State var selectedText = "赤"
    
    var body: some View {
        VStack{
            Picker(
                selection: $selectedText,
                label: Text("色を選んでください")
            ){
                Text("赤").tag("赤")
                Text("青").tag("青")
                Text("黄").tag("黄")
                Text("緑").tag("緑")
                Text("紫").tag("紫")
            }
            .pickerStyle(SegmentedPickerStyle())
            .padding()
            Text(selectedText)
        }
    }
}
SwiftUI

Pickerの選択項目に列挙型を用いる

このコードは公式サイトのものからの引用です.

import SwiftUI

enum Flavor: String, CaseIterable, Identifiable {
    case chocolate
    case vanilla
    case strawberry
    
    var id: String { self.rawValue }
}

struct ContentView: View {
    
    @State private var selectedFlavor = Flavor.chocolate
    
    var body: some View {
        Picker("Flavor", selection: $selectedFlavor) {
            Text("Chocolate").tag(Flavor.chocolate)
            Text("Vanilla").tag(Flavor.vanilla)
            Text("Strawberry").tag(Flavor.strawberry)
        }
        Text("Selected flavor: \(selectedFlavor.rawValue)")
    }
}
SwiftUI

選択肢にForEachを用いる

選択肢をForEachで作成することもできます. 他のものと似ているので画像は省略します.

import SwiftUI

struct ContentView: View {
    var colors = ["赤", "青", "黄", "緑", "紫"]
    @State var selected = 0
    
    var body: some View {
        VStack{
            Picker(
                selection: $selected,
                label: Text("色を選んでください")
            ){
                ForEach(0..<colors.count){
                    Text(self.colors[$0])
                }
            }
            .padding()
            Text("選んだ色は\(colors[selected])です")
        }
    }
}

PickerをHStackを用いて横に2つ並べる

はまりました. 普通にコードを書くとうまくいきませんでした. 例えば, 次のように並べると, うまく真ん中にいきません.

import SwiftUI

struct ContentView: View {
    var column = ["1", "2", "3", "4", "5"]
    var row = ["1", "2", "3", "4", "5"]
    
    @State var selectedColumn = 0
    @State var selectedRow = 0
    
    var body: some View {
        VStack{
            HStack{
                Picker(
                    selection: $selectedColumn,
                    label: Text("Selected cloumn")
                ){
                    ForEach(0..<column.count){
                        Text(self.column[$0])
                    }
                }
                .border(Color.red)
                Picker(
                    selection: $selectedRow,
                    label: Text("Selected row")
                ){
                    ForEach(0..<row.count){
                        Text(self.row[$0])
                    }
                }
                .border(Color.blue)
            }
        }
    }
}
SwiftUI
なぜか数字が端によってしまいます

こんなところで悩むと思わず, 呆然. 悩んでいたところ, 解決策がありました. Stack Overflowにはお世話になりっぱなしです.

この回答を参考にコードを書くと次のようになります.

import SwiftUI

struct ContentView: View {
    var column = ["1", "2", "3", "4", "5", "6", "7"]
    var row = ["1", "2", "3", "4", "5", "6", "7"]
    
    @State var selectedColumn = 0
    @State var selectedRow = 0
    
    var body: some View {
        GeometryReader { geometry in
            VStack{
                Text("座席数を選んでください")
                    .padding()
                    .foregroundColor(.pink)
                HStack(spacing: 0) {
                    VStack {
                        Text("何行目")
                        Picker(
                            selection: $selectedColumn,
                            label: Text("Selected cloumn")
                        ){
                            ForEach(0..<column.count){
                                Text(self.column[$0])
                            }
                        }
                        .frame(maxWidth: geometry.size.width / 2)
                        .clipped()
                    }
                    VStack {
                        Text("何列目")
                        Picker(
                            selection: $selectedRow,
                            label: Text("Selected row")
                        ){
                            ForEach(0..<row.count){
                                Text(self.row[$0])
                            }
                        }
                        .frame(maxWidth: geometry.size.width / 2)
                        .clipped()
                    }
                }
                HStack{
                Text("選んだ座席数は")
                Text("\(selectedColumn + 1) × \(selectedRow + 1)")
                    .font(.title)
                    .foregroundColor(.purple)
                Text("です")
                }
            }
        }
    }
}
SwiftUI

pickerの値に応じて座席のButtonを表示させる

思ったより大変でした. そしてコードが見にくくてすみません.

import SwiftUI

struct ContentView: View {
    var column = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
    var row = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
    
    @State var selectedColumn = 0
    @State var selectedRow = 0
    
    var body: some View {
        GeometryReader { geometry in
            VStack{
                Text("座席数を選んでください")
                    .padding()
                    .foregroundColor(.pink)
                HStack(spacing: 0) {
                    VStack {
                        Text("何行目")
                        Picker(
                            selection: $selectedColumn,
                            label: Text("Selected cloumn")
                        ){
                            ForEach(0..<column.count){
                                Text(self.column[$0])
                            }
                        }
                        .frame(maxWidth: geometry.size.width / 2)
                        .clipped()
                    }
                    VStack {
                        Text("何列目")
                        Picker(
                            selection: $selectedRow,
                            label: Text("Selected row")
                        ){
                            ForEach(0..<row.count){
                                Text(self.row[$0])
                            }
                        }
                        .frame(maxWidth: geometry.size.width / 2)
                        .clipped()
                    }
                }
                HStack{
                    Text("選んだ座席数は")
                    Text("\(selectedColumn + 1) × \(selectedRow + 1)")
                        .font(.title)
                        .foregroundColor(.purple)
                    Text("です")
                }
                SubView(row: $selectedRow, column: $selectedColumn)
                    .padding()
            }
        }
    }
}


struct SubView: View {
    @Binding var row: Int
    @Binding var column: Int
    var seatsNumber = 1
    
    var body: some View {
        VStack{
            ForEach(0..<column+1, id:\.self) {_ in
                HStack{
                    ForEach(0..<row+1, id:\.self) {_ in
                        Button(action: {}) {
                            Text("").modifier(CustomModifier())
                        }
                    }
                }
            }
        }
    }
}

//ボタン内のテキストの装飾
struct CustomModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .frame(width: 20)
            .padding(5)
            .foregroundColor(.red)
            .background(Color.blue)
            .cornerRadius(5)
            .overlay(RoundedRectangle(cornerRadius: 5)
                        .stroke(Color.pink, lineWidth: 1)
            )
    }
}
SwiftUI
よかったらシェアしてね!

コメント

コメントする

目次
閉じる