SwiftUI实现滑入视图:保持主视图尺寸不被挤压的方案
滑入视图推开主视图的实现方案
问题场景
滑动前效果:
滑动后效果:
当前代码实现:
struct SlideView: View { @State var isClicked = false var body: some View { HStack{ Rectangle() .fill(.gray) .ignoresSafeArea() .frame(width: isClicked ? UIScreen.main.bounds.width * 0.75 : 0) VStack{ Text("This gets squished") HStack{ Button{ withAnimation(.spring()) { isClicked.toggle() } } label: { Image(systemName: "menucard.fill") .padding(.leading) } Spacer() } Spacer() } } } }
现有问题:HStack布局会让灰色视图和主视图按比例分配空间,导致主视图被挤压至原尺寸的25%,需要实现灰色视图滑入时推开主视图,主视图保持原尺寸,仅显示左部1/4区域,其余部分隐藏。
解决方案
使用ZStack配合偏移和裁剪功能,让主视图始终保持全屏尺寸,通过偏移实现被推开的视觉效果,同时裁剪超出屏幕的部分:
struct SlideView: View { @State var isClicked = false private let menuWidth = UIScreen.main.bounds.width * 0.75 var body: some View { ZStack(alignment: .leading) { // 滑入的灰色菜单视图 Rectangle() .fill(.gray) .ignoresSafeArea() .frame(width: menuWidth) // 主视图:保持全屏尺寸,通过偏移实现被推开效果 VStack{ Text("This no longer gets squished") HStack{ Button{ withAnimation(.spring()) { isClicked.toggle() } } label: { Image(systemName: "menucard.fill") .padding(.leading) } Spacer() } Spacer() } .frame(maxWidth: .infinity, maxHeight: .infinity) .offset(x: isClicked ? menuWidth : 0) .clipped() // 裁剪超出屏幕的部分,只显示左部1/4区域 } } }
原理说明
ZStack将灰色菜单和主视图层叠布局,菜单在底层,主视图在顶层- 主视图通过
frame(maxWidth: .infinity, maxHeight: .infinity)保持全屏尺寸 - 点击按钮时,主视图向右偏移
menuWidth(屏幕宽度的75%),此时屏幕内仅能显示主视图左部25%的区域 clipped()裁剪掉主视图超出屏幕的部分,实现“仅显示左部1/4”的效果- 配合
withAnimation(.spring())实现平滑的过渡动画
内容的提问来源于stack exchange,提问作者Tom Mils
相关产品推荐
相关产品推荐

