样式部分
Logo展示区域
首先,我们创建一个新的SwiftUI
文件,命名为LogoView
。
然后,我们使用Image
作为logo
展示的区域,示例:
// MARK: Logo展示区域 private var ShowLogoView: some View { Image(systemName: logoImage) .font(.system(size: 68)) .foregroundColor(logoColor) .frame(minWidth: 80, maxWidth: 120, minHeight: 80, maxHeight: 120) .background(bgColor) .cornerRadius(8) } 复制代码
上述代码中,我们声明了三个存储变量logoImage
、logoColor
、bgColor
,分别可以调整logo
的图片、填充色、背景色。
在主要展示页面,我们使用Image
构建logo
视图,并通过修饰符调整logo
的图片大小、logo颜色、整体大小、背景填充颜色和圆角。
Segment分段选择
下面我们来实现切换选择调整logo
各项参数的区域,我们通过Segment
分段选择来区分开,示例:
// MARK: 分选选择 private var SegmentView: some View { Picker("分段选择", selection: $selectedSegment) { ForEach(0 ..< 3) { Text(self.segmentTitle[$0]).tag($0) } } .pickerStyle(SegmentedPickerStyle()) .padding() } 复制代码
上述代码中,我们声明了两个变量segmentTitle
、selectedSegment
。
segmentTitle
用来存储分段器的标题,selectedSegment
来记录当前我们选中的是分段器的哪一项。然后我们使用Picker
实现了分段器的样式,使用ForEach
遍历分段器选项和内容,这里分段器的样式需要选择SegmentedPickerStyle
。
然后我们在LogoView
视图中展示,看起来还不错。
功能交互
背景颜色切换
背景颜色我们使用网格布局来实现,首先我们先声明了网格的列数为4列,然后颜色部分,我们取回之前色卡部分的颜色。
private var gridItemLayout = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())] @State var cardItems: [CardModel] = [] 复制代码
然后构建背景颜色选择的页面,示例:
//MARK: 背景颜色 private var BGColorView: some View { ScrollView { LazyVGrid(columns: gridItemLayout, spacing: 20) { ForEach(cardItems, id: \.cardColorRBG) { item in Rectangle() .fill(Color.Hex(item.cardBGColor)) .frame(width: 80, height: 80) .cornerRadius(8) } } }.padding() } 复制代码
上述代码中,我们构建了一个纵向网格视图,spacing
间距为20
,然后通过遍历cardItems
色卡数组中的数据,然后遍历出一个个色块。
我们把网络请求补充上,然后将BGColorView
在主视图展示看看效果:
交互部分,当我们点击背景颜色色块时,上面logo展示区域的logo也同时需要更改其背景颜色,我们来实现下。示例:
.onTapGesture { bgColor = Color.Hex(item.cardBGColor) } 复制代码
我们给背景颜色部分的色卡添加一个点击事件,点击背景颜色色块时,将颜色赋予logo背景颜色。
这样,我们就完成了背景颜色的设置。
图标图片切换
图标部分切换的原理类似,我们这里换成本地的数据做一下演示,先准备一些Apple
的系统图标作为示例:
private var appleSymbols = ["house.circle", "person.circle", "bag.circle", "location.circle", "bookmark.circle", "gift.circle", "globe.asia.australia.fill", "lock.circle", "pencil.circle", "link.circle"] 复制代码
然后也通过LazyVGrid
纵向网格和ForEach
循环的方式遍历appleSymbols
图片数组的数据,示例:
// MARK: 图标切换 private var SwitchIconView: some View { ScrollView { LazyVGrid(columns: gridItemLayout, spacing: 20) { ForEach(appleSymbols.indices, id: \.self) { item in Image(systemName: appleSymbols[item]) .font(.system(size: 30)) .frame(width: 80, height: 80) .background(bgColor) .cornerRadius(8) .onTapGesture { logoImage = appleSymbols[item] } } } }.padding() } 复制代码
上述代码中,当我们创建了一个图标网格,然后遍历appleSymbols
图片数组的数据,在点击每个图片时,我们把点击的图片赋值到logo区域中logoImage
的变量,就实现了切换图标的效果。
我们来运行下看看效果:
同理,图标填充色我们就把背景颜色那块内容复制一份过来,然后当点击颜色的时候,赋值给logoColor
变量就完成了,这里就不做演示了。
分段选项切换
最后是分段器的切换,我们可以根据selectedSegment
变量作为切换状态值,当selectedSegment
处于不同的值时,我们切换不同的视图。示例:
VStack(spacing: 60) { Spacer() ShowLogoView Spacer() VStack(spacing: -10) { SegmentView if selectedSegment == 0 { BGColorView } else if selectedSegment == 1 { SwitchIconView } else { LogoColorView } } } 复制代码
完成后,我们尝试更改Logo背景颜色、Logo图标、Logo填充色来看看效果。
功能进阶
完成上述内容后,总觉得好像还差点东西,思来想去总算发现一个问题。
当前我们的颜色和Logo图标都是内置的,没有办法自定义。背景颜色和填充色还好,但是Logo图片不能自定义,就…….不够优雅。
接下来,我们来实现自定义Logo图标的方法,最简单的就是本地上传图片。
我们设想下通用的交互,当我们点击图标时,它弹出一个弹窗,让我们选择修改的来源。常用的图片来源有2种:相册、拍照,这里我们只完成相册的部分,毕竟应该很少人会直接拍照作为Logo图标。
打开Sheet弹窗
我们使用官方提供的Sheet弹窗来完成来源选择交互,示例:
// MARK: - 选择来源弹窗 private var chooseImageSheet: ActionSheet { let action = ActionSheet(title: Text("选择来源"), buttons: [.default(Text("相册"), action: { // 打开相册 }), .cancel(Text("取消"), action: { })]) return action } 复制代码
上述代码中,我们构建了一个打开Sheet
弹窗的视图chooseImageSheet
,它的类型是ActionSheet
,即触发Sheet弹窗。
然后我们完善了Sheet弹窗里的相关内容,标题、操作(相册、取消)。
然后我们需要声明一个变量
,判断是否打开Sheet
弹窗,示例:
@State var showChooseImageSheet: Bool = false 复制代码
完成后,我们在LogoView
中使用.actionSheet
修饰符实现打开Sheet
弹窗的交互。示例:
// 选择来源 .actionSheet(isPresented: $showChooseImageSheet, content: {chooseImageSheet }) 复制代码
选择本地图片
我们已经成功调用Sheet
弹窗了,可选项为相册、取消,取消即自动收起Sheet弹窗,而当我们点击相册的时候,需要调用本地相册。
接下来,我们来实现唤起本地相册的功能。
我们新建一个Swift
文件,命名为ImagePickerView
,然后实现以下方法:
import SwiftUI public struct ImagePickerView: UIViewControllerRepresentable { private let sourceType: UIImagePickerController.SourceType private let onImagePicked: (UIImage) -> Void @Environment(\.presentationMode) private var presentationMode public init(sourceType: UIImagePickerController.SourceType, onImagePicked: @escaping (UIImage) -> Void) { self.sourceType = sourceType self.onImagePicked = onImagePicked } public func makeUIViewController(context: Context) -> UIImagePickerController { let picker = UIImagePickerController() picker.sourceType = self.sourceType picker.delegate = context.coordinator return picker } public func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} public func makeCoordinator() -> Coordinator { Coordinator( onDismiss: { self.presentationMode.wrappedValue.dismiss() }, onImagePicked: self.onImagePicked ) } final public class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { private let onDismiss: () -> Void private let onImagePicked: (UIImage) -> Void init(onDismiss: @escaping () -> Void, onImagePicked: @escaping (UIImage) -> Void) { self.onDismiss = onDismiss self.onImagePicked = onImagePicked } public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { if let image = info[.originalImage] as? UIImage { self.onImagePicked(image) } self.onDismiss() } public func imagePickerControllerDidCancel(_: UIImagePickerController) { self.onDismiss() } } } 复制代码
上述代码中,创建了一个公开的结构体ImagePickerView
,遵循UIViewControllerRepresentable
协议。
然后调用系统的UIImagePickerController
选择图片方法,调用成功后就关闭弹窗并且返回选中的图片。
代码中大部分内容为实现选择图片的相关协议和返回UIImage
类型图片的方法,在这里就不赘述了。
我们回到LogoView
文件中,我们先声明必要的参数。示例:
@State var showImagePicker: Bool = false @State var image: UIImage? 复制代码
上述代码中,showImagePicker
是我们是否打开选择图片的弹窗,而image
则用来接收我们相册中选择的图片。
我们使用.sheet
调用打开本地相册的方法。示例:
// 本地图片选择弹窗 .sheet(isPresented: $showImagePicker) { ImagePickerView(sourceType: .photoLibrary) { image in self.image = image } } 复制代码
我们使用showImagePicker
绑定了打开本地图片弹窗的条件,我们把这个触发条件放在我们点击“相册”选项的操作。示例:
图标图片替换
上述代码中,我们已经通过调用本地相册的方法,获得了选中的图片,这时我们需要替换当前Logo
的图标。
我们创建多一个视图来展示选中图片后回调的内容。示例:
// MARK: 本地图片 private var ShowImageView: some View { Image(uiImage: image!) .resizable() .frame(width: 68, height: 68, alignment: .center) .clipShape(Circle()) .padding(20) .background(bgColor) .cornerRadius(8) .onTapGesture { self.showChooseImageSheet.toggle() } } 复制代码
上述代码中,我们创建了一个新的视图ShowImageView
,Image
图片的内容换成了换取本地图库中选中回调的image
。
图标图片部分,使用clipShape
修饰符切成圆形比较美观,背景颜色可调节,图标由于是图标就无需进行填充色调整了。
我们在LogoView
视图中根据image
的有无,展示不同的视图。效果如下:
项目预览
恭喜你,完成了本章的所有内容!
快来动手试试吧!