界面设计:平台称号输入框
声明好需要的变量后,我们来搭建平台称号输入框内容,我们可以和搭建closeBtn关闭按钮视图一样,单独搭建平台输入框视图,再将该视图内容赋予NewView主要的视图中,如下代码所示:
// 头衔名称输入框 func titleInputView() -> some View { TextField("请输入头衔", text: $title) .padding() .background(Color(.systemGray6)) .cornerRadius(8) .padding(.horizontal) }
上述代码中,我们创建了一个平台称号输入框视图titleInputView,主体内容使用TextField输入框控件,输入框提示文字为“请输入头衔”,输入内容绑定声明的变量title。
在样式方面,为了突出输入框视图内容,使用padding修饰符“撑开”输入框外层区域,将外层区域填充背景色为systemGray6,并设置圆角度数为8,最后设置水平位置两边留白,便实现了上图效果。
界面设计:自定义平台选择器
接下来我们来设计“选择平台”的操作逻辑。可以简单设想下,用户在“添加身份卡”页面输入完平台称号后,下一步是选择该称号所在的社区或者平台。
最直观的展现方式是将平台都排列出来让用户进行选择,而由于展示空间有限,我们可以只展示平台的图标。当用户看到平台图标时,通过点击选择以确定平台,而且平台选择单张身份卡只能选择一个平台。
有了基础的想法后,我们来实现这个交互逻辑。
首先需要创建一个平台展示的数据集合,我们声明一个数据用于存放数据,如下代码所示:
private let platforms = [ ("稀土掘金技术社区", "icon_juejin"), ("CSDN博客", "icon_csdn"), ("阿里云社区", "icon_aliyun"), ("华为云社区", "icon_huaweiyun"), ]
上述代码中,我们声明了一个常量数组platforms,在platforms数组内有两个内容,前一个参数是平台名称,后一个参数是平台图标。
声明好数据后,我们来创建平台选择样式部分,这次需要用到的SwiftUI控件是LazyVGrid垂直网格布局容器,LazyVGrid垂直网格布局容器类似VStack垂直布局容器,不同的是VStack垂直布局容器只能将内部的元素垂直排布,而LazyVGrid垂直网格视图容器可以保持垂直布局的情况下,将内部的元素分为几列,如下图所示:
LazyVGrid垂直网格布局容器使用需要提前声明网格的列数,如下代码所示:
private var gridItemLayout = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]
上述代码中,我们声明了布局容器的GridItem列项为4列自适应调整的列项,将参数赋予变量值gridItemLayout。
紧接着我们来使用LazyVGrid垂直网格布局容器,LazyVGrid垂直网格布局容器的使用方法和List列表的使用方法类似,通过与ForEach循环遍历配合使用,我们依旧使用单独构建视图的方法创建它,如下代码所示:
// 平台选择器 func platformPicker() -> some View { LazyVGrid(columns: gridItemLayout, spacing: 10) { ForEach(0 ..< platforms.count, id: .self) { item in Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) } } }
上述代码中,我们创建了“选择平台”视图platformPicker,在platformPicker视图中使用LazyVGrid垂直网格布局容器搭建网格视图,LazyVGrid的columns列项为上面声明的gridItemLayout,网格之间元素的spacing间距为10。
和List列表的方法一样,我们使用ForEach循环遍历platforms数组的数据,并使用了Image图片控件来展示platforms数组中的数据。由于platforms数组使用两个数据,因此我们使用下标法指向数组的第二个数据(计算机数据从0开始计数)。
在这里还需要考虑一个问题,当我们平台图标太多时,可能会占据整个App的页面,我们可以在LazyVGrid垂直网格布局容器最外层增加一个ScrollView滚动视图容器,并设置滚动视图的高度,如此LazyVGrid垂直网格布局容器不管有多少元素,都只会在ScrollView滚动视图容器中展示,如下代码所示:
ScrollView { LazyVGrid(columns: gridItemLayout, spacing: 10) { ForEach(0 ..< platforms.count, id: .self) { item in Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) } } } .padding() .background(Color(.systemGray6)) .cornerRadius(8) .padding(.horizontal) .frame(maxHeight: 180)
很好,完成了“平台选择器”的样式之后,我们来实现交互逻辑部分,首先我们要看到用户点击选择的平台是哪一个,并将其凸显出来。
由于ForEach是遍历数据给到了item,因此当用户点击了指定的item时,该item对应的样式与其他未选中的样式分隔开。为了实现这个效果,我们首先要声明一个变量,知道选中的是哪一个item,如下代码所示:
@State var selectedItem = 0
当选中时,即item的值等于selectedItem时,我们设置图片加一层边框,如果不是,则保持原样,如下代码所示:
if item == selectedItem { Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) .overlay( Circle() .stroke(Color.green, lineWidth: 4) ) } else { Image(platforms[item].1) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 48, height: 48) .clipShape(Circle()) .onTapGesture { selectedItem = item } }
上述代码中,我们通过判断当前的item是否等于selectedItem来构建不同的图片样式,如果一致,则Image图片使用overlay修饰符覆盖一层绿色的圆形边框。如果不一致,则保持原来的样式,在原有的样式上增加onTapGesture点击事件,当点击的时候,让selectedItem选中的item等于点击的item。
可以在模拟器上试试效果,如下图所示:
另外,当点击平台图标时,我们需要给声明的变量进行赋值,如下代码所示:
platformIcon = platforms[item].1 platformName = platforms[item].0
如此,便完成了“自定义平台选择器”的所有内容。