私は新しい自動レイアウトを使用しようとしています。 a>ライオンではかなりいいと思われるので。しかし、私は物事を行う方法についての良い情報を見つけることができません。例えば:
私は2つのラベルを持っています:
+----------------+
| +------------+ |
| + label 1 | |
| +------------+ |
| |
| +------------+ |
| | label 2 | |
| +------------+ |
+----------------+
最初のラベルには必ずしもコンテンツが埋め込まれていない場合があります。コンテンツがない場合もあります。私がしたいのは、ラベル1が内容を持つときにラベル2が自動的にラベル2を表示することです。
+----------------+
| +------------+ |
| + label 2 | |
| +------------+ |
| |
| |
| |
| |
+----------------+
どのような制約を加える必要があるので、autolayoutで自動的に動作しますか?私はすべてをコーディングすることができると理解していますが、30種類のラベルやイメージ、さまざまなスタイルや形状のボタンがありますが、これらはすべてオプションですので、自動的に機能するときにはコードの行を追加したくありません。 。
それが動作しない場合、私はちょうどWebViewを使用し、HTMLとCSSでそれを行います。
これは自動レイアウトでは可能ですが、正確に拡大するわけではありません。
あなたの例を挙げると、ラベルAとラベルB(またはボタンなど)があるとしましょう。最初に、Aのスーパービューに上限制約を追加します。次に、AとBの間に垂直スペーシング制約があります。これまではすべて正常です。この時点でAを削除すると、Bはあいまいなレイアウトになります。あなたがそれを隠そうとしていたとしても、それはまだラベルの間のスペースを含むスペースを占有するでしょう。
次に、Bから別の制約をスーパービューの先頭に追加する必要があります。この優先順位を他の優先順位より低く(たとえば900)変更し、それを標準(または他の小さな値)に設定します。今、Aがスーパービューから削除されると、より低い優先度の制約が入り、Bを上に引きます。制約は次のようになります。
この問題は、ラベルの長いリストでこれを実行しようとすると発生します。
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
私はあなたがそうすることはできないと思います。ラベル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のフレームを変更する方が良いと思います!
ここでは、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の内部から変更されたからです。
私はもともとこれをこのスタックオーバーフローの答えに基づいて実装し、自分のニーズに合わせて変更しました。
私はこれを行うために、うなずいてまともな方法を見つけました。これは 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] - |
のようになり、新しいビューをその元のビューとスーパービューのスーパービューの高さ
私はこれを行う別の方法を見つけました。この方法論はどこにでも適用でき、スケーリングの問題はありません。マージンも処理します。それにサードパーティのものは必要ありません。
まず、このレイアウトを使用しないでください:
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
に設定するそして
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();
}
}
プログラムでこの問題を解決しました。いくつかのボタンが連続していて、いつでもそのボタンを隠すことにします。
地図作成を使用して、 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
}