SwiftのCSS:UIViewのサブクラスにスタイルを使用する

記事の元のタイトル:Swift関数を使用した、構成可能でタイプセーフなUIViewスタイリング



素材に慣れる前に、自分からスタイルを抽象化することについて何か付け加えたいと思います。 この方法は、特に活発に変化する製品で、大規模なプロジェクトで作業するときの生活を楽にします。 IL DE BOTEのようなプロジェクトでこれを完全に感じました。そこでは、アプリケーションの視覚コンポーネントの要件が重要でした。



プロジェクトが進行するにつれて、プロジェクトに大幅なUIの変更が加えられました。スタイルの選択のおかげで、私たちは少し血を流しました。 このアプローチでは、標準クラスの拡張機能(UITextField、UILabel、UITextView、UIFont、UIColor)を使用しました。 この記事の著者は、このアプローチを数段階上に上げることに成功したようです-手のひらをこすり、新しいプロジェクトで使用するために急いで行きました。 この翻訳が、開発時間の最適化とプロジェクトの改善に役立つことを願っています。







アプリケーションで使用されるさまざまなプレゼンテーションスタイル(フォント、背景色、角の半径など)を抽象化しない場合、それらに変更を加えると、実際の災害につながります。 あなたは私を信じることができます-私は自分の経験に基づいて判断します。 多くの苦しみを受けて、UIViewのさまざまなインスタンスの共有クラスを作成できるようにするAPIについて考え始めました。



body {background-color: powderblue;} h1 {color: blue;} p {color: red;}
      
      





Web上のスタイルを抽象化するために、CSSがあります。 プレゼンテーションクラスを定義し、同じスタイルを複数のビューとそのすべてのサブクラスに適用できます。 強力なものを作りたいです。



人生を楽しむために必要なもの:





私の最初のアイデアは、UIViewのスタイル設定に必要なすべてのプロパティを格納する構造にスタイルを抽象化することでした。



 struct UIViewStyle { let backgroundColor: UIColor let cornerRadius: CGFloat }
      
      





すぐに気付きました。これらのプロパティはたくさんあります。 また、UILabelの場合、このスタイルをクラスに適用するために、他のプロパティと新しい関数を含む新しいUILabelStyle構造体を作成する必要があります。 それらを書いたり使用したりするのは退屈なように思えました。



さらに、この手法は十分な伸縮性がありません。新しいプロパティをクラスに追加する必要がある場合、各構造に追加する必要があります。 これは、オープン/クローズの原則に違反しています。



この手法の別の問題は、2つのスタイルを自動的にまとめる簡単な方法がないことです。 2つの構造を取得し、それらのプロパティを取得して新しい構造に割り当てる必要がありますが、一方は他方より優先されます。



これは、メタプログラミングを使用して自動的に実行できますが、解決策はかなり複雑です。 難しい決断をするとき、私は立ち止まって自分に問いかけます:「最初に間違いを犯したのではないか?」 ほとんどの場合、この質問に対する答えは肯定的です。



この問題をより根本的に見ることにしました。 スタイルとは何ですか? UIViewのサブクラスを取り、その中の特定のプロパティを変更します。 つまり、UIViewに副作用があります。 そして、それは関数のように見えます!



 typealias UIViewStyle<T: UIView> = (T)-> Void
      
      





スタイルは、UIViewに適用される関数にすぎません。 UILabelでfontSizeを変更する場合は、対応するプロパティを変更するだけです。



 let smallLabelStyle: UIViewStyle<UILabel> = { label in label.font = label.font.withSize(12) }
      
      





その結果、UIViewの各サブクラスを手動で宣言する必要はありません。 この関数は必要な型を受け入れるため、そのプロパティはすべて変更する準備ができています。



単純な関数を使用することの良い面は、あるクラスが別のクラスのプロパティをできるだけ単純に継承することです。単に関数を次々に呼び出すだけです。 すべての変更が適用され、必要に応じて2番目のクラスが最初のクラスをオーバーライドします。



 let smallLabelStyle: UIViewStyle<UILabel> = { label in label.font = label.font.withSize(12) } let lightLabelStyle: UIViewStyle<UILabel> = { label in label.textColor = .lightGray } let captionLabelStyle: UIViewStyle<UILabel> = { label in smallLabelStyle(label) lightLabelStyle(label) }
      
      





APIを使いやすくするために、スタイル関数をラップするUIViewStyle構造体を追加します。



 struct UIViewStyle<T: UIView> { let styling: (T)-> Void }
      
      





宣言されたスタイルは少し異なって見えるようになりましたが、プレーンな関数と同じくらい簡単に使用できます。



 let smallLabelStyle: UIViewStyle<UILabel> = UIViewStyle { label in label.font = label.font.withSize(12) } let lightLabelStyle: UIViewStyle<UILabel> = UIViewStyle { label in label.textColor = .lightGray } let captionLabelStyle: UIViewStyle<UILabel> = UIViewStyle { label in smallLabelStyle.styling(label) lightLabelStyle.styling(label) }
      
      





必要なのは、2つの小さな変更を加えることだけです。



  1. 新しいUIViewStyleオブジェクトを作成し、スタイルクロージャーをパラメーターとしてUIViewStyle.initに渡します。
  2. キャプションスタイルでは、スタイルを関数として呼び出すのではなく、UIViewStyleの現在のインスタンスでスタイリング関数変数を呼び出します。


これで、変数パラメーター(スタイルの配列)を受け取り、それらを順次呼び出して、いくつかのスタイルで構成される新しいUIViewStyleを返す構成関数を宣言できます。



 struct UIViewStyle<T: UIView> { let styling: (T)-> Void static func compose(_ styles: UIViewStyle<T>...)-> UIViewStyle<T> { return UIViewStyle { view in for style in styles { style.styling(view) } } } }
      
      





これは基本的にファクトリーメソッドです。 入力に2つ以上のスタイルがある場合、彼は各ソーススタイルの機能を順番に呼び出す新しいスタイルを作成します。



このおかげで、複合スタイルの宣言は目に優しいものとなり、より有益なものになります。



let captionLabelStyle:UIViewStyle = .compose(smallLabelStyle、lightLabelStyle)



また、UIViewを取得し、それを使用してStylingメソッドを呼び出す適用関数を追加します。



 struct UIViewStyle<T: UIView> { //... func apply(to view: T) { styling(view) } }
      
      





これで、アプリケーションでスタイルを宣言する、クリーンでタイプセーフで構成可能な方法ができました。 そして、これらのスタイルをUIViewControllerまたはUIViewのクラスに適用する手順は非常に簡単です。



 class ViewController: UIViewController { let captionLabel = UILabel() override func viewDidLoad() { super.viewDidLoad() captionLabelStyle.apply(to: captionLabel) } }
      
      






All Articles