我有一个自定义修饰符,可以用图像视图替换导航栏标题,在iOS 14中,使用.toolbar修饰符非常简单,但是在iOS 13中,它需要做更多的工作,但是有可能。
当我想在条件修饰符中同时使用两个解决方案时,问题就来了,以下代码重现了该问题,它在iOS 14上运行时可以运行,但在iOS 13上却没有任何结果,但是如果“ #available”条件是从修改器中删除,仅保留iOS 13代码,它可以正常工作。将iOS 14包装在AnyView中也无济于事:
extension View {
@ViewBuilder
func configuresIcon() -> some View {
if #available(iOS 14.0, *){
self.modifier(NavigationConfigurationView14Modifier())
} else {
self.modifier(NavigationConfigurationViewModifier(configure: { nv in
nv.topItem?.titleView = UIImageView(image: UIImage(named: IMAGE_NAME_HERE))
}))
}
}
}
struct NavigationConfigurationViewModifier: ViewModifier {
let configure: (UINavigationBar) -> ()
func body(content: Content) -> some View {
content.background(NavigationControllerLayout(configure: {
configure($0.navigationBar)
}))
}
}
@available(iOS 14.0, *)
struct NavigationConfigurationView14Modifier: ViewModifier {
func body(content: Content) -> some View {
content
.toolbar {
ToolbarItem(placement: .principal) {
Image(IMAGE_NAME_HERE)
}
}
}
}
struct NavigationControllerLayout: UIViewControllerRepresentable {
var configure: (UINavigationController) -> () = { _ in }
func makeUIViewController(
context: UIViewControllerRepresentableContext<NavigationControllerLayout>
) -> UIViewController {
UIViewController()
}
func updateUIViewController(
_ uiViewController: UIViewController,
context: UIViewControllerRepresentableContext<NavigationControllerLayout>
) {
if let navigationContoller = uiViewController.navigationController {
configure(navigationContoller)
}
}
}
答案 0 :(得分:0)
尝试将内容包装在Group
中(未经测试-唯一的想法)
extension View {
@ViewBuilder
func configuresIcon() -> some View {
Group {
if #available(iOS 14.0, *){
self.modifier(NavigationConfigurationView14Modifier())
} else {
self.modifier(NavigationConfigurationViewModifier(configure: { nv in
nv.topItem?.titleView = UIImageView(image: UIImage(named: IMAGE_NAME_HERE))
}))
}
}
}
}
答案 1 :(得分:0)
如果我们在运行时而不是在编译时检查OS版本,也许会起作用(因为buildlimitedavailability(_:)
本身就是available only since iOS 14)。
extension View {
func erase() -> AnyView {
return AnyView(self)
}
func applyIf<VM1: ViewModifier, VM2: ViewModifier>(_ condition: @autoclosure () -> Bool, ApplyIfTrue: VM1, ApplyIfFalse: VM2
) -> AnyView {
if condition() {
return self.modifier(ApplyIfTrue).erase()
} else {
return self.modifier(ApplyIfFalse).erase()
}
}
@ViewBuilder func configuresIcon() -> some View {
self.applyIf(NSProcessInfo().isOperatingSystemAtLeastVersion(NSOperatingSystemVersion(majorVersion: 14, minorVersion: 0, patchVersion: 0)),
ApplyIfTrue: NavigationConfigurationView14Modifier(),
ApplyIfFalse: modifier(NavigationConfigurationViewModifier(configure: { nv in
nv.topItem?.titleView = UIImageView(image: UIImage(named: IMAGE_NAME_HERE))
})))
}
}
如果您确实需要#available
选项,可以尝试以下几种方法。 1)可能是因为扩展点不合适,所以请尝试将其移出View
的扩展名。 2)将逻辑从修饰符移到主体。
例如下面的代码可以正常工作。
@available(macOS 10.15, iOS 13.0, *)
struct ContentView: View {
var body: some View {
ScrollView {
if #available(macOS 11.0, iOS 14.0, *) {
LazyVStack {
ForEach(1...1000, id: \.self) { value in
Text("Row \(value)")
}
}
} else {
VStack {
ForEach(1...1000, id: \.self) { value in
Text("Row \(value)")
}
}
}
}
}
}