SwiftUI:如何横向呈现 FullScreenCover
SwiftUI: How to present a FullScreenCover Sideways
我正在制作一个应用程序,其中多个 pages/views 嵌入到一个 parent 视图中,该视图具有标签栏、菜单栏和 header,像这样:
HeaderView()
MenuView()
TabView(selection: $selected){
HomeView()
Page2View()
Page3View()
Page4View()
}
当用户点击其中一个页面上的列表单元格时,我希望它打开到详细视图 侧向 ,而不是打开 sheet/modal 垂直打开,隐藏菜单栏,header,和标签栏..我试过为此使用 FullScreenCover,但它总是自下而上显示,我不知道如何显示它从侧面。
我也尝试过使用 NavigationLink,但是当我不希望它们显示时,它会保留选项卡栏、菜单栏和 header,而且我无法弄清楚如何使详细视图全屏显示。
您知道有什么方法可以让 FullsSreenCover 横向打开,或者让 NavigationLink 在另一个视图内时填满整个屏幕吗?
对动画使用overlay
父视图
struct ContentView: View {
@State var isShowSheet: Bool = false
var body: some View {
VStack{
Button("Show Sheet") {
withAnimation {
isShowSheet.toggle()
}
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.overlay(isShowSheet ? FullScreen(isShowSheet: $isShowSheet.animation()) : nil)
}
}
全屏视图
struct FullScreen: View {
@Binding var isShowSheet: Bool
var body: some View {
Color.blue
.transition(.move(edge: .leading))
.onTapGesture {
isShowSheet = false
}
.edgesIgnoringSafeArea(.all)
}
}
第二个选项是使用带有自定义动画的 UIViewController。
我从这个 link (// ) 中使用了 viewControllerHolder 扩展并添加了 CATransition()
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.presentController(toPresent)
}
func presentController(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.25
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromLeft
self.view.window?.layer.add(transition, forKey: kCATransition)
present(viewControllerToPresent, animated: false)
}
func dismissController() {
let transition = CATransition()
transition.duration = 0.25
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
self.view.window?.layer.add(transition, forKey: kCATransition)
dismiss(animated: false)
}
}
ContentView 和全屏
struct ContentView: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
var body: some View {
VStack{
Button("Show Sheet") {
viewControllerHolder?.present(style: .overFullScreen, builder: {
FullScreen()
})
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
struct FullScreen: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
var body: some View {
Color.blue
.onTapGesture {
viewControllerHolder?.dismissController()
}
.edgesIgnoringSafeArea(.all)
}
}
我正在制作一个应用程序,其中多个 pages/views 嵌入到一个 parent 视图中,该视图具有标签栏、菜单栏和 header,像这样:
HeaderView()
MenuView()
TabView(selection: $selected){
HomeView()
Page2View()
Page3View()
Page4View()
}
当用户点击其中一个页面上的列表单元格时,我希望它打开到详细视图 侧向 ,而不是打开 sheet/modal 垂直打开,隐藏菜单栏,header,和标签栏..我试过为此使用 FullScreenCover,但它总是自下而上显示,我不知道如何显示它从侧面。 我也尝试过使用 NavigationLink,但是当我不希望它们显示时,它会保留选项卡栏、菜单栏和 header,而且我无法弄清楚如何使详细视图全屏显示。
您知道有什么方法可以让 FullsSreenCover 横向打开,或者让 NavigationLink 在另一个视图内时填满整个屏幕吗?
对动画使用overlay
父视图
struct ContentView: View {
@State var isShowSheet: Bool = false
var body: some View {
VStack{
Button("Show Sheet") {
withAnimation {
isShowSheet.toggle()
}
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.overlay(isShowSheet ? FullScreen(isShowSheet: $isShowSheet.animation()) : nil)
}
}
全屏视图
struct FullScreen: View {
@Binding var isShowSheet: Bool
var body: some View {
Color.blue
.transition(.move(edge: .leading))
.onTapGesture {
isShowSheet = false
}
.edgesIgnoringSafeArea(.all)
}
}
第二个选项是使用带有自定义动画的 UIViewController。
我从这个 link (// CATransition()
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.presentController(toPresent)
}
func presentController(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.25
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromLeft
self.view.window?.layer.add(transition, forKey: kCATransition)
present(viewControllerToPresent, animated: false)
}
func dismissController() {
let transition = CATransition()
transition.duration = 0.25
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
self.view.window?.layer.add(transition, forKey: kCATransition)
dismiss(animated: false)
}
}
ContentView 和全屏
struct ContentView: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
var body: some View {
VStack{
Button("Show Sheet") {
viewControllerHolder?.present(style: .overFullScreen, builder: {
FullScreen()
})
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
struct FullScreen: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
var body: some View {
Color.blue
.onTapGesture {
viewControllerHolder?.dismissController()
}
.edgesIgnoringSafeArea(.all)
}
}