OS Xのココア自動レイアウト隠し要素

私は新しい自動レイアウトを使用しようとしています。 a>ライオンではかなりいいと思われるので。しかし、私は物事を行う方法についての良い情報を見つけることができません。例えば:

私は2つのラベルを持っています:

+----------------+
| +------------+ |
| + label 1    | |
| +------------+ |
|                |
| +------------+ |
| | label 2    | |
| +------------+ |
+----------------+

最初のラベルには必ずしもコンテンツが埋め込まれていない場合があります。コンテンツがない場合もあります。私がしたいのは、ラベル1が内容を持つときにラベル2が自動的にラベル2を表示することです。

+----------------+
| +------------+ |
| + label 2    | |
| +------------+ |
|                |
|                |
|                |
|                |
+----------------+

どのような制約を加える必要があるので、autolayoutで自動的に動作しますか?私はすべてをコーディングすることができると理解していますが、30種類のラベルやイメージ、さまざまなスタイルや形状のボタンがありますが、これらはすべてオプションですので、自動的に機能するときにはコードの行を追加したくありません。 。

それが動作しない場合、私はちょうどWebViewを使用し、HTMLとCSSでそれを行います。

29
テーブルが上から下に向かうのであればテーブルが助けになりますが、いくつかのものは左から右になり、他のものやものの代わりになります。しかし、この考えは悪くないと私は認めている。
追加された 著者 Jeena,
自動レイアウトで可能かどうかは分かりませんが、実際にはテーブルが必要なように見えます。
追加された 著者 user557219,

8 答え

これは自動レイアウトでは可能ですが、正確に拡大するわけではありません。

あなたの例を挙げると、ラベルAとラベルB(またはボタンなど)があるとしましょう。最初に、Aのスーパービューに上限制約を追加します。次に、AとBの間に垂直スペーシング制約があります。これまではすべて正常です。この時点でAを削除すると、Bはあいまいなレイアウトになります。あなたがそれを隠そうとしていたとしても、それはまだラベルの間のスペースを含むスペースを占有するでしょう。

次に、Bから別の制約をスーパービューの先頭に追加する必要があります。この優先順位を他の優先順位より低く(たとえば900)変更し、それを標準(または他の小さな値)に設定します。今、Aがスーパービューから削除されると、より低い優先度の制約が入り、Bを上に引きます。制約は次のようになります。

Interface Builder screenshot

この問題は、ラベルの長いリストでこれを実行しようとすると発生します。

24
追加された
これは、提示されたケースのきれいな解決策です。より多くのラベルが必要な場合は、コード内でこれを複製するのが最も簡単でしょう。 IBは、 "最近隣"を参照するときに、ポップアップの "Add new constraint"エディタで解を提案します。それが実際にそれをしたのであれば、それは箱から出るでしょう。私は問題がバインディング(「neigbhor」)が早すぎると思っており、これはストーリーボードファイル形式で見ることができます。
追加された 著者 Chris Conover,
この作品の第2部はどのように機能しますか? Bからスーパービューに別の制約を追加すると、優先度に関係なく常にトリガーされませんか?
追加された 著者 kevinl,
残念ながら、私はこの特定のロジックを私のシナリオでは使用できないようにしていました。私はボタンA、B、Cを持っています。私はBを取り除きます。
追加された 著者 kevinl,

UILabelサブクラスの折りたたみ

1つの簡単な解決策は、UILabelをサブクラス化して、固有のコンテンツサイズを変更することです。

@implementation WBSCollapsingLabel

- (CGSize)intrinsicContentSize
{
    if (self.isHidden) {
        return CGSizeMake(UIViewNoIntrinsicMetric, 0.0f);
    } else {
        return [super intrinsicContentSize];
    }
}

- (void)setHidden:(BOOL)hidden
{
    [super setHidden:hidden];

    [self updateConstraintsIfNeeded];
    [self layoutIfNeeded];
}

@end
10
追加された
まあ...すばらしい質問です。一般的には、自動レイアウトのトピックはSOで十分にカバーされていません。私はまた、多くの人がコンストレインのコンセントをつかんで、高さを叩くだけだと思います。サブクラスも少し面倒です。
追加された 著者 Cameron Lowell Palmer,
H:| - (8) - [view1] - (12) - [hidden1] - (8) - |のようなマージンは?うん...あなたはそうだけど、それはフレームを持っていたときと同じ問題です。ビュー間の間隔を確実に処理する必要がありますが、これは別の質問です。
追加された 著者 Cameron Lowell Palmer,
このアプローチの問題点は、通常はあなたの意見の周りにあるマージンを考慮に入れないことです。
追加された 著者 tcurdt,
これは、ココアでもうまくいきますが、 NSViewNoInstrinsicMetricupdateConstraintsIfNeededupdateConstraintsForSubtreeIfNeeded layoutIfNeededlayoutSubtreeIfNeeded に設定すると、魅力的に機能します。ありがとうございました!
追加された 著者 bithavoc,
これは本当にシンプルでエレガントな方法です。私はなぜそれが実際に働く場合、それが高く投票されていないのですか?
追加された 著者 software evolved,

このカテゴリでは、自動レイアウト制約付きビューの折り畳みが非常にシンプルになります。

https://github.com/depth42/AutolayoutExtensions

私はちょうどそれをプロジェクトに追加し、それは素晴らしい作品です。

4
追加された
プロジェクトでこれを使用しようとしていますが、プロジェクトのビューのXcodeに新しいパブリックコンセント PWHidingMasterView は表示されません。サンプルプロジェクトを開くと、コンセントがそこにあります。私は自分のプロジェクトやサンプルと何が違うのか理解できません。任意のヒント?
追加された 著者 Ricardo Sanchez-Saez,

私はあなたがそうすることはできないと思います。ラベル2のレイアウトをラベル1の距離制約に基づいて設定した場合、ラベル1に内容がないときに高さゼロに自動崩壊されたとしても、ラベル2はまだ距離が下がります。

+----------------+
| +------------+ |
| + label 1    | |
| +------------+ |
|        ^       |
|        ^       !
| +------------+ |
| | label 2    | |
| +------------+ |
+----------------+

ここで、^はオートレイアウトの距離制約です - ラベル1が文字列が空のときにゼロ高さになる方法を知っているなら、あなたはまだ取得します:

+----------------+
| +------------+ |
|        ^       |
|        ^       !
| +------------+ |
| | label 2    | |
| +------------+ |
+----------------+

Maybe it is possible by creating your NSLayoutConstraint manually. You could make the second attribute be the height of label 1, make the constant zero, and then carefully work out what the multiplier would be to make the distance be what you want based on a multiple of the non-zero label height.

しかし、このすべてをやったことで、自動サイズ調整を行うNSLabelサブクラスを作成し、視覚言語ではなく手動で制約オブジェクトを作成し、その意志を超えてNSLayoutConstraintを折り曲げました。

ラベル1の文字列が空白の場合、ラベル2のフレームを変更する方が良いと思います!

2
追加された
定数を0に設定せずに、インタフェースビルダーで使用できる直接オプションはどれですか?
追加された 著者 user2223516,

ここでは、Interface Builderを使用するのではなく、プログラムでこれをどのように処理したかの例を示します。要約すれば;私はそれが有効になっている場合のみ、ビューを追加し、私は行くように垂直方向の制約を追加し、サブビューを反復する。

問題のビューはこの前に初期化されていることに注意してください。

/*
  Begin Auto Layout
*/
NSMutableArray *constraints = [NSMutableArray array];
NSMutableDictionary *views = [[NSMutableDictionary alloc] init];


/*
  Label One
*/
if (enableLabelOne) {
    [contentView addSubview:self.labelOne];

    self.labelOne.translatesAutoresizingMaskIntoConstraints = NO;

    [views setObject:self.labelOne
              forKey:@"_labelOne"];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_labelOne(44)]"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:views]];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_labelOne]-|"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:views]];
}

/*
    Label Two
*/
if (enableLabelTwo) {
    [contentView addSubview:self.labelTwo];

    self.labelTwo.translatesAutoresizingMaskIntoConstraints = NO;

    [views setObject:self.labelTwo
              forKey:@"_labelTwo"];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_labelTwo(44)]"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:views]];
}

[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_labelTwo]-|"
                                                                         options:0
                                                                         metrics:nil
                                                                           views:views]];

/*
  Dynamically add vertical spacing constraints to subviews
*/
NSArray *subviews = [contentView subviews];

if ([subviews count] > 0) {
    UIView *firstView = [subviews objectAtIndex:0];
    UIView *secondView = nil;
    UIView *lastView = [subviews lastObject];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[firstView]"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:NSDictionaryOfVariableBindings(firstView)]];

    for (int i = 1; i < [subviews count]; i++) {
        secondView = [subviews objectAtIndex:i];
        [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[firstView]-10-[secondView]"
                                                                                 options:0
                                                                                 metrics:nil
                                                                                   views:NSDictionaryOfVariableBindings(firstView, secondView)]];
        firstView = secondView;
    }

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[lastView]-|"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:NSDictionaryOfVariableBindings(lastView)]];
}


[self addConstraints:constraints];

私は lastView という制約を設定しているに過ぎません。なぜなら、このコードはUIScrollViewの内部から変更されたからです。

私はもともとこれをこのスタックオーバーフローの答えに基づいて実装し、自分のニーズに合わせて変更しました。

1
追加された

私はこれを行うために、うなずいてまともな方法を見つけました。これは David's に似ています。ここでコードでどのように動作するのですか?私はスーパービューを作成しました。サブビューはすべて表示されない場合もあります。スーパービューに V:| - [_ btn] などの制約の多くを追加しました。これらの制約の最後に表示されるように、スーパービューの下にはリンクがありません。私はその後、ビューの両方の状態に対して2つの制約の配列を作成しました。違いは「詳細オプション」の開示用三角です。三角形の状態に応じて三角形をクリックすると、それに応じて制約とサブビューが追加され、削除されます。たとえば、私は追加する:

[self.backgroundView removeConstraints:self.lessOptionsConstraints];
[self.backgroundView addSubview:self.nameField];
[self.backgroundView addConstraints:self.moreOptionsConstraints];

削除した制約は、ボタンを V:[_ btn] - | のようにスーパービューの一番下につなぎました。この制約がわかるように、追加した制約は、 V:[_ btn] - [_ nameField] - | のようになり、新しいビューをその元のビューとスーパービューのスーパービューの高さ

0
追加された

プログラムでこの問題を解決しました。いくつかのボタンが連続していて、いつでもそのボタンを隠すことにします。

enter image description here

地図作成を使用して、 hidden のいずれかの変更があるたびに置き換えます。

let buttons = self.buttons!.filter { button in
    return !button.hidden
}

constrain(buttons, replace: self.constraintGroup) { buttons in
    let superview = buttons.first!.superview!

    buttons.first!.left == superview.left

    for var i = 1; i < buttons.count; i++ {
        buttons[i].left == buttons[i-1].right + 10
    }

    buttons.last!.right == superview.right
}
0
追加された

私はこれを行う別の方法を見つけました。この方法論はどこにでも適用でき、スケーリングの問題はありません。マージンも処理します。それにサードパーティのものは必要ありません。

まず、このレイアウトを使用しないでください:

V:|-?-[Label1]-10-[Label2]-10-|
H:|-?-[Label1]-?-|
H:|-20-[Label2]-20-|

代わりにこれらを使用してください:

("|" is the real (outer) container)
V:|-?-[Label1]-0-[Label2HideableMarginContainer]-0-|
H:|-?-[Label1]-?-|
H:|-0-[Label2HideableMarginContainer]-0-|

("|" is Label2HideableMarginContainer)
V:|-10-[Label2]-10-|
H:|-20-[Label2]-20-|

では、今何をしましたか? Label2 はレイアウトでは直接使用されません。 余白コンテナに配置されます。そのコンテナは Label2プロキシとして、レイアウトでは0の余白で使用されます。実際のマージンは Margin-Containerに配置されます。

Label2 を次のように隠すことができます:

    隠しYES に設定する

そして

  • Disabling the Top, Bottom, Leading そして Trailing constraints. So seek them out, than set Active to NO on them. This will cause the Margin-Container to have a Frame Size of (0,0); because it does have subview(s); but there aren't any (active) layout constraints which anchors those subviews to it.

Maybe a bit complex, but you only have to develop it once. All the logic can be put into a separate place, そして be reused every time you need to hide smg.

以下はC#Xamarinのコードで、 Margin-Container ビューの内側の端にサブビューを固定する制約をどのように探すかです:

public List SubConstraints { get; private set; }

private void ReadSubContraints()
{
    var constraints = View.Constraints;//View: the Margin-Container NSView
    if(constraints?.Any() ?? false)
    {
        SubConstraints = constraints.Where((NSLayoutConstraint c) => {
            var predicate = 
                c.FirstAttribute == NSLayoutAttribute.Top ||
                c.FirstAttribute == NSLayoutAttribute.Bottom ||
                c.FirstAttribute == NSLayoutAttribute.Leading ||
                c.FirstAttribute == NSLayoutAttribute.Trailing;
            predicate &= ViewそしてSubviews.Contains(c.FirstItem);//ViewそしてSubviews: The View そして View.Subviews
            predicate &= ViewそしてSubviews.Contains(c.SecondItem);
            return predicate;
        }).ToList();
    }
}
0
追加された