展开&收起,使用SwiftUI搭建一个侧滑展开页面交互
项目背景
闲来无事,在使用某云音乐听歌的时候发现一个侧滑展开的内页,交互效果还不错。
那么这一章节中,我们将使用SwiftUI
搭建一个侧边展开页面交互。
项目搭建
首先,创建一个新的SwiftUI
项目,命名为SlideOutMenu
。
逻辑分析
首先我们来分析下基本的逻辑,一般的侧滑展开方式的交互是,在首页右上角有一个“更多”的按钮,点击按钮时,内页菜单从左往右划出,滑出至离右边20~30的位置停止。
然后首页背景将蒙上一个蒙层,点击蒙层时,侧滑展开的页面从右往左收起。
简单分析完逻辑后,我们来实现这个交互。
首页入口
首先,我们需要在首页搭建一个入口,示例:
// 顶部导航入口 private var moreBtnView: some View { Button(action: { }) { Image(systemName: "list.bullet") .foregroundColor(.black) } }
然后,我们可以使用NavigationView
和navigationBarItems
创建顶部导航按钮样式,示例:
var body: some View { NavigationView { Text("点击左上角侧滑展开") .padding() .navigationBarTitle("首页", displayMode: .inline) .navigationBarItems(leading: moreBtnView) } }
如此,首页入口部分我们就完成了。
左边菜单
接下来,我们来构建左侧菜单的内容。我们可以沿用之前设计过的“设置”页面的结构,我们先来构建栏目结构。示例:
// MARK: 栏目结构 struct listItemView: View { var itemImage: String var itemName: String var body: some View { Button(action: { }) { HStack { Image(systemName: itemImage) .font(.system(size: 17)) .foregroundColor(.black) Text(itemName) .foregroundColor(.black) .font(.system(size: 17)) Spacer() Image(systemName: "chevron.forward") .font(.system(size: 14)) .foregroundColor(.gray) }.padding(.vertical, 10) } } } 作者:文如秋雨 链接:https://juejin.cn/post/7132848697666175006 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在我们构建侧滑展开的页面前,我们需要声明两个变量,一个是侧滑展开的页面的宽度,一个是当前这个页面的位置。示例:
@State var menuWidth = UIScreen.main.bounds.width - 60 @State var offsetX = -UIScreen.main.bounds.width + 60
我们设置的侧滑展开页面的宽度是屏幕宽度-60
,而当前侧滑展开页面的位置是负位置
,这样就可以在展示的时候先把页面隐藏起来。
而当我们点击顶部导航中的“更多”按钮时,将offsetX
偏移量X轴坐标设置为0
。示例:
// 顶部导航入口 private var moreBtnView: some View { Button(action: { withAnimation { offsetX = 0 } }) { Image(systemName: "list.bullet") .foregroundColor(.black) } }
然后,我们创建一个新视图来构建侧滑展开的页面内容,示例:
// MARK: 左侧菜单 struct SlideOutMenu: View { @Binding var menuWidth: CGFloat @Binding var offsetX: CGFloat var body: some View { Form { Section { } Section { listItemView(itemImage: "lock", itemName: "账号绑定") listItemView(itemImage: "gear.circle", itemName: "通用设置") listItemView(itemImage: "briefcase", itemName: "简历管理") } Section { listItemView(itemImage: "icloud.and.arrow.down", itemName: "版本更新") listItemView(itemImage: "leaf", itemName: "清理缓存") listItemView(itemImage: "person", itemName: "关于掘金") } } .padding(.trailing, UIScreen.main.bounds.width - menuWidth) .edgesIgnoringSafeArea(.all) .shadow(color: Color.black.opacity(offsetX != 0 ? 0.1 : 0), radius: 5, x: 5, y: 0) .offset(x: offsetX) .background( Color.black.opacity(offsetX == 0 ? 0.5 : 0) .ignoresSafeArea(.all, edges: .vertical) .onTapGesture { withAnimation { offsetX = -menuWidth } }) } }
上述代码中,我们也对页面宽度menuWidth
、偏移位置offsetX
进行了声明,方便之后我们在ContentView
视图中进行双向绑定。
我么使用Form
表单和Section
段落构建样式,这点就不说了。
值得说的一点是,我们设置了在页面展开的时候,也就是offsetX
页面偏移量X轴坐标不为0
,我们加了一个阴影,完善了侧滑展开页面的悬浮效果。
然后使用offset
调整页面初始位置。背景部分,除了根据offsetX
页面偏移量X轴坐标加了一个蒙层,而且当我们点击的背景的时候,我们将偏移位置offsetX
重新赋值,这样就能实现收起的交互效果。
我们在ContentView
视图中展示侧滑展开视图,示例:
var body: some View { ZStack { NavigationView { Text("点击左上角侧滑展开") .padding() .navigationBarTitle("首页", displayMode: .inline) .navigationBarItems(leading: moreBtnView) } SlideOutMenu(menuWidth: $menuWidth, offsetX: $offsetX) } }
项目展示
恭喜你,完成了本章的全部内容!
快来动手试试吧。