「Slide from Botton」アニメーションで別のシーンを表示するボタンを実装しようとしています。
PresentationButtonは良い候補のように見えたので、試してみました。
import SwiftUI
struct ContentView : View {
var body: some View {
NavigationView {
PresentationButton(destination: Green().frame(width: 1000.0)) {
Text("Click")
}.navigationBarTitle(Text("Navigation"))
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
Group {
ContentView()
.previewDevice("iPhone X")
.colorScheme(.dark)
ContentView()
.colorScheme(.dark)
.previewDevice("iPad Pro (12.9-inch) (3rd generation)"
)
}
}
}
#endif
緑のビューが画面全体を覆い、モーダルが「ドラッグして閉じる」ことができないようにしたい。
修飾子をPresentationButtonに追加してフルスクリーンにしてドラッグできないようにすることはできますか?
ナビゲーションボタンも試してみましたが、-「下からスライド」しません-詳細ビューに「戻るボタン」を作成します。
ありがとう!
残念ながら、現在 ベータ2 ベータ3、これは純粋なSwiftUIでは不可能です。 Modal
パラメータがない がUIModalPresentationStyle.fullScreen
。同様に PresentationButton の場合。
レーダーを提出することをお勧めします。
あなたが現在できる最も近いものは次のようなものです:
@State var showModal: Bool = false
var body: some View {
NavigationView {
Button(action: {
self.showModal = true
}) {
Text("Tap me!")
}
}
.navigationBarTitle(Text("Navigation!"))
.overlay(self.showModal ? Color.green : nil)
}
もちろん、そこからオーバーレイに好きなトランジションを追加できます。
私の他の答えは現在正しいですが、人々はおそらくこれを今できるようにしたいと思うでしょう。 Environment
を使用して、ビューコントローラーを子に渡すことができます。 ここに要旨
_struct ViewControllerHolder {
weak var value: UIViewController?
}
struct ViewControllerKey: EnvironmentKey {
static var defaultValue: ViewControllerHolder { return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController ) }
}
extension EnvironmentValues {
var viewController: UIViewControllerHolder {
get { return self[ViewControllerKey.self] }
set { self[ViewControllerKey.self] = newValue }
}
}
_
UIViewControllerに拡張機能を追加する
_extension UIViewController {
func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
// Must instantiate HostingController with some sort of view...
let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
toPresent.modalPresentationStyle = style
// ... but then we can reset rootView to include the environment
toPresent.rootView = AnyView(
builder()
.environment(\.viewController, ViewControllerHolder(value: toPresent))
)
self.present(toPresent, animated: true, completion: nil)
}
}
_
そして、必要なときはいつでも使用してください:
_struct MyView: View {
@Environment(\.viewController) private var viewControllerHolder: ViewControllerHolder
private var viewController: UIViewController? {
self.viewControllerHolder.value
}
var body: some View {
Button(action: {
self.viewController?.present(style: .fullScreen) {
MyView()
}
}) {
Text("Present me!")
}
}
}
_
[編集] @Environment(\.viewController) var viewController: UIViewController?
のようなことをすることが望ましいですが、これは保持サイクルにつながります。したがって、ホルダーを使用する必要があります。
だから私はそれに苦労していました、そしてそれは私にいくつかのメモリバグを与え、私はiOSに非常に新しいのでSwiftUIだけを知っていてUIKitを知らないので、オーバーレイ機能もViewControllerラップバージョンも好きではありませんでした。
私は credits SwiftUIを使用して以下を開発しました。これはおそらくオーバーレイが行うことですが、私の目的でははるかに柔軟性があります。
struct FullscreenModalView<Presenting, Content>: View where Presenting: View, Content: View {
@Binding var isShowing: Bool
let parent: () -> Presenting
let content: () -> Content
@inlinable public init(isShowing: Binding<Bool>, parent: @escaping () -> Presenting, @ViewBuilder content: @escaping () -> Content) {
self._isShowing = isShowing
self.parent = parent
self.content = content
}
var body: some View {
GeometryReader { geometry in
ZStack {
self.parent().zIndex(0)
if self.$isShowing.wrappedValue {
self.content()
.background(Color.primary.colorInvert())
.edgesIgnoringSafeArea(.all)
.frame(width: geometry.size.width, height: geometry.size.height)
.transition(.move(Edge: .bottom))
.zIndex(1)
}
}
}
}
}
View
に拡張機能を追加する:
extension View {
func modal<Content>(isShowing: Binding<Bool>, @ViewBuilder content: @escaping () -> Content) -> some View where Content: View {
FullscreenModalView(isShowing: isShowing, parent: { self }, content: content)
}
}
使用法:カスタムビューを使用し、showModal
変数をBinding<Bool>
として渡して、ビュー自体からモーダルを閉じます。
struct ContentView : View {
@State private var showModal: Bool = false
var body: some View {
ZStack {
Button(action: {
withAnimation {
self.showModal.toggle()
}
}, label: {
HStack{
Image(systemName: "eye.fill")
Text("Calibrate")
}
.frame(width: 220, height: 120)
})
}
.modal(isShowing: self.$showModal, content: {
Text("Hallo")
})
}
}
これが役に立てば幸いです!
あいさつkrjw
このバージョンでは、XCode 11.1に存在するコンパイルエラーが修正され、渡されたスタイルでコントローラーが表示されるようになっています。
import SwiftUI
struct ViewControllerHolder {
weak var value: UIViewController?
}
struct ViewControllerKey: EnvironmentKey {
static var defaultValue: ViewControllerHolder {
return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)
}
}
extension EnvironmentValues {
var viewController: UIViewController? {
get { return self[ViewControllerKey.self].value }
set { self[ViewControllerKey.self].value = newValue }
}
}
extension UIViewController {
func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
toPresent.modalPresentationStyle = style
toPresent.rootView = AnyView(
builder()
.environment(\.viewController, toPresent)
)
self.present(toPresent, animated: true, completion: nil)
}
}
このバージョンを使用するために、コードは前のバージョンから変更されていません。
struct MyView: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
private var viewController: UIViewController? {
self.viewControllerHolder.value
}
var body: some View {
Button(action: {
self.viewController?.present(style: .fullScreen) {
MyView()
}
}) {
Text("Present me!")
}
}
}