这里每天分享一个 iOS 的新知识,快来关注我吧
前言
最近开始正式使用 SwiftUI 做项目了,但是发现了一个很大的问题,就是很多在 UIKit 中经常用的 API,在 SwiftUI 中需要很高的版本才能使用。
随便举几个例子,ScrollView
滚动关闭键盘的 keyboardDismissMode
属性,在 UIScrollView 中 iOS 7 就支持了,但在 SwiftUI 中 iOS 16 才支持。再比如,在 UIAlertController
上添加 TextField
,在 UIKit 中 iOS 8 就支持,但在 SwiftUI 上,iOS 16 才支持。
所以现阶段不太可能用纯 SwiftUI 做项目,除非你的项目最低兼容 iOS 15,甚至是 16 以上。话说回来,在一些 API 低版本不支持的情况下,就需要用到一些兼容手段,最近看到了一些聪明的方式分享给大家。
错误的兼容方式
我们假设你的项目最低版本支持 iOS 14,在使用一些 14 上不兼容的 API 时会报错:
可以看到 cyan
这个颜色在 iOS 15 才能使用,有一种办法是增加在这个 VStack
下增加 #available
判断:
scss
var body: some View {
if #available(iOS 16.0, *) {
VStack {
Text("Hello, world!")
.fontWeight(.bold)
.background(Color.red)
.foregroundColor(.blue)
.padding()
.frame(width: 100, height: 100)
Text("Hello, world!")
.fontWeight(.bold)
.background(Color.red)
.padding()
.frame(width: 100, height: 100)
.foregroundColor(.cyan)
}
} else {
VStack {
Text("Hello, world!")
.fontWeight(.bold)
.background(Color.red)
.foregroundColor(.blue)
.padding()
.frame(width: 100, height: 100)
Text("Hello, world!")
.fontWeight(.bold)
.background(Color.red)
.padding()
.frame(width: 100, height: 100)
.foregroundColor(.blue)
}
}
}
这种方案有几个问题,首先为了使用 cyan
,整个 VStack
都要被 if 语句包裹起来,如果这个 VStack
下代码非常多的话,会有很多的重复代码。其次这种方法不利于维护,如果再有一个属性是 iOS 16 才能用的,那么再用 if iOS 16
包裹一次吗?显然不合理。
正确的做法
正确的方法是通过扩展做兼容,我们可以给 Color
扩展出一个新的 newCyan
属性,来兼容这种情况:
swift
extension Color {
static let newCyan: Self = {
if #available(iOS 15.0, *) {
return .cyan
} else {
return .black
}
}()
}
这样的话,再使用的时候直接使用 newCyan
就行了:
scss
Text("Hello, world!")
.foregroundColor(.newCyan)
这样就解决了上边的问题。
其他的例子
使用扩展的兼容方案是个不错的思路,还有一些其他例子:
1、隐藏 List 的分割线 listRowSeparator
方法,在 iOS 15 才能用:
同样使用扩展:
swift
func newHiddenListRowSeparator() -> some View {
if #available(iOS 15.0, *) {
return listRowSeparator(.hidden)
} else {
return self
}
}
hiddenListRowSeparator
改成 newHiddenListRowSeparator
即可。
2、ScrollView 禁止滚动
swift
func newScrollDisabled() -> some View {
if #available(iOS 16.0, *) {
return self.scrollDisabled(true)
} else {
return self
}
}
3、View 的 tint 方法 iOS 15 以上才能用
那就给 View 写个扩展
swift
extension View {
func newTint(_ color: Color?) -> some View {
if #available(iOS 16.0, *) {
return self.tint(color)
} else {
return self.accentColor(color)
}
}
}
总结
使用扩展兼容 API 的方式好处显而易见:
-
解决了重复代码问题
-
每个 API 的兼容判断都是独立的,可维护性强
-
当你升级最低版本时,只需要把版本判断删掉或者直接把方法名改掉即可
这里每天分享一个 iOS 的新知识,快来关注我吧
本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!