在 SwiftUI 中,pos 是否可以只对某个 os 目标使用修饰符?

In SwiftUI, is it possible to use a modifier only for a certain os target?

美好的一天!在 SwiftUI 中,pos 是否可以只对某个 os 目标使用修饰符? 在下面的代码中,我想将修饰符 .listStyle(SidebarListStyle()) 仅用于 MacOS 目标,因为它对于 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()
  }
}

感谢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()
  }
}

你最好这样做:

 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
 }

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

您可以创建一个 View 扩展并像这样使用它:

List {
    // ...
}
.ifOS(.macOS) {
    [=10=].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) {
                    [=11=].font(.system(size: 20))
                }
        }
    }
    ```
    */
    @ViewBuilder
    func ifOS<Content: View>(
        _ operatingSystems: OperatingSystem...,
        modifier: (Self) -> Content
    ) -> some View {
        if operatingSystems.contains(OperatingSystem.current) {
            modifier(self)
        } else {
            self
        }
    }
}

但是,如果您尝试使用并非适用于所有目标平台的方法,这将不起作用。使这项工作的唯一方法是直接使用 #if os(…)

我有一个扩展程序可以更轻松地做到这一点:

extension View {
    /**
    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)
                    [=12=].actionSheet(…)
                    #else
                    [=12=]
                    #endif
                }
        }
    }
    ```
    */
    func modify<T: View>(@ViewBuilder modifier: (Self) -> T) -> T {
        modifier(self)
    }
}

Swift 5.5

从Swift5.5版本开始,可以直接对withing修饰符使用add条件

  } // End NavigationView
    #if os(macOS)
    .listStyle(SidebarListStyle())
    #else
    .navigationViewStyle(DefaultNavigationViewStyle())
    #endif