坂本  篤司

坂本 篤司

1653552000

SwiftUIの16の便利な拡張機能

WWDC 2022とおそらくバージョン4.0のSwiftUIに近づくにつれ、私がこれまでずっと使ってきたフレームワークは幸運だったので、何度も使用している拡張機能の小さなコレクションを公開するかもしれないと思いました。 。これらのいくつかが次のリリースに組み込まれることを願っています。

1.非表示

これは、通常は表示できない可能性のあるビューを表示または非表示にできるビュー修飾子です。ビュー修飾子は、メモリにコミットするのに適した非常に便利なパターンであることに言及する価値があります。

struct Show: ViewModifier {
    let isVisible: Bool

    @ViewBuilder
    func body(content: Content) -> some View {
        if isVisible {
            content
        } else {
            content.hidden()
        }
    }
}

これは、ビューの修飾子として単純に使用します。条件変数は単純にブール値です。

.modifier(Show(isVisible: condition))

これはうまく機能しますが、お気づきのように、はスペースを解放しview、再描画を強制します。そのため、パフォーマンスが低下します。または、いつでもopacityタブを使用して同様の効果を得ることができます。実行速度は速くなりますが、使用したスペースが解放されることはありません。

2.ブランチ

私が出会ったこの修飾子は、属性の包含/除外を制御するための完璧なソリューションです。

extension View {
  @ViewBuilder
  func `if`<Transform: View>(_ condition: Bool, transform: (Self) ->  Transform) -> some View {
    if condition { transform(self) }
    else { self }
  }
}

このように使用するコードは、この例では色付きの変数が含まれています。

.if(colored) { view in
  view.background(Color.blue)
}

3.印刷

SwiftUIを初めて使用する場合、最初に気付くのはですprint。それはデバッグ技術の恐竜かもしれませんが、彼らはまだクラスでそれを教えており、SwiftUIビューでそれを使用できないことに気付くのは苦痛です。したがって、このコードスニペットは非常に貴重です。

extension View {
    func Print(_ vars: Any...) -> some View {
        for v in vars { print(v) }
        return EmptyView()
    }
}

これにより、コードでこのようなステートメントを使用できます。

self.Print("Inside ForEach", varOne, varTwo ...)

4.遅延

これはiOS15で変更されたばかりであり、SwiftUI自体ではありませんが、コード内で実行していることは間違いありません。

extension Task where Success == Never, Failure == Never {
  static func sleep(seconds: Double) async throws {
  let duration = UInt64(seconds * 1000_000_000)
  try await sleep(nanoseconds: duration)
  }
}

もちろん、遅延後に実行するコードTaskは、遅延自体を作成するコードに従う必要があります。

Task { try! await Task.sleep(seconds: 0.5) }

5. PassThruSubjects

CombineSwiftUIを使い始めたときPassThroughSubjects、古いものと新しいものをリンクする非常に便利な方法を見つけました。アプリ内購入での使用についての記事を書きましたが、完璧ではなく、送信するときに何度も起動することがよくあります。このコードは、その問題を見つけるのに役立ちます。

let changeColor = PassthroughSubject<Int,Never>()

使用するコードは次のようになります。

.onReceive(signalButton
  .eraseToAnyPublisher()
  .throttle(for: .milliseconds(10), scheduler: RunLoop.main, latest: true))
{ value in
  if value == 2 {
    button2 = true
    levelColor = Color.red
  }
}

ルーチンではcalling、この場合、同じSwiftUIコードで複数のブランチをトリガーできるように、ここでの番号を使用して1つのサブジェクトに名前を付けました。

changeColor.send(3)

6.サブスクリプション

コードを開始するもう1つの方法は、SwiftUIではありませんが、SwiftUIコード内で繰り返し使用した非常に貴重な要素です。次のコードを使用して設定します。

let cameraGesture = PassthroughSubject<cameraActions,Never>()
var cameraSubscription:AnyCancellable? = nil

次に、次のように2つのcombine宣言が使用されます。

cameraSubscription = cameraGesture
  .eraseToAnyPublisher()
  .throttle(for: .milliseconds(10), scheduler: RunLoop.main, latest: true)
   .sink(receiveValue: { value in   
  // do something with the value                 
})

combine以前と同じようにメッセージを送信します。

cameraGesture.send(._1orbitTurntable)

7.タイマー

Apublisherはタイマーを作成するための優れた方法です。私が考えるほとんどすべてのプロジェクトでそれを使用していることがわかります。

let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

これがコードです。

:変数に時間値があり_ unusedます。これは、とは異なり、send大量ではなく1つのメッセージを送信するため、より確実に機能します。

.onReceive(timer) { _ in
  // do something
}

8.座標/サイズ

これがどういう意味だったのかよく思い出せないので、ここに例を示します。また、返されるサイズは親であり、使用する子ではないため、少し注意が必要です。

struct returnSize: View {
  var body: some View {
  GeometryReader { geometry in
    Color.clear
      .onAppear(perform: {
        print("geo \(geometry.size)")
      })
    }
  }
}

したがって、通常は背景ビューとして使用します。このコマンドを使用してビューのサイズを返す方法は次のとおりです。

.background(returnSize())

9.属性文字列

StackOverflowで見つけた非常に便利な拡張機能。iOS15のTextオブジェクトの属性に適用されます。

extension Text {
  init(_ string: String, configure: ((inout AttributedString) -> Void)) {
   var attributedString = AttributedString(string) /// create an `AttributedString`
   configure(&attributedString) 
   self.init(attributedString) 
  }
}

上記のスニペットは次のように使用できます。

Text("GAME OVER") { $0.kern = CGFloat(2) }

これらの種類のパラメーターを使用して、この記事で詳細に追加できます。

10. AnyView

次は、一致しないビューについて不平を言うそのSwiftUIメッセージの修正です。私は通常、を使用するAnyViewことをお勧めしませんが、他の解決策がないように見える場合もあります。

extension View {
    func eraseToAnyView() -> AnyView {
        AnyView(self)
    }
}

テキストアイテムまたは画像を返したい拡張機能の例を次に示します。

struct returnDifferentViews: View {
@State var means:Bool
var body: some View {
  if means {
    return Image("1528")
     .eraseToAnyView()
  } else {
    return Text("1528")
      .eraseToAnyView()
  }
 }
}

11.下付き文字

この拡張機能を使用すると、文字列に添え字を付けることができます。古くからある規格を採用しています

extension String {
  var length: Int {
  return count
}
subscript (i: Int) -> String {
  return self[i ..< i + 1]
}
func substring(fromIndex: Int) -> String {
  return self[min(fromIndex, length) ..< length]
}
func substring(toIndex: Int) -> String {
  return self[0 ..< max(0, toIndex)]
}
subscript (r: Range<Int>) -> String {
  let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
upper: min(length, max(0, r.upperBound))))
  let start = index(startIndex, offsetBy: range.lowerBound)
  let end = index(start, offsetBy: range.upperBound - range.lowerBound)
  return String(self[start ..< end])
  }
}

他の言語と同じようにコードを使用できます。

let word = "Start"
  for i in 0..<word.length {
    print(word[i])
}

12.揺れを検出します

このGoogleコードは、私がいつも調べているものです。誰がこのシーケンスを覚えていますか?

extension NSNotification.Name {
  public static let deviceDidShakeNotification =   NSNotification.Name("MyDeviceDidShakeNotification")
}
extension UIWindow {
  open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
  super.motionEnded(motion, with: event)
  NotificationCenter.default.post(name: .deviceDidShakeNotification, object: event)
}
}
extension View {
  func onShake(perform action: @escaping () -> Void) -> some View {
  self.modifier(ShakeDetector(onShake: action))
  }
}
struct ShakeDetector: ViewModifier {
  let onShake: () -> Void
func body(content: Content) -> some View {
  content
    .onAppear() // this has to be here because of a SwiftUI bug
    .onReceive(NotificationCenter.default.publisher(for:
    .deviceDidShakeNotification)) { _ in
    onShake()
    }
  }
}

次のような拡張機能を作成できます。

.onShake {
  print("stop it shaking")
}

13.ビューのスナップショット

この宝石はHWSのウェブサイトから来ています。それは迅速なすべてのものの優れた情報源です。

extension View {
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self)
        let view = controller.view

        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear

        let renderer = UIGraphicsImageRenderer(size: targetSize)

        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}

次のように使用できます。

let image = textView.snapshot().ignoresSafeArea

14.画像の保存/読み込み

これがAppleDevelopersポータルで見つかった場合。重宝します。

extension URL {
  func loadImage(_ image: inout UIImage) {
  if let loaded = UIImage(contentsOfFile: self.path) {
    image = loaded
  }
}
func saveImage(_ image: UIImage) {
  if let data = image.jpegData(compressionQuality: 1.0) {
    try? data.write(to: self)
    }
  }
}
https://developer.apple.com/forums/thread/661144

拡張機能では、次のようなコードを使用できます。

@State private var image = UIImage(systemName: "xmark")!
private var url: URL {  let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)  return paths[0].appendingPathComponent("image.jpg")}var body: some View { 
Image(uiImage: image)  
  .onAppear {   url.load(&image)  }  
  .onTapGesture {   url.save(image)  }
}

15.フォントの一覧表示

ほぼ終わりです。この次のものは便利です。

let fontFamilyNames = UIFont.familyNames
for familyName in fontFamilyNames {
  print("Font Family Name = [\(familyName)]")
  let names = UIFont.fontNames(forFamilyName: familyName)
  print("Font Names = [\(names)]")
}

SwiftUIコードを使用すると、次のようなフォントを見つけることができます。

struct Fonts {
  static func avenirNextCondensedBold (size: CGFloat) -> Font {
  return Font.custom("AvenirNextCondensed-Bold", size: size)
}

このコンストラクトを呼び出して、コードを使用します。

.font(Fonts.avenirNextCondensedBold(size: 12))

16.三項演算子

この最後の拡張機能はSwiftUIの多くの領域で使用できますが、構文を思い出せません。

ここで、三項演算子は評価conditionし、

  • の場合、conditionが実行されます。trueexpression1
  • の場合、conditionが実行されます。falseexpression2

三項演算子は、3つのオペランド(、、、conditionおよびexpression1)を取りますexpression2。したがって、名前の三項演算子。

flipColor = flipColor == .blue ? .green : .blue

したがって、の場合flipColorblue戻りgreen、の場合flipColorgreen戻りblueます。

これらすべてが私をこのリストの最後に導きます。ここで便利なスニペットを見つけていただければ幸いです。

読んでくれてありがとう!

ソース:https ://betterprogramming.pub/16-useful-extensions-for-swiftui-88aae6ff8909

#swiftui #extensions

What is GEEK

Buddha Community

SwiftUIの16の便利な拡張機能
坂本  篤司

坂本 篤司

1653552000

SwiftUIの16の便利な拡張機能

WWDC 2022とおそらくバージョン4.0のSwiftUIに近づくにつれ、私がこれまでずっと使ってきたフレームワークは幸運だったので、何度も使用している拡張機能の小さなコレクションを公開するかもしれないと思いました。 。これらのいくつかが次のリリースに組み込まれることを願っています。

1.非表示

これは、通常は表示できない可能性のあるビューを表示または非表示にできるビュー修飾子です。ビュー修飾子は、メモリにコミットするのに適した非常に便利なパターンであることに言及する価値があります。

struct Show: ViewModifier {
    let isVisible: Bool

    @ViewBuilder
    func body(content: Content) -> some View {
        if isVisible {
            content
        } else {
            content.hidden()
        }
    }
}

これは、ビューの修飾子として単純に使用します。条件変数は単純にブール値です。

.modifier(Show(isVisible: condition))

これはうまく機能しますが、お気づきのように、はスペースを解放しview、再描画を強制します。そのため、パフォーマンスが低下します。または、いつでもopacityタブを使用して同様の効果を得ることができます。実行速度は速くなりますが、使用したスペースが解放されることはありません。

2.ブランチ

私が出会ったこの修飾子は、属性の包含/除外を制御するための完璧なソリューションです。

extension View {
  @ViewBuilder
  func `if`<Transform: View>(_ condition: Bool, transform: (Self) ->  Transform) -> some View {
    if condition { transform(self) }
    else { self }
  }
}

このように使用するコードは、この例では色付きの変数が含まれています。

.if(colored) { view in
  view.background(Color.blue)
}

3.印刷

SwiftUIを初めて使用する場合、最初に気付くのはですprint。それはデバッグ技術の恐竜かもしれませんが、彼らはまだクラスでそれを教えており、SwiftUIビューでそれを使用できないことに気付くのは苦痛です。したがって、このコードスニペットは非常に貴重です。

extension View {
    func Print(_ vars: Any...) -> some View {
        for v in vars { print(v) }
        return EmptyView()
    }
}

これにより、コードでこのようなステートメントを使用できます。

self.Print("Inside ForEach", varOne, varTwo ...)

4.遅延

これはiOS15で変更されたばかりであり、SwiftUI自体ではありませんが、コード内で実行していることは間違いありません。

extension Task where Success == Never, Failure == Never {
  static func sleep(seconds: Double) async throws {
  let duration = UInt64(seconds * 1000_000_000)
  try await sleep(nanoseconds: duration)
  }
}

もちろん、遅延後に実行するコードTaskは、遅延自体を作成するコードに従う必要があります。

Task { try! await Task.sleep(seconds: 0.5) }

5. PassThruSubjects

CombineSwiftUIを使い始めたときPassThroughSubjects、古いものと新しいものをリンクする非常に便利な方法を見つけました。アプリ内購入での使用についての記事を書きましたが、完璧ではなく、送信するときに何度も起動することがよくあります。このコードは、その問題を見つけるのに役立ちます。

let changeColor = PassthroughSubject<Int,Never>()

使用するコードは次のようになります。

.onReceive(signalButton
  .eraseToAnyPublisher()
  .throttle(for: .milliseconds(10), scheduler: RunLoop.main, latest: true))
{ value in
  if value == 2 {
    button2 = true
    levelColor = Color.red
  }
}

ルーチンではcalling、この場合、同じSwiftUIコードで複数のブランチをトリガーできるように、ここでの番号を使用して1つのサブジェクトに名前を付けました。

changeColor.send(3)

6.サブスクリプション

コードを開始するもう1つの方法は、SwiftUIではありませんが、SwiftUIコード内で繰り返し使用した非常に貴重な要素です。次のコードを使用して設定します。

let cameraGesture = PassthroughSubject<cameraActions,Never>()
var cameraSubscription:AnyCancellable? = nil

次に、次のように2つのcombine宣言が使用されます。

cameraSubscription = cameraGesture
  .eraseToAnyPublisher()
  .throttle(for: .milliseconds(10), scheduler: RunLoop.main, latest: true)
   .sink(receiveValue: { value in   
  // do something with the value                 
})

combine以前と同じようにメッセージを送信します。

cameraGesture.send(._1orbitTurntable)

7.タイマー

Apublisherはタイマーを作成するための優れた方法です。私が考えるほとんどすべてのプロジェクトでそれを使用していることがわかります。

let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

これがコードです。

:変数に時間値があり_ unusedます。これは、とは異なり、send大量ではなく1つのメッセージを送信するため、より確実に機能します。

.onReceive(timer) { _ in
  // do something
}

8.座標/サイズ

これがどういう意味だったのかよく思い出せないので、ここに例を示します。また、返されるサイズは親であり、使用する子ではないため、少し注意が必要です。

struct returnSize: View {
  var body: some View {
  GeometryReader { geometry in
    Color.clear
      .onAppear(perform: {
        print("geo \(geometry.size)")
      })
    }
  }
}

したがって、通常は背景ビューとして使用します。このコマンドを使用してビューのサイズを返す方法は次のとおりです。

.background(returnSize())

9.属性文字列

StackOverflowで見つけた非常に便利な拡張機能。iOS15のTextオブジェクトの属性に適用されます。

extension Text {
  init(_ string: String, configure: ((inout AttributedString) -> Void)) {
   var attributedString = AttributedString(string) /// create an `AttributedString`
   configure(&attributedString) 
   self.init(attributedString) 
  }
}

上記のスニペットは次のように使用できます。

Text("GAME OVER") { $0.kern = CGFloat(2) }

これらの種類のパラメーターを使用して、この記事で詳細に追加できます。

10. AnyView

次は、一致しないビューについて不平を言うそのSwiftUIメッセージの修正です。私は通常、を使用するAnyViewことをお勧めしませんが、他の解決策がないように見える場合もあります。

extension View {
    func eraseToAnyView() -> AnyView {
        AnyView(self)
    }
}

テキストアイテムまたは画像を返したい拡張機能の例を次に示します。

struct returnDifferentViews: View {
@State var means:Bool
var body: some View {
  if means {
    return Image("1528")
     .eraseToAnyView()
  } else {
    return Text("1528")
      .eraseToAnyView()
  }
 }
}

11.下付き文字

この拡張機能を使用すると、文字列に添え字を付けることができます。古くからある規格を採用しています

extension String {
  var length: Int {
  return count
}
subscript (i: Int) -> String {
  return self[i ..< i + 1]
}
func substring(fromIndex: Int) -> String {
  return self[min(fromIndex, length) ..< length]
}
func substring(toIndex: Int) -> String {
  return self[0 ..< max(0, toIndex)]
}
subscript (r: Range<Int>) -> String {
  let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
upper: min(length, max(0, r.upperBound))))
  let start = index(startIndex, offsetBy: range.lowerBound)
  let end = index(start, offsetBy: range.upperBound - range.lowerBound)
  return String(self[start ..< end])
  }
}

他の言語と同じようにコードを使用できます。

let word = "Start"
  for i in 0..<word.length {
    print(word[i])
}

12.揺れを検出します

このGoogleコードは、私がいつも調べているものです。誰がこのシーケンスを覚えていますか?

extension NSNotification.Name {
  public static let deviceDidShakeNotification =   NSNotification.Name("MyDeviceDidShakeNotification")
}
extension UIWindow {
  open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
  super.motionEnded(motion, with: event)
  NotificationCenter.default.post(name: .deviceDidShakeNotification, object: event)
}
}
extension View {
  func onShake(perform action: @escaping () -> Void) -> some View {
  self.modifier(ShakeDetector(onShake: action))
  }
}
struct ShakeDetector: ViewModifier {
  let onShake: () -> Void
func body(content: Content) -> some View {
  content
    .onAppear() // this has to be here because of a SwiftUI bug
    .onReceive(NotificationCenter.default.publisher(for:
    .deviceDidShakeNotification)) { _ in
    onShake()
    }
  }
}

次のような拡張機能を作成できます。

.onShake {
  print("stop it shaking")
}

13.ビューのスナップショット

この宝石はHWSのウェブサイトから来ています。それは迅速なすべてのものの優れた情報源です。

extension View {
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self)
        let view = controller.view

        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear

        let renderer = UIGraphicsImageRenderer(size: targetSize)

        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}

次のように使用できます。

let image = textView.snapshot().ignoresSafeArea

14.画像の保存/読み込み

これがAppleDevelopersポータルで見つかった場合。重宝します。

extension URL {
  func loadImage(_ image: inout UIImage) {
  if let loaded = UIImage(contentsOfFile: self.path) {
    image = loaded
  }
}
func saveImage(_ image: UIImage) {
  if let data = image.jpegData(compressionQuality: 1.0) {
    try? data.write(to: self)
    }
  }
}
https://developer.apple.com/forums/thread/661144

拡張機能では、次のようなコードを使用できます。

@State private var image = UIImage(systemName: "xmark")!
private var url: URL {  let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)  return paths[0].appendingPathComponent("image.jpg")}var body: some View { 
Image(uiImage: image)  
  .onAppear {   url.load(&image)  }  
  .onTapGesture {   url.save(image)  }
}

15.フォントの一覧表示

ほぼ終わりです。この次のものは便利です。

let fontFamilyNames = UIFont.familyNames
for familyName in fontFamilyNames {
  print("Font Family Name = [\(familyName)]")
  let names = UIFont.fontNames(forFamilyName: familyName)
  print("Font Names = [\(names)]")
}

SwiftUIコードを使用すると、次のようなフォントを見つけることができます。

struct Fonts {
  static func avenirNextCondensedBold (size: CGFloat) -> Font {
  return Font.custom("AvenirNextCondensed-Bold", size: size)
}

このコンストラクトを呼び出して、コードを使用します。

.font(Fonts.avenirNextCondensedBold(size: 12))

16.三項演算子

この最後の拡張機能はSwiftUIの多くの領域で使用できますが、構文を思い出せません。

ここで、三項演算子は評価conditionし、

  • の場合、conditionが実行されます。trueexpression1
  • の場合、conditionが実行されます。falseexpression2

三項演算子は、3つのオペランド(、、、conditionおよびexpression1)を取りますexpression2。したがって、名前の三項演算子。

flipColor = flipColor == .blue ? .green : .blue

したがって、の場合flipColorblue戻りgreen、の場合flipColorgreen戻りblueます。

これらすべてが私をこのリストの最後に導きます。ここで便利なスニペットを見つけていただければ幸いです。

読んでくれてありがとう!

ソース:https ://betterprogramming.pub/16-useful-extensions-for-swiftui-88aae6ff8909

#swiftui #extensions