web-dev-qa-db-ja.com

NSSplitViewと自動レイアウト

NSSplitViewサブビュー内で自動レイアウト制約をどのように使用する必要がありますか?

私のNSSplitViewサブビューには、topPanetableContainerbottomPaneの3つのサブビューがあり、次のように制約を設定します。

_NSDictionary* views = NSDictionaryOfVariableBindings(topPane, tableContainer, bottomPane);

for (NSView* view in [views allValues]) {
    [view setTranslatesAutoresizingMaskIntoConstraints:NO];
}

[myView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[topPane(34)][tableContainer][bottomPane(24)]|"
                                                               options:0 
                                                               metrics:nil 
                                                                 views:views]];

[mySplitView addSubview:myView];
_

そしてこれをコンソールで取得しました:

_Unable to simultaneously satisfy constraints:
(
    "<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]>",
    "<NSLayoutConstraint:0x7fd6c4b30910 V:[CPane:0x7fd6c4b2f870(34)]>",
    "<NSLayoutConstraint:0x7fd6c4b30770 V:|-(0)-[CPane:0x7fd6c4b2f870]   (Names: '|':NSView:0x7fd6c4b22e50 )>",
    "<NSLayoutConstraint:0x7fd6c4b212f0 V:[CPane:0x7fd6c4b2fd10]-(0)-|   (Names: '|':NSView:0x7fd6c4b22e50 )>",
    "<NSLayoutConstraint:0x7fd6c4b2f910 V:[CPane:0x7fd6c4b2f870]-(0)-[NSScrollView:0x7fd6c4b234c0]>",
    "<NSLayoutConstraint:0x7fd6c4b21290 V:[CPane:0x7fd6c4b2fd10(24)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]>
_

<NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>が原因だと思いますが、NSSplitViewが設定しているため、自動サイズ変更マスクをリセットできません。

分割ビュー内で自動レイアウトを使用する最良の方法は何ですか?そして、NSSplitViewDelegateなしで自動レイアウトを使用して分割ビューサブビューの最小/最大サイズを処理する方法はありますか?

22
Dmitry

このエラーは、ウィンドウにtoolbarがあり、このデリゲートメソッドのいずれかによって分割ビューを制御している場合に表示されることがわかりました。

splitView:constrainMinCoordinate:ofSubviewAt:   
splitView:constrainMaxCoordinate:ofSubviewAt:
splitView:shouldAdjustSizeOfSubview:

WindowDidLoadのウィンドウにツールバーをアタッチすることで解決策が見つかりました。

7
Al Zonke

NSSplitViewは最初から奇妙なものであり、すぐになくなることは私を驚かせません。 NSSplitViewをAutoLayoutで1か月間動作させようとし、絶望的な攻撃から別の攻撃に沈んだ後、私はついに諦めました。

私の解決策はAutoLayoutでNSSplitViewを使用しないです。したがって、AutolayoutなしのNSSplitViewまたはNSSplitViewなしのAutolayoutのいずれか:これは思ったほど複雑ではありません。サブビューを並べてレイアウトし、NSLayoutConstraintsIBOutletsとして追加するだけです。これらの制約の定数は、コード内のコントローラーから設定および変更できます。このアプローチでは、原点(ウィンドウからスライドさせるための負のオフセット)、幅、および他のサブビューとの関係を設定できます。さらに、ビューのアニメーターを使用して制約をアニメーション化するのは非常に簡単です(これまでに試みたことがありますanimateNSSplitView?)

足りないのは仕切りのマウスドラッグだけですが、これはカスタムの「SplitView」でmouseEventsを追跡する数行で実装できます。

Apple(残念ながら垂直のみ)からの自動レイアウト「splitview」の例があり、最近githubで少なくとも1つの新しいプロジェクトを見ました。私にとっては、開始する方が簡単だと思いました。非常に普遍的なものを作成しようとするのではなく、アプリの特定のニーズに合わせたカスタムソリューションを使用します(したがって、複雑すぎて処理できません)。

編集:これで、個別のペン先からサブビューをロードするカスタムsplitViewが完成しました。制約の問題や自動レイアウトの警告はありません。 NSSplitViewで動作させようとした1か月と比較すると、制約に基づいて、簡単にアニメートできる、たった1晩で作成されたカスタムsplitViewが動作するようになりました。私は絶対にこのルートを取ることをお勧めします!

4
auco

将来これに遭遇し、制約ベースのNSSplitView置換へのジャンプスタートを探している人のために、私はここにNSSplitViewの機能の一部を使用して再作成しようとする小さなプロジェクトを書きました自動レイアウト:

https://github.com/jwilling/JWSplitView

ややバグがありますが、このルートに行きたい人にとっては便利なリファレンスになるでしょう。

4
sudo rm -rf

10.8はその問題を修正しました。リリースノートを参照してください。

これが10.7(カスタム分割ビュー)の私の解決策です: https://github.com/benuri/HASplitView.git

3
Yoav

translatesAutoresizingMaskIntoConstraintsをまったく無効にしたくありません。システムビューの制約を台無しにしないでください。 NSSplitViewは、個々のビュー自体のサイズ設定を処理します。基本的に、コントロールを取り除こうとしています。言うまでもなく、あなたはスプリッターを説明するのを忘れていました。

スプリットビューで最小または最大(または一定)の幅/高さを設定する正しい方法は、ビューでそれらを個別に設定することです。特に、コードでこれを行う場合は、constraintWithVisualFormatを2回別々に呼び出す必要があります。そうしないと、ビジュアルフォーマット言語によってビュー間に制約が作成されるためです。

これらすべてをIBで問題なく実行できます。分割ビューで各ビューの優先度を設定することもできます。これにより、サイズ変更を均等に分散するのではなく、ウィンドウのサイズ変更時にどちらかのビューのサイズが変更されます。

1
David Beck

自動レイアウトで警告を取り除くのに少し時間がかかりましたが、IB(いくつかのスプリットビューとサブビュー)で処理されました。

私のレイアウトは次のようになります。

RootView
| --1番目のNSSplitView(3つの垂直サブビュー)
| ---- UIView(左)
| ----2番目のNSSplitView(中央と2つの水平サブビュー)
| --- UIView(上)
| ---番目のNSSplitView(下と3つの垂直サブビュー)
| --- UIView(左)
| --- UIView(中央)
| --- UIView(右)
| ---- UIView(右)

私の問題は、すべてのサブビューに19の警告があったが、レイアウトが正常に見え、本来の動作をしたことでした。しばらくすると、警告の原因が見つかりました。最初のスプリットビューの外側のビューの制約です。

両方のビュー(左と右)には「width> = 200」の幅の制約があり、中央のビュー(2番目の分割ビュー)には制約がありませんでした(サブビューによって処理される最小幅と最大幅のため)。

警告は、計算された最小幅がレイアウトよりも小さいため、自動レイアウトがIB-UI-Layoutを縮小したいが、IBでは縮小したくないことを示していました。

最初のスプリットビューの両方の外側のサブビューに固定制約「width = 200」を追加し、「ビルド時に削除」をチェックしました。

これで、私のレイアウトには警告がなくなり、すべてが正常に機能します。

私の結論

自動レイアウトと分割ビューの問題は、自動レイアウトがサブビューの幅の制約を処理できないことだと思います。スプリットビューを使用する理由は、ビューの動的な幅が必要であり、縮小と拡大の両方向にそれが必要だからです。

したがって、幅<= xxx && width> = xxxはありません。自動レイアウトはそのうちの1つしか処理できず、IBで警告が表示されます。この問題は、実行前に削除されるIBの一時的な制約で修正できます。

私が書いたものが理にかなっていることを願っていますが、私のプロジェクトではうまくいきました。

PS:私はこのスレッドを見つけた今日まで解決策を見つけることができませんでした..だからあなたの投稿が私にインスピレーションを与えたと思います:-)

0
Rikco

私が反対するのは嫌いですが、Aucoの答えは最高に投票されるべきではありません。十分な量の作業で問題を解決するのに決して役立ちません。私の意見では、NSSplitViewは、ドキュメントを十分に読んでいない人にとってのみ問題でした。

ここで説明する問題の実際の解決策は非常に簡単です。自動レイアウトにより、NSSplitViewに新しい「HoldingPrioritiesAPI」が導入されました。そして、ドキュメントが言うように:サブビューの保持優先度に低い値を設定すると、彼はより早く幅を取る可能性が高くなります。これらはすべてIBで設定でき、プログラムで絶望することなく設定できます。必要な作業量:約20秒。

0
Jacque

私はこのクラスを回避策として使用しました。完璧ではありませんが(サブビューが少し途切れます)、ブロックが解除されました。このクラスを、各分割ビューペイン内のカスタムクラスとして使用します。

@interface FBSplitPaneView : NSView

@end

@implementation FBSplitPaneView

- (void)setFrame:(NSRect)frame
{
  for (NSView *subview in self.subviews) {
    subview.frame = self.bounds;
  }
  [super setFrame:frame];
}

@end
0
Mathieu Tozer

すべてをnibファイルでロードし、その後setTranslatesAutoresizingMaskIntoConstraints:NOします。

したがって、最初に[mySplitView addSubview:myView];でビューを追加し、その後、自動サイズ変更マスクの制約への変換を無効にしてから、制約をmyViewに追加する必要があります。

編集:

MyViewを誤解しているようです。スプリットビューではなく、サブビューに制約を追加する必要があります。

[topPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topPane(34)]" options:0 metrics:nil views:views]];

[bottomPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[bottomPane(24)]" options:0 metrics:nil views:views]];

NSSplitViewのサブビューはすでに自動サイズ変更されているため、エッジ制約( "V:| [topPane(34)]"の "|")を追加する必要はありません。

これはこれにつながります。 topPane制約の場合:

Screenshout

注:サブビューのコンテンツは無視してください。これらは単なるプレースホルダーです。

0
Stephan