OS X Cocoa Auto Layout схаваныя элементы

Я спрабую выкарыстоўваць новы Auto Layout </а> у Ліёне, таму што здаецца даволі добра. Але я не магу знайсці добрую інфармацыю аб тым, як рабіць рэчы. Напрыклад:

У мяне ёсць дзве пазнакі:

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

але першая метка атрымлівае не заўсёды запаўняецца зместам, часам не истите проста няма кантэнту для яго. Тое, што я хацеў бы зрабіць гэта аўтаматычна паказаць этыкетку 2, дзе пазнака 1 будзе, калі ён будзе мець змест.

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

Што стрымлівае б я павінен дадаць, дык гэта працуе аўтаматычна з autolayout? Я разумею, што я мог бы проста закадаваць усё, але ў мяне ёсць каля 30 такіх пазнак і выявы і кнопкі розных стыляў і формаў, якія з'яўляюцца неабавязковымі, і я не хачу, каб дадаць hundrets радкоў кода, калі ён можа працаваць у аўтаматычным рэжыме даволі добра таксама ,

Калі ён не працуе, то я буду проста выкарыстоўваць WebView і зрабіць гэта з HTML і CSS.

29
Табліца дапаможа, калі б толькі зверху ўніз, але некаторыя рэчы занадта злева направа і павінны заняць месца іншых людзей і рэчаў. Але ідэя не дрэнная, я прызнаю.
дададзена аўтар Jeena, крыніца
Я не ўпэўнены, калі гэта магчыма з аўтаматычнай раскладкай, але гэта выглядае як тое, што вы сапраўды хочаце гэта табліца.
дададзена аўтар user557219, крыніца

8 адказы

Гэта магчыма з аўтаматычным макеце, але дакладна не маштабуецца.

Такім чынам, прымаючы ваш прыклад, скажам, у вас ёсць ярлык A, і пазнака B (або кнопка або што-небудзь яшчэ на самай справе). Першы запуск шляхам дадання верхняга абмежаванні да надтаблицам для А. Тады вертыкальнае адлегласці паміж абмежаваннем паміж А і В. Гэта ўсё нармальна да гэтага часу. Калі вы павінны былі выдаліць ў гэтай кропцы, B будзе мець неадназначнае размяшчэнне. Калі б вы былі, каб схаваць гэта, яна па-ранейшаму займае гэта прастора, уключаючы прастору паміж пазнакамі.

Далей вам трэба дадаць яшчэ адно абмежаванне, з B, у верхняй частцы надтаблицы. Змена прыярытэту на гэтым будзе ніжэй, чым у іншых (скажам, 900), а затым ўсталяваць яго пастаянным быць стандартным (або іншае меншае значэнне). Цяпер, калі выдаляецца ад яго SuperView, з больш нізкім прыярытэтам абмежаванне будзе ўдар і цягнуць B да вяршыні. Абмежаванні выглядаць прыкладна так:

Interface Builder screenshot

Праблема ўзнікае, калі вы спрабуеце зрабіць гэта з дапамогай доўгага спісу метак.

24
дададзена
Гэта чыстае рашэнне для выпадку, прадстаўленага. Для выпадку больш пазнак, верагодна, было б лягчэй паўтарыць гэта ў кодзе. IB прапануе рашэнне ў ўсплываючым акне «Дадаць новае абмежаванне» рэдактар, калі ён спасылаецца на «бліжэйшы сусед». Калі гэта на самай справе толькі што, ён будзе працаваць з скрынкі. Я думаю, што праблема ў тым, што яны з'яўляюцца абавязковымі ( «neigbhor») занадта рана, і вы можаце ўбачыць гэта ў раскадроўкі фармату.
дададзена аўтар Chris Conover, крыніца
як жа другая частка гэтай працы? Калі дадаць яшчэ адно абмежаванне, ад B да надтаблицы, не заўсёды выклікаюць незалежна ад прыярытэту?
дададзена аўтар kevinl, крыніца
дуля, я спрабаваў выкарыстаць гэтую спецыфічную логіку па маім сцэнары, які не ў канчатковым выніку працуе: у мяне ёсць кнопка A, B, C. Я выдаляю B, і я хачу, C, каб заняць месца B.
дададзена аўтар kevinl, крыніца

Згортванне UILabel падклас

Адно простае рашэнне, гэта проста падклас 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. Я таксама думаю, што многія людзі проста падключыць выхад да абмежавання і граміць вышыню. Sub-прылічаць таксама трохі раздражняе.
дададзена аўтар Cameron Lowell Palmer, крыніца
Поля, як і ў Н: | - (8) - [view1] - (12) - [hidden1] - (8) - |? Да ... Вы маеце рацыю, але гэта тая ж самая праблема, калі ў вас з кадрамі. Вы ўсё яшчэ будзеце павінны пераканацца, што адлегласць паміж выглядам апрацоўваецца, але гэта асобнае пытанне!
дададзена аўтар Cameron Lowell Palmer, крыніца
Праблема такога падыходу складаецца ў тым, што ён не прымае пад увагу, што палі вы звычайна маеце вакол поглядаў.
дададзена аўтар tcurdt, крыніца
Гэта такое вытанчанае рашэнне працуе ў какава, а таксама, проста уключыце UIViewNoIntrinsicMetric у NSViewNoInstrinsicMetric , updateConstraintsIfNeeded у updateConstraintsForSubtreeIfNeeded і layoutIfNeeded у layoutSubtreeIfNeeded і ён працуе як шарм. Дзякуй!
дададзена аўтар bithavoc, крыніца
Гэта здаецца вельмі простым, элегантным спосабам пайсці. Мне цікава, чаму ён не быў прызнаны вышэй, калі яна на самай справе працуе?
дададзена аўтар software evolved, крыніца

Гэтая катэгорыя робіць руйнуюць Auto Layout стрымліваецца выгляд вельмі просты:

https://github.com/depth42/AutolayoutExtensions

Я проста дадаць яго ў праект, і ён выдатна працуе.

4
дададзена
Я спрабую выкарыстоўваць гэта ў маім праекце, але новы грамадскі выпускны PWHidingMasterView не з'яўляецца ў Xcode для поглядаў на мой праект. Калі я адкрываю ўзор праекта выйсце ёсць. Я не магу зразумець, што гэта адрозніваецца ад майго праекта, і ўзор аднаго. Любыя парады?
дададзена аўтар Ricardo Sanchez-Saez, крыніца

Я не думаю, што вы маглі б зрабіць гэта такім чынам. Калі вы зрабілі макет для этыкеткі 2 грунтавацца на адлегласці абмежаванні ад пазнакі 1, нават калі вы зрабілі ярлык 1 аўтаматычнага калапс на нулявую вышыню, калі ён не мае ніякага зместу, пазнака-усё яшчэ будзе, што адлегласць ўніз, гэта значыць у:

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

Дзе ^ з'яўляецца autolayout адлегласці абмежаванні - Калі пазнака 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 па-за яго волі.

Я думаю, што вам лепш проста змяніць рамку этыкеткі 2, калі ярлык 1 у радок пусты!

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
дададзена

Я знайшоў seemlingly годнага спосабу зрабіць гэта, як добра. Гэта падобна на Дэвіда. Вось як гэта працуе ў кодзе. Я стварыў SuperView і ўсе гэтыя падвіды, нават тыя, якія не заўсёды могуць быць паказаны. Я дадаў шмат абмежаванняў, такіх як V: | - [_ BTN] у надтаблицы. Як вы можаце бачыць у канцы гэтых абмежаванняў не існуе спасылка на дно на надтаблицы. Затым я стварыў два масіва абмежаванняў для абодвух станаў гледжання, для мяне розніца з'яўляецца раскрыццё трыкутніка «Дадатковыя параметры». Тады, калі трохкутнік пстрыкнуў у залежнасці ад таго, што гэта стан я дадаваць і выдаляць абмежаванні і падвідаў адпаведна. Напрыклад, каб дадаць я:

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

Абмежаванні я выдаленыя прывязаў кнопку ўнізе надтаблицы як V: [_ BTN] - | . Абмежаванні я дадаў выглядаць V: [_ BTN] - [_ nameField] - | як вы можаце бачыць гэта абмежаванне змяшчае новы від паміж першапачатковым выглядам над ёй і ніжняй часткай надтаблицы, якая пашырае вышыня SuperView ст.

0
дададзена

Вырашана гэтае пытанне праграмна. У мяне ёсць некалькі кнопак у шэраг, і я магу вырашыць, каб схаваць адзін у любы час.

enter image description here

Б картаграфія , каб замяніць іх кожны раз, скрыты змены ў любы з іх.

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
дададзена

Я знайшоў яшчэ адзін спосаб зрабіць гэта. Гэтая методыка можа быць прымененая ў любым месцы, не мае ніякіх праблем маштабавання; і апрацоўвае поля, а таксама. І вам не трэба 3-ці партыі рэчы для яго.

Па-першае, не выкарыстоўваць гэты фармат:

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 не выкарыстоўваецца непасрэдна ў макеце; ён змяшчаецца ў Margin-Container . Кантэйнер ад выкарыстоўваецца ў якасці <�моцны> проксі </моцны> з label2 , <�моцны> з 0 палямі ў макеце. Рэальныя поля змяшчаюцца ўнутры у Margin-Container .

Цяпер мы можам схаваць LABEL2 з:

  • настройка Утоены у Ды на ім

І

  • 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 код, як шукаць тыя абмежаванні, якія якароў у падвід (ы) да унутраным краях маржынальнасць-кантэйнер Выгляд:

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
дададзена