xib
(childXib
)ファイルがその所有者を介してカスタムUIView
Swiftファイルにリンクされています。
これが私のカスタムUIView
を初期化する方法です。
// init for IBDesignable
override init(frame: CGRect) {
super.init(frame: frame)
let view = loadViewFromNib()
view.frame = bounds
addSubview(view)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addSubview(loadViewFromNib())
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "CommentCellView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
このxib
(childXib
)を別のxib
(parentXib
)に追加すると、次のエラーが発生します。
エラー:IB Designables:MyRootViewのインスタンスのレンダリングに失敗しました:エージェントが例外をスローしました。
ここで、MyRootView
はparentXib
にリンクされているファイルです。
エラー:IB Designables:自動レイアウトステータスの更新に失敗しました:エージェントが「NSInternalInconsistencyException」例外を発生させました:バンドルにNIBをロードできませんでした:「NSBundle(ロード済み)」、名前は「MyIBDesignableCustomViewFilename」
ここで、MyIBDesignableCustomViewFilename
はchildXib
にリンクされているファイルです。
Custom class
からIdentity inspector
のDebug
をクリックしてデバッグすると、その行からは機能しません。
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
すべてのxib
ファイルはCopy Bundle Resources
のBuild Phases
にあります。
何が問題なのか分かりますか?
最初の一歩:
IBDesignableとIBInspectableの概要を説明し、新機能を活用する方法を紹介します。デモを作成する以外に、機能を詳しく説明する方法はありません。そこで、「Rainbow」というカスタムインターフェイスを一緒に構築します。
IBDesignableおよびIBInspectable
IBDesignableとIBInspectableを使用すると、開発者はInterface Builderでリアルタイムにレンダリングするインターフェイス(またはビュー)を作成できます。一般に、この新機能を適用するには、UIViewまたはUIControlをサブクラス化してビジュアルクラスを作成し、Swiftでクラス名の前に@IBDesignableキーワードを付けるだけです。 Objective-Cを使用している場合は、代わりにIB_DESIGNABLEマクロを使用します。 Swiftのサンプルコードは次のとおりです。
@IBDesignable
class Rainbow: UIView {
}
Xcodeの古いバージョンでは、ユーザー定義のランタイム属性を編集して、Interface Builderでオブジェクト(layer.cornerRadiusなど)のプロパティを変更できます。問題は、プロパティの正確な名前を入力する必要があることです。 IBInspectableは一歩前進します。ビジュアルクラスのプロパティの前にIBInspectableを付けると、プロパティはInterface Builderに公開されるため、値を非常に簡単に変更できます。
繰り返しますが、Swiftでアプリを開発している場合は、選択したプロパティの前にキーワード@IBInspectableを付けるだけです。サンプルコードスニペットは次のとおりです。
@IBInspectable var firstColor: UIColor = UIColor.blackColor()
{
// Update your UI when value changes
}
@IBInspectable var firstColor: UIColor = UIColor.blackColor()
{
// Update your UI when value changes
}
Xcodeプロジェクトのビルド
Xcodeで新しいプロジェクトを作成し、テンプレートとしてシングルビューアプリケーションを選択して、RainbowDemoという名前を付けてみましょう。このプロジェクトではプログラミング言語としてSwiftを使用するので、プロジェクトを作成するときに忘れずに選択してください。
終了したら、プロジェクトナビゲータでMain.storyboardを選択し、ViewオブジェクトをオブジェクトライブラリからViewControllerにドラッグします。色を#38334C(または任意の色)に変更し、サイズを600 x 434に設定します。次に、メインビューの中央に配置します。メインビューの色をビューオブジェクトの同じ色に変更することを忘れないでください。ヒント:コードのRGBカラー値を変更する場合は、カラーパレットを開き、[スライダー]タブに切り替えてRGB値を変更します。
混乱しますか?心配ない。プロジェクトのデモを終えると、私が何を意味するのか理解できます。
Xcode 6では、すべてのタイプのiOSデバイスをサポートするために、ビューの自動レイアウト制約を構成する必要があります。自動レイアウトは、Xcodeの最新バージョンでは非常に強力です。単純な制約の場合は、[自動レイアウト]メニューの[問題]オプションをクリックして[欠落している制約を追加]を選択するだけで、Xcodeがビューのレイアウト制約を自動的に構成します。
カスタムビュークラスの作成
ストーリーボードでビューを作成したので、次はカスタムビュークラスを作成します。クラスの作成にはSwiftクラステンプレートを使用します。「Rainbow」という名前を付けます。
Then insert the following code in the class:
import UIKit
class Rainbow: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
}
前述のように、ビジュアルクラスはUIViewのサブクラスです。ライブレンダリングでカスタムクラスを使用するには、上記のように両方の初期化子をオーバーライドする必要があります。次に、アシスタントエディタを選択してビューを分割します。
完了したら、アシスタントエディタでメインストーリーボードを選択して、構築しているものをリアルタイムで確認できるようにします。 IDインスペクターで、ビューのクラス名を「Rainbow」に変更することを忘れないでください。
IBDesignableコントロールの実装
ライブレンダリングのコントロールを有効にする最初の手順は、クラス名の前に@IBDesignableを付けて、カスタムビューをDesignableとして設定することです。
@IBDesignable
class Rainbow: UIView {
...
}
ご覧のとおり、簡単です。しかし、この単純なキーワードを使用すると、開発がはるかに簡単になります。次に、円の色を設定するためのいくつかのプロパティを追加します。次のコード行をRainbowクラスに挿入します。
@IBInspectable var firstColor: UIColor = UIColor(red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
@IBInspectable var secondColor: UIColor = UIColor(red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
@IBInspectable var thirdColor: UIColor = UIColor(red: (238.0/255.0), green: (32.0/255)
ここでは、各プロパティをデフォルトの色で事前定義し、ユーザーが値を変更するたびにビューを再描画するように指示します。最も重要なのは、各プロパティの前に@IBInspectableキーワードを付けることです。ビューの検査可能な属性に移動すると、次のプロパティが視覚的に表示されます。
かっこいいですよね?プロパティをIBInspectableとして指定することにより、カラーピッカーを使用して視覚的に編集できます。
では、画面に円を描くために使用されるRainbowクラスのメインメソッドの実装に移りましょう。次のメソッドをクラスに挿入します。
func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat, strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor, shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {
let arc = CAShapeLayer()
arc.lineWidth = lineWidth
arc.path = path
arc.strokeStart = strokeStart
arc.strokeEnd = strokeEnd
arc.strokeColor = strokeColor.CGColor
arc.fillColor = fillColor.CGColor
arc.shadowColor = UIColor.blackColor().CGColor
arc.shadowRadius = shadowRadius
arc.shadowOpacity = shadowOpacity
arc.shadowOffset = shadowOffsset
layer.addSublayer(arc)
}
コードをクリーンで読みやすくするために、呼び出し元から提供されたパラメーターに従って、完全な円または半円を描画するための一般的なメソッドを作成します。 CAShapeLayerクラスを使用して円または円弧を描くのは非常に簡単です。 StrokeStartプロパティとstrokeEndプロパティを使用して、ストロークの開始と終了を制御できます。 stokeEndの値を0.0から1.0の間で変化させることにより、完全な円または部分的な円を描くことができます。残りのプロパティは、ストロークの色や影の色などを設定するために使用されます。CAShapeLayerで使用可能なすべてのプロパティの詳細については、公式ドキュメントを確認してください。
次に、Rainbowクラスに次のメソッドを挿入します。
override func drawRect(rect: CGRect) {
// Add ARCs
self.addCirle(80, capRadius: 20, color: self.firstColor)
self.addCirle(150, capRadius: 20, color: self.secondColor)
self.addCirle(215, capRadius: 20, color: self.thirdColor)
}
func addCirle(arcRadius: CGFloat, capRadius: CGFloat, color: UIColor) {
let X = CGRectGetMidX(self.bounds)
let Y = CGRectGetMidY(self.bounds)
// Bottom Oval
let pathBottom = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
self.addOval(20.0, path: pathBottom, strokeStart: 0, strokeEnd: 0.5, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
// Middle Cap
let pathMiddle = UIBezierPath(ovalInRect: CGRectMake((X - (capRadius/2)) - (arcRadius/2), (Y - (capRadius/2)), capRadius, capRadius)).CGPath
self.addOval(0.0, path: pathMiddle, strokeStart: 0, strokeEnd: 1.0, strokeColor: color, fillColor: color, shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero)
// Top Oval
let pathTop = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
self.addOval(20.0, path: pathTop, strokeStart: 0.5, strokeEnd: 1.0, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
}
drawRect
メソッドのデフォルトの実装は何もしません。ビューに円を描画するために、メソッドをオーバーライドして独自の描画コードを実装します。 addCircle
メソッドは、arcRadius、capRadius、およびcolorの3つのパラメーターを取ります。 arcRadius
は円の半径であり、capRadius
は丸いキャップの半径です。
AddCircleメソッドは、UIBezierPathを使用して円弧を描画し、次のように機能します。
First it draws a half circle at the bottom
Next it draws a full small circle at the Edge of the arc.
Finally, it draws the other half of the circle
DrawRectメソッドでは、半径と色が異なるaddCircleメソッドを3回呼び出します。この図は、円がどのように描かれるかを示しています。
ヒント:UIBezierPathの詳細が必要な場合は、Appleの公式ドキュメントを確認してください。
IBInspectableプロパティを使用すると、コードに飛び込むことなく、InterfaceBuilderで各円の色を自由に変更できるようになりました。
明らかに、arcRadiusをIBInspectableプロパティとしてさらに公開できます。練習問題として残しておきます。
サンプルコードについては、ここをクリックしてください: https://github.com/appcoda/Rainbow-IBDesignable-Demo
私は同じ問題を抱えていて、なんとかそれを修正することができました。
Swift
let bundle = Bundle(for: MyView.self)
let view = UINib(nibName: "MyView", bundle: bundle).instantiate(withOwner: self) as! MyView
重要なのはバンドルです
以下のような両方のエラーの場合:
error: IB Designables: Failed to render instance of ....
error: IB Designables: Failed to update auto layout status: The agent raised a "NSInternalInconsistencyException" exception: Could not load NIB in bundle ...
問題をどこで解決すべきかを理解するのに役立つ、簡単な自己検証を行うことをお勧めします。