IBDesignableの魔法、またはXcodeのInterface Builderの機能を拡張する





XcodeのInterface Builderは、インターフェイス要素の標準レイアウトでの作業に費やす時間を大幅に節約してくれ、時にはプロトタイピングタスクに役立ちます。 バージョン6以降、XcodeはIBDesignable属性でマークされたカスタムビューをレンダリングする機能、およびIBInspectable属性でマークされたクラスのビルダーフィールドに表示する機能を追加しました。



Xcode 7以降、この機能は多かれ少なかれ使用できるようになったため、その機能を確認したいと思いました。



IBDesignable / IBInspectableについては、 こちらこちらをご覧ください



標準ケース



これらすべてのパラメーターをInterface Builderで制御できるように、境界線の色、太さ、半径をカスタマイズできるカスタムボタンを作成しましょう。



@IBDesignable class BorderedButton : UIButton { ///   @IBInspectable var borderWidth: CGFloat { set { layer.borderWidth = newValue } get { return layer.borderWidth } } ///   @IBInspectable var borderColor: UIColor? { set { layer.borderColor = newValue?.CGColor } get { return layer.borderColor?.UIColor } } ///   @IBInspectable var cornerRadius: CGFloat { set { layer.cornerRadius = newValue } get { return layer.cornerRadius } } } extension CGColor { private var UIColor: UIKit.UIColor { return UIKit.UIColor(CGColor: self) } }
      
      









すべてが機能し、ビルダーはパラメーターを変更するときにレンダリングを更新します。











しかし、そのようなパラメーターは、おそらくボタンクラスだけでなく、他のボタンにも含まれます。 UIButton基本クラスの拡張を作成してください。



 extension UIButton { ///   @IBInspectable var cornerRadius: CGFloat { set { layer.cornerRadius = newValue } get { return layer.cornerRadius } } ///   @IBInspectable var borderWidth: CGFloat { set { layer.borderWidth = newValue } get { return layer.borderWidth } } ///   @IBInspectable var borderColor: UIColor? { set { layer.borderColor = newValue?.CGColor } get { return layer.borderColor?.UIColor } } }
      
      





拡張機能に既に登録されているため、カスタムボタンクラスのIBInspectableフィールドを消去しましょう。 その結果、クラスは空のままになります。



 @IBDesignable class BorderedButton : UIButton {}
      
      





カスタムボタンの横に別のボタンを追加しますが、クラスを割り当てません(標準のUIButtonがあります)。







結果からわかるように、Interface Builderは、UIButton基本クラスでもIBInspectableフィールドを入力する機能を保持していますが、IBDesignable属性でマークされていないため、レンダリングしません。



さらに展開する



同様に、UIViewの基本クラスを拡張できます。



 extension UIView { ///   @IBInspectable var cornerRadius: CGFloat { set { layer.cornerRadius = newValue } get { return layer.cornerRadius } } ///   @IBInspectable var borderWidth: CGFloat { set { layer.borderWidth = newValue } get { return layer.borderWidth } } ///   @IBInspectable var borderColor: UIColor? { set { layer.borderColor = newValue?.CGColor } get { return layer.borderColor?.UIColor } } ///   @IBInspectable var shadowOffset: CGSize { set { layer.shadowOffset = newValue } get { return layer.shadowOffset } } ///   @IBInspectable var shadowOpacity: Float { set { layer.shadowOpacity = newValue } get { return layer.shadowOpacity } } ///    @IBInspectable var shadowRadius: CGFloat { set { layer.shadowRadius = newValue } get { return layer.shadowRadius } } ///   @IBInspectable var shadowColor: UIColor? { set { layer.shadowColor = newValue?.CGColor } get { return layer.shadowColor?.UIColor } } ///    @IBInspectable var _clipsToBounds: Bool { set { clipsToBounds = newValue } get { return clipsToBounds } } }
      
      









これで、すべてのビューのレイヤーパラメーターをビルダーで制御できるようになりました。 ライブレンダリングが可能な条件は1つだけです。ビルダーのビューには、IBDesignable属性を持つカスタムクラスが必要です。



カスタムケース



アプリケーションに明るいテーマと暗いテーマがあるとします。 列挙を使用してボタンのスタイルを設定してみましょう。



 ///   enum ButtonStyle: String { ///   case Light = "light" ///   case Dark = "dark" ///  var tintColor: UIColor { switch self { case .Light: return UIColor.blackColor() case .Dark: return UIColor.lightGrayColor() } } ///   var borderColor: UIColor { return tintColor } ///   var backgroundColor: UIColor { return UIColor.clearColor() } ///   var borderWidth: CGFloat { return 1 } ///   var cornerRadius: CGFloat { return 4 } }
      
      





UIButtonクラスに対応する拡張機能を作成します。これにより、スタイルを選択してボタンに適用できます。



 extension UIButton { ///   @IBInspectable var style: String? { set { setupWithStyleNamed(newValue) } get { return nil } } ///       private func setupWithStyleNamed(named: String?){ if let styleName = named, style = ButtonStyle(rawValue: styleName) { setupWithStyle(style) } } ///      func setupWithStyle(style: ButtonStyle){ backgroundColor = style.backgroundColor tintColor = style.tintColor borderColor = style.borderColor borderWidth = style.borderWidth cornerRadius = style.cornerRadius } }
      
      





次に、ビルダーにさらに2つのボタンを追加し、新しいフィールドStyleで、それぞれスタイル「dark」と「light」を規定します。















これで、ビルダーの1つのフィールドでボタンにスタイルを適用し、実際の表示を確認できます。 最初にのみ制限する場合、IBDesignableクラス(本質的に空です)を作成する必要さえありません。 スタイルを追加したり、ビューのクラスに応じて使用する値を動的に選択したりするだけでなく、スタイルをさらに追加することもできます。



まとめ



この記事では、インターフェイス要素のスタイリングの新しい方法を提示しようとしませんでした。 ただし、おそらくこのアプローチは、誰かをこの機能の別のオリジナルアプリケーションにプッシュするでしょう。



ソースはgitaにあります。



All Articles