在日常的SwiftUI
开发过程中,常常会出现一些“小BUG”让我们措手不及、头顶发凉。这些问题可能是由于我们自己不熟悉SwiftUI
语法导致的,也有是SwiftUI
本身自带的缺陷,毕竟是一个新兴语言。
那么本章就介绍一些SwiftUI
开发的小技巧,帮助我们避避那些让我们头秃的坑。
1、如何在List列表视图去掉分割线LineSeparator?
SwiftUI
中的List
可以说是UIKit中TableView
的进化版本,在UIKit
中我们使用separatorColor
修饰符将分割线的样式改为无。示例:
tableView.separatorColor = .clear
在SwiftUI
中使用的方法类似,SwiftUI
中的List
的底层使用的是UITableView
,我们可以调用AppearanceAPI
来实现去掉分割线样式。示例:
UITableView.appearance().separatorColor = .clear
但是,使用这种方式会导致App
中所有的List
,包含其他页面的的List
也会自动去掉分割线,这是因为UITableView
是List
的底层,我们的修饰符是作用在UITableView上的。
往后我们要在其他页面,比如设置页面,要恢复分割线,我们就需要赋予分割线的样式。示例:
UITableView.appearance().separatorColor = .systemGray4
2、如何在List列表视图隐藏箭头?
在UIKit
中,我们使用accessoryType
修饰符来禁用disclosure
指示器,也就是右侧的箭头。示例:
cell.accessoryType = .none
在SwiftUI
中,非常遗憾的是,Apple
没有提供专门的API
来设置隐藏disclosure
指示器,这会有点麻烦。
我们建立一个List
列表来看看,当我们使用NavigationLink
跳转到DetailView
详情页时,系统就会自动展示右侧的箭头,示例:
那么我们试试自己来实现隐藏disclosure
指示器。
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(1 ... 4, id: \.self) { index in
ZStack(alignment: .leading) {
NavigationLink(
destination: DetailView()) {
}
.opacity(0)
Text("第 \(index)页")
}
}
}.navigationTitle("列表")
}
}
}
上述代码中,我们使用ZStack
层叠视图将整个NavigationLink
的视图包裹起来,然后使用opacity
修饰符把disclosure
指示器隐藏。
看起来不错!
3、如何修改整个视图的背景颜色?
在List
列表中,由于我们使用SwiftUI
自带的列表组件,它会默认给整个视图填充一个背景颜色以凸显列表,这时我们追求页面整体性时,需要给List
视图加一个背景颜色。
在UIKit
中,我们可以直接给视图加背景颜色,示例:
view.backgroundColor = UIColor.colorF6F7FB()
首先,我们要去掉原有的List
列表颜色,示例:
init() {
UITableView.appearance().backgroundColor = .clear
}
然后在业务代码中,我们可以使用ZStack
层叠视图和Color
的方式设置List
的背景颜色,示例:
Color(red: 132.0 / 255.0, green: 161.0 / 255.0, blue: 255.0 / 255.0).edgesIgnoringSafeArea(.all)
不错不错!
4、如何通过网络请求显示一张网络图片?
在常用的设置页面或者我的页面,会使用到用户头像等作为用户登录示例,除了使用第三方网络请求框架外,我们也可以使用SwiftUI
自带的网络图片组件,示例:
AsyncImage(url: URL(string: imageURL))
.aspectRatio(contentMode: .fit)
.frame(minWidth: 120, maxWidth: 120, minHeight: 120, maxHeight: 120)
.cornerRadius(8)
上述代码中,我们只需要定义一个图片的网络地址,就可以使用AsyncImage
组件呈现一张图片出来,并且AsyncImage
和Image
一样,可以使用修饰符修改大小的参数。
5、如何绘制带有边角的图形?
在SwiftUI
开发过程中,我们常常会看到一些带有部分圆角的形状,这又是如何实现的呢?
我们可以通过图片的方式展示,也可以自己根据形状绘制,下面我们尝试使用Shape
形状来实现这个效果。示例:
struct CShape: Shape {
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(
roundedRect: rect,
byRoundingCorners: [.topRight, .bottomLeft],
cornerRadii: CGSize(width: 55, height: 55)
)
return Path(path.cgPath)
}
}
上述代码中,我们绘制了一个形状CShape
结构体,在结构体中我们的定义了一个方法path
,它返回一个Path
路径。
我们使用贝塞尔曲线UIBezierPath
进行绘制,在右上topRight
和左下bottomLeft
绘制曲率。
接下来我们在视图中使用,示例:
struct CShapeView: View {
var body: some View {
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [Color.blue, Color.green]), startPoint: .leading, endPoint: .trailing))
.frame(width: 100, height: 100)
.clipShape(CShape())
}
}
上述代码中,我们绘制了一个矩形Rectangle
,给它填充了一个蓝色过渡到绿色的渐变色,然后设置了大小为100*100
。
最后我们使用clipShape
修饰符切割曲线,切割方式为上面设置好的CShape
。
这样,我们就完成了一个类似叶子效果的带边角的形状。
6、如何绘制虚线边框?
在新版的Xcode
中,我们已经不能直接使用border
修饰符给按钮加边框了,那我们该如何给按钮加边框线呢?
其实很简单,我们可以使用overlay
修饰符在按钮上覆盖一层边框,示例:
Text("文如秋雨")
.font(.title)
.foregroundColor(.blue)
.padding()
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(Color(.systemGray5), lineWidth: 2)
)
上述代码中,我们使用overlay
覆盖了一层圆角矩形RoundedRectangle
,圆角度数为30
,并且使用stroke
修饰符给圆角赋予了一个灰色systemGray5
,和2
的线宽。
这是边框的实现方式,那么虚线边框我们使用的是Capsule
容器。示例:
Text("文如秋雨")
.font(.title)
.foregroundColor(.blue)
.padding()
.overlay(
Capsule(style: .continuous)
.stroke(Color.blue, style: StrokeStyle(lineWidth: 2, dash: [10]))
)
上述代码中,我们覆盖的是Capsule
容器,然后将Capsule
容器的样式指定为StrokeStyle
,StrokeStyle
样式中线宽为2
,线段间距为10
。
如此,我们便实现了绘制一个虚线边框。
7、如何分享文本和图片?
在实际的开发应用中,我们常常会在App
中使用分享操作,将某一段文字或者图片分享出去,这是如何实现的呢?
首先我们先实现分享的方法,示例:
struct ShareSheet: UIViewControllerRepresentable {
var items: [Any]
func makeUIViewController(context: Context) -> UIActivityViewController {
let controller = UIActivityViewController(activityItems: items, applicationActivities: nil)
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
}
}
上述代码中,我们创建了一个ShareSheet
结构体,它遵循UIViewControllerRepresentable
协议。
我们声明了一个items
变量是随机类型,便于后续我们存储不同类型的内容。然后定义了一个方法makeUIViewController
,调用系统的UIActivityViewController
视图方法,分享声明好的items
内容。
接下来,我们来完成视图部分,示例:
struct ShareLinkView: View {
let items = ["https://juejin.cn/user/3897092103223517"]
@State var showingSheet: Bool = false
var body: some View {
HStack {
Image(systemName: "square.and.arrow.up")
Text("分享")
}
.onTapGesture {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
ShareSheet(items: items)
}
}
}
上述代码中,我们声明了一个常量,存储我们的网站地址,然后使用Image
和Text
创建了一个分享的样式,调用sheet
弹窗方法打开弹窗,弹窗的内容为我们声明好的ShareSheet
视图,然后将声明好的内容传入进行分享。效果如下:
8、如何在按钮点击时有震动反馈?
iOS
很突出的一点是它的线性马达
所带来的反馈体验,让我们在点击屏幕某些操作时能够接收到App
提供的反馈信息。
如果我们需要给App
的某些操作加入一些震动反馈,该如何实现?
我们可以使用UINotificationFeedbackGenerator
来实现震动反馈的效果,示例:
struct Haptics {
static func hapticSuccess() {
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.success)
}
static func hapticWarning() {
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.warning)
}
}
上述代码中,我们创建了一个结构体Haptics
,在Haptics
中定义了2
个震动反馈效果,一个时成功反馈,一个是失败反馈。
然后我们在实际业务视图中使用它,示例:
struct HapticsView: View {
var body: some View {
VStack(spacing:40) {
Text("成功时的反馈")
.padding()
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(5)
.onTapGesture {
Haptics.hapticSuccess()
}
Text("失败时的反馈")
.padding()
.foregroundColor(.white)
.background(Color.gray)
.cornerRadius(5)
.onTapGesture {
Haptics.hapticWarning()
}
}
}
}
上述代码中,我们创建了2
个按钮,分别赋予了不同的样式,当我们点击按钮
时,会调用震动反馈的方法,从而实现让用户有点击的效果。
震动反馈常用在长按或者一些警告业务场景中,可以视情况而使用。
小结
好啦!这就是本章的所有内容,是不是有点眼前一亮呢?
你还知道有哪些SwiftUI
小技巧,不妨分享一下。
如果本专栏对你有帮助,不妨点赞、评论、关注~
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。