0
点赞
收藏
分享

微信扫一扫

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器

前言

在本章中,你将学会使用​​Segment​​​分段器、​​LazyVGrid​​​垂直网格、​​ImagePicker​​图片选择器构建一个Logo生成器

在上一章中,我们完善了​​SearchBar​​​搜索栏、​​TabView​​​底部导航,还有做了一个​​Loading​​加载动作。最近突然有个想法,如果把色卡图片进行组合,这不就是一个简单的Logo了吗?我能不能做个Logo生成器

说干就干,我们继续完成​​App​​的相关内容。

样式部分

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)
}

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_Swift

上述代码中,我们声明了三个存储变量​​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()
}

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_背景颜色_02

上述代码中,我们声明了两个变量​​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​​在主视图展示看看效果:

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_背景颜色_03

交互部分,当我们点击背景颜色色块时,上面logo展示区域的logo也同时需要更改背景颜色,我们来实现下。示例:

.onTapGesture {
bgColor

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_Swift_04

我们给背景颜色部分的色卡添加一个点击事件,点击背景颜色色块时,将颜色赋予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​​的变量,就实现了切换图标的效果。

我们来运行下看看效果:

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_数据_05

同理,图标填充色我们就把背景颜色那块内容复制一份过来,然后当点击颜色的时候,赋值给​​logoColor​​变量就完成了,这里就不做演示了。

分段选项切换

最后是分段器的切换,我们可以根据​​selectedSegment​​变量作为切换状态值,当​​selectedSegment​​处于不同的值时,我们切换不同的视图。示例:

VStack(spacing: 60) {

Spacer()
ShowLogoView
Spacer()

VStack(spacing: -10) {
SegmentView
if selectedSegment == 0 {
BGColorView
} else if selectedSegment == 1

完成后,我们尝试更改Logo背景颜色、Logo图标、Logo填充色来看看效果。

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_背景颜色_06

功能进阶

完成上述内容后,总觉得好像还差点东西,思来想去总算发现一个问题。

当前我们的颜色和Logo图标都是内置的,没有办法自定义。背景颜色和填充色还好,但是Logo图片不能自定义,就…….不够优雅

接下来,我们来实现自定义Logo图标的方法,最简单的就是本地上传图片

我们设想下通用的交互,当我们点击图标时,它弹出一个弹窗,让我们选择修改的来源。常用的图片来源有2种:相册、拍照,这里我们只完成相册的部分,毕竟应该很少人会直接拍照作为Logo图标。

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_SwiftUI_07

打开Sheet弹窗

我们使用官方提供的Sheet弹窗来完成来源选择交互,示例:

// MARK: - 选择来源弹窗

private var chooseImageSheet: ActionSheet {
let action = ActionSheet(title: Text("选择来源"), buttons: [.default(Text("相册"), action: {

// 打开相册
}), .cancel(Text("取消"), action: {
})])
return

上述代码中,我们构建了一个打开​​Sheet​​​弹窗的视图​​chooseImageSheet​​​,它的类型是​​ActionSheet​​,即触发Sheet弹窗

然后我们完善了Sheet弹窗里的相关内容,标题、操作(相册、取消)。

然后我们需要声明一个​​变量​​​,判断是否打开​​Sheet​​弹窗,示例:

@State var showChooseImageSheet: Bool = false

完成后,我们在​​LogoView​​​中使用​​.actionSheet​​​修饰符实现打开​​Sheet​​弹窗的交互。示例:

// 选择来源

.actionSheet(isPresented: $showChooseImageSheet, content: {chooseImageSheet })

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_数据_08

选择本地图片

我们已经成功调用​​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()
}
}
}

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_自定义_09

上述代码中,创建了一个公开的结构体​​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​​绑定了打开本地图片弹窗的条件,我们把这个触发条件放在我们点击“相册”选项的操作。示例:

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_自定义_10

图标图片替换

上述代码中,我们已经通过调用本地相册的方法,获得了选中的图片,这时我们需要替换当前​​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​​的有无,展示不同的视图。效果如下:

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_SwiftUI_11

项目预览

SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器_背景颜色_12

恭喜你,完成了本章的所有内容!

快来动手试试吧!

如果本专栏对你有帮助,不妨点赞、评论、关注~


举报

相关推荐

0 条评论