LoginSignup
3
2

More than 1 year has passed since last update.

別Viewを表示するModifier(sheet, alertなど)の位置は大切(SwiftUIの癖)

Posted at

問題

メニューの中にisPresentedを切り替えて、Text("Next View")をsheet表示させるボタンがあります。

以下のコードで動くでしょうか?

struct ContentView: View {
  @State var isPresented = false
  
  var body: some View {
    Menu {
      Button {
        isPresented.toggle()
      } label: {
        Text("Button")
      }
      .sheet(isPresented: $isPresented) {
        Text("Next View")
      }

    } label: {
      Text("Menu")
    }
  }
}

解答: なんと動きません!

動かない原因は、.sheet(View Modifier)の位置です。
Menu内のButtonはクリックされた瞬間に消えてしまいます。
そのため.sheet(View Modifier)も消えてしまうのです。

解決方法(Tips)

Buttonでsheet表示させたい時はButtonの一段階上にさせよう

struct ContentView: View {
  @State var isPresented = false
  
  var body: some View {
    Menu {
      Button {
        isPresented.toggle()
      } label: {
        Text("Button")
      }
    } label: {
      Text("Menu")
    }
    .sheet(isPresented: $isPresented) {
      Text("Next View")
    }
  }
}

alertやfullScreenCoverも同様

struct ContentView: View {
  @State var isPresented = false
  
  var body: some View {
    Menu {
      Button {
        isPresented.toggle()
      } label: {
        Text("Button")
      }
      .alert("Alert", isPresented: $isPresented) {
        Button("Close") {}
      }
    } label: {
      Text("Menu")
    }
  }
}

おまけ(PhotosPicker)

このコードも一見動きそうですが、動きません。

import PhotosUI

struct ContentView: View {
  @State var photoItem: PhotosPickerItem?
  
  var body: some View {
    Menu {
      PhotosPicker("Photo", selection: $photoItem)
    } label: {
      Text("Menu")
    }
  }
}

これは動きます。

struct ContentView: View {
  @State var isPresented = false
  @State var photoItem: PhotosPickerItem?
  
  var body: some View {
    Menu {
      Button("Photo") { isPresented.toggle() }
    } label: {
      Text("Menu")
    }
    .photosPicker(isPresented: $isPresented, selection: $photoItem)
  }
}

これからわかるPhotosPickerの実装

こういった実装のためMenu内では動作しないことがわかる

struct PhotosPicker: View {
  @State var isPresented: Bool = false
  @Binding var photoItem: PhotosPickerItem?
  
  var body: some View {
    Button("Photo") {
      isPresented.toggle()
    }
    .photosPicker(isPresented: $isPresented, selection: $photoItem)
  }
}
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2