你好!在SwiftUI中,是否可以只对特定的操作系统目标使用修饰符?在SwiftUI中,是否可以只对特定的操作系统目标使用一个修饰符?在下面的代码中,我想只对MacOS目标使用修饰符.listStyle(SidebarListStyle()),因为它不存在于iOS目标。谢谢你的帮助。
import SwiftUI
struct ContentView: View {
@State var selection: Int?
var body: some View {
HStack() {
NavigationView {
List () {
NavigationLink(destination: FirstView(), tag: 0, selection: self.$selection) {
Text("Click Me To Display The First View")
} // End Navigation Link
NavigationLink(destination: SecondView(), tag: 1, selection: self.$selection) {
Text("Click Me To Display The Second View")
} // End Navigation Link
} // End list
.frame(minWidth: 350, maxWidth: 350)
.onAppear {
self.selection = 0
}
} // End NavigationView
.listStyle(SidebarListStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
} // End HStack
} // End some View
} // End ContentView
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
你最好这样做。
import SwiftUI
struct ContentView: View {
@State var selection: Int?
var body: some View {
#if targetEnvironment(macCatalyst)
return theList.listStyle(SidebarListStyle())
#else
return theList.navigationViewStyle(DefaultNavigationViewStyle())
#endif
}
var theList: some View {
HStack() {
NavigationView {
List () {
NavigationLink(destination: FirstView(), tag: 0, selection: self.$selection) {
Text("Click Me To Display The First View")
} // End Navigation Link
NavigationLink(destination: SecondView(), tag: 1, selection: self.$selection) {
Text("Click Me To Display The Second View")
} // End Navigation Link
} // End list
.frame(minWidth: 350, maxWidth: 350)
.onAppear {
self.selection = 0
}
} // End NavigationView
.frame(maxWidth: .infinity, maxHeight: .infinity)
} // End HStack
} // End some View
} // End ContentView
}
你可以创建一个 View
扩展,并像这样使用它。
List {
// ...
}
.ifOS(.macOS) {
$0.listStyle(SidebarListStyle())
}
这就是它的实现方法
enum OperatingSystem {
case macOS
case iOS
case tvOS
case watchOS
#if os(macOS)
static let current = macOS
#elseif os(iOS)
static let current = iOS
#elseif os(tvOS)
static let current = tvOS
#elseif os(watchOS)
static let current = watchOS
#else
#error("Unsupported platform")
#endif
}
extension View {
/**
Conditionally apply modifiers depending on the target operating system.
```
struct ContentView: View {
var body: some View {
Text("Unicorn")
.font(.system(size: 10))
.ifOS(.macOS, .tvOS) {
$0.font(.system(size: 20))
}
}
}
```
*/
@ViewBuilder
func ifOS<Content: View>(
_ operatingSystems: OperatingSystem...,
modifier: @escaping (Self) -> Content
) -> some View {
if operatingSystems.contains(OperatingSystem.current) {
modifier(self)
} else {
self
}
}
}
然而如果你试图使用一种并非适用于所有目标平台的方法,这将无法工作。唯一的方法是使用 #if os(…)
直接使用。
我有一个扩展,可以让你更容易做到这一点。
extension View {
/// Returns a type-erased version of `self`.
func eraseToAnyView() -> AnyView {
AnyView(self)
}
}
extension View {
// The closure unfortunately has to return `AnyView` as `some` cannot yet be used in return values in closures.
/**
Modify the view in a closure. This can be useful when you need to conditionally apply a modifier that is unavailable on certain platforms.
For example, imagine this code needing to run on macOS too where `View#actionSheet()` is not available:
```
struct ContentView: View {
var body: some View {
Text("Unicorn")
.modify {
#if os(iOS)
return $0.actionSheet(…).eraseToAnyView()
#endif
return nil
}
}
}
```
*/
func modify(_ modifier: (Self) -> AnyView?) -> some View {
modifier(self) ?? AnyView(self)
}
}
如果你用的是Swift 5. 3或更高版本,你可以用这个,它稍微好一点。
@ViewBuilder
func modify(_ modifier: (Self) -> AnyView?) -> some View {
if let view = modifier(self) {
view
} else {
self
}
}
谢谢 DoesData 给我的指导.
解决方法是在整个代码周围使用#is os(macOS),而不仅仅是修改器本身。
import SwiftUI
struct ContentView: View {
@State var selection: Int?
var body: some View {
#if os(macOS)
HStack() {
NavigationView {
List () {
NavigationLink(destination: FirstView(), tag: 0, selection: self.$selection) {
Text("Click Me To Display The First View")
} // End Navigation Link
NavigationLink(destination: SecondView(), tag: 1, selection: self.$selection) {
Text("Click Me To Display The Second View")
} // End Navigation Link
} // End list
.frame(minWidth: 350, maxWidth: 350)
.onAppear {
self.selection = 0
}
} // End NavigationView
.listStyle(SidebarListStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
} // End HStack
#elseif os(iOS)
HStack() {
NavigationView {
List () {
NavigationLink(destination: FirstView(), tag: 0, selection: self.$selection) {
Text("Click Me To Display The First View")
} // End Navigation Link
NavigationLink(destination: SecondView(), tag: 1, selection: self.$selection) {
Text("Click Me To Display The Second View")
} // End Navigation Link
} // End list
.frame(minWidth: 350, maxWidth: 350)
.onAppear {
self.selection = 0
}
} // End NavigationView
.frame(maxWidth: .infinity, maxHeight: .infinity)
} // End HStack
#endif
} // End some View
} // End ContentView
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
WorkingDog,我用一个非常简单的代码尝试了你的elegante代码,以改变文本的颜色取决于目标......但文本在两个目标上都保持蓝色,而在MacOS上并没有变红!我想这是一个很好的解决方法。
import SwiftUI
struct ContentView: View {
var body: some View {
#if os(macOS)
return monText.foregroundColor(Color.red)
#elseif os(iOS)
return monText.foregroundColor(Color.blue)
#endif
}
var monText: some View {
Text("Hello, World!")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}