OS X Cocoa Auto Layout maxfiy elementlari

Men yangi Auto Layout ni ishlatishga harakat qilaman. da, chunki juda yaxshi ko'rinadi. Lekin narsalarni qanday qilish haqida yaxshi ma'lumot topa olmayapman. Misol uchun:

Menda ikkita teg bor:

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

lekin birinchi teg har doim kontent bilan to'ldirilmaydi, ba'zida uning uchun hech qanday kontent yo'q. Men nima qilishni xohlasam, 1-belgining mazmuni bo'lganda yorliqni avtomatik ravishda ko'rsatish kerak.

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

Autolayout bilan avtomatik ravishda ishlaydigan qilib, qanday qo'shimcha cheklovlarni kiritishim kerak? Men hamma narsani faqatgina kodlashim mumkinligini tushunaman, lekin mening taxminan 30 tagacha etiket va rasm va tugmachalar turli xil uslub va shakllar mavjud, bularning barchasi ixtiyoriy va men avtomatik tarzda juda yaxshi ishlay oladigan kod satrlari qo'shilmoqchi emasman .

Agar u ishlamasa, men faqatgina WebViewdan foydalanaman va HTML va CSS bilan ishlayman.

29
Agar jadval faqat yuqoridan pastga tushsa, bir jadval yordam beradi, lekin ba'zi narsalar ham chapdan o'ngga, boshqalarning va narsalarning o'rnini egallashi kerak. Lekin bu fikrni men tan olmayapman.
qo'shib qo'ydi muallif Jeena, manba
Avtomatik tuzilish bilan mumkinligini bilmayman, lekin aslida siz xohlagan narsangizga o'xshaydi.
qo'shib qo'ydi muallif user557219, manba

8 javoblar

Bu avtomatik tartib bilan amalga oshirilishi mumkin, biroq aniq ravishda o'lchamasligi mumkin.

Shunday qilib, masalan, A belgisi va B belgisiga (yoki tugmani yoki boshqa biror narsa) ega bo'lishingiz mumkin. Avval A uchun superseptsiyani qo'shib, boshlang. Keyin, A va B o'rtasida vertikal oraliq chegarasi. Bu hozirgacha normaldir. Agar siz Ani ushbu nuqtada olib tashlasangiz, B noaniq tartibga ega bo'lishi kerak edi. Agar siz uni yashirishni istasangiz, u hali ham uning bo'sh joyini egallaydi, shu jumladan teglar orasidagi bo'sh joy.

Keyinchalik B-dan yana bir cheklov qo'shishingiz kerak. Buning ustunligini boshqalardan ko'ra pastroq deb o'zgartiring (900 deb yozing) va so'ngra uning sobit (yoki boshqa kichikroq qiymati) bo'lishini o'rnating. Endi, A-ning sirtdan chiqarilganda, pastroq ustuvor cheklovlar boshlanadi va B tomonga yuqoriga qarab tortiladi. Cheklovlar shunday ko'rinishga ega:

Interface Builder screenshot

Muammoni uzoq vaqtdan beri yorliqlar ro'yxatiga kiritishga urinayotganda keladi.

24
qo'shib qo'ydi
Bu taqdim etilgan ish uchun toza echim. Ko'proq teglar uchun, bu kodni ko'paytirish oson. IB "yaqin qo'shni" ga murojaat qilganida, "Yangi cheklovni qo'shish" muharriri pop-up-da yechim taklif qiladi. Agar haqiqatan ham shunday bo'lsa, u qutidan chiqadi. Muammo shundaki, ular ("neigbhor") juda erta bo'lishi kerak, va buni buni hikoya qilish formatidagi fayl formatida ko'rishingiz mumkin.
qo'shib qo'ydi muallif Chris Conover, manba
bu ishning ikkinchi qismi qanday? Agar B dan yana bir qo'shimcha cheklov qo'shsangiz, u ustuvor bo'lishidan qat'iy nazar har doim tetiklanmaydi.
qo'shib qo'ydi muallif kevinl, manba
Sizningcha, men bu ishni yakunlamagan ish stsenariyasidan foydalanmoqchi bo'ldim: men A, B, C tugmalarini bosdim. B ni olib tashlayapman va C ga ega bo'lishni istayman.
qo'shib qo'ydi muallif kevinl, manba

UILabel subclassini yig'ish

Bitta sodda yechim UILabelning pastki klassi va ichki kontentning o'lchamini o'zgartirishdir.

@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
qo'shib qo'ydi
Xo'sh ... katta savol. Umuman olganda, avtomatik tarzda tartibga solingan mavzular SO ga yaxshi ta'sir o'tkazmagan. Bundan tashqari, men ko'pchilik odamlar cheklovga chiqish nuqtasini ko'tarib, balandlikda o'ynashni o'ylayman. Sub-tasnifi ham bir oz zerikarli.
qo'shib qo'ydi muallif Cameron Lowell Palmer, manba
H: | - (8) - [view1] - (12) - [yashirin] - (8) - | Ha ... Siz haqsiz, lekin bu sizning ramkangizda bo'lganingizda ham xuddi shu muammo. Siz hali ham ko'rinish o'rtasidagi masofa ishonchliligini tekshirishingiz kerak, lekin bu alohida savoldir!
qo'shib qo'ydi muallif Cameron Lowell Palmer, manba
Ushbu yondashuv bilan bog'liq muammo, siz odatda fikrlaringiz atrofida bo'lgan marjinlarni hisobga olmaydi.
qo'shib qo'ydi muallif tcurdt, manba
Bu faqat uchun NSViewNoInstrinsicMetric , updateConstraintsIfNeeded uchun UIViewNoIntrinsicMetric o'tish, shuningdek, bu kakao ishlaydi, masalan, bir toza hal updateConstraintsForSubtreeIfNeeded va uchun layoutIfNeeded layoutSubtreeIfNeeded va bir joziba kabi ishlaydi. Rahmat!
qo'shib qo'ydi muallif bithavoc, manba
Bu borishning chindan ham sodda, oqilona usuliga o'xshaydi. Men aslida ishlayotgan bo'lsa, nima uchun u yuqoriroq ovoz bermaganligini qiziqtirganman?
qo'shib qo'ydi muallif software evolved, manba

Ushbu turkumda avtomatik tartiblash cheklangan ko'rinishlarni chindan ham osonlashtirmoqda:

https://github.com/depth42/AutolayoutExtensions

Men uni faqat loyihaga qo'shdim va u ajoyib ishlaydi.

4
qo'shib qo'ydi
Men buni loyihamda ishlatmoqchiman, lekin yangi PWHidingMasterView loyihasi mening xcode ko'rinishda ko'rinmaydi. Men namunali loyihani ochganimda, mahsulot bor. Men loyihamdan va namunadan nimalarni farqlay olaman. Har qanday maslahat?
qo'shib qo'ydi muallif Ricardo Sanchez-Saez, manba

Men shunday qila olaman deb o'ylamayman. Agar siz 2-yorliq uchun tartibni o'rnatgan bo'lsangiz, 1-yorliqdan masofa chekloviga tayanilansiz ham, 1 ta avtomatik tanaffusni hech qanday kontent yo'q bo'lsa, nolga tenglashtirsa ham, 2-yorliq hali ham o'sha masofani pastga aylantiradi, ya'ni:

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

Qaerda ^ autolayout masofa cheklovi - Label 1 satr bo'sh bo'lganda qanday qilib nolga aylanishi mumkinligini bilsa, siz hali ham olishni boshlaysiz:

+----------------+
| +------------+ |
|        ^       |
|        ^       !
| +------------+ |
| | 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.

Ammo buning hammasini qildingiz, endi avtomatik o'lchamdagi NSLabel subclassini kodlashingiz, vizual til orqali emas, cheklov obyektini qo'lda yaratgansiz va NSLayoutConstraint ni o'z xohishidan tashqari bükgansiz.

Agar siz etiketli 1 ning siri bo'sh bo'lsa, 2-ramkani o'zgartirganingiz ma'qulroq!

2
qo'shib qo'ydi
interfeysi yaratuvchisi mavjud bo'lgan har qanday to'g'ridan-to'g'ri parametr mavjud emasmi?
qo'shib qo'ydi muallif user2223516, manba

Interface Builder dasturidan foydalanishni emas, balki bu dasturiy usulda qanday ishlashimni ko'rib chiqaylik. Qisqa bayoni; yakunida; Men faqat faollashtirilgan ko'rinishni qo'shib qo'yaman va keyin men subversiyalar ustidan yinelaman, men borganimda vertikal cheklovlarni qo'shaman.

Shuni e'tiborga olingki, ko'rib chiqilayotgan qarashlar bundan oldin ishga tushiriladi.

/*
  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];

Men faqatgina lastView cheklovini o'rnatmoqchiman, chunki bu kod UIScrollView ichidagi biror narsadan moslangan.

Aslida buni bu Stack Overflow answer ga asoslanib amalga oshirdim va narsalarni o'z ehtiyojlarimga mos ravishda o'zgartirdim.

1
qo'shib qo'ydi

Buni amalga oshirish uchun juda yaxshi yo'lni topdim. Bu Devidning ga o'xshaydi. Kodning qanday ishlashi bu erda. Men umumiy nuqtai va barcha subviewsni yaratdim, hatto doimo ko'rsatilmaydigan narsalar ham. V: | - [_ btn] kabi cheklovlarni ko'pchiligiga qo'shib qo'ydim. Ushbu cheklovlar oxirida ko'rib turganingizdek, pastki qismda pastki qismga bog'lanish yo'q. Keyin ikkala holat uchun ham ikkita qator cheklovlarni yaratdim, men uchun bu farq "Ko'proq variantlar" uchburchagi. So'ngra, uchburchak uning holatiga bog'liq holda bosilsa, shunga ko'ra cheklovlar va subvavatlarni qo'shib, olib tashlayman. Masalan, quyidagilarni qo'shish uchun:

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

Men chiqargan cheklovlar tugmachani pastki qismga V: [_ btn] - | tagiga bog'lab qo'ydi. Men kiritgan cheklashlar V: [_ btn] - [_ nameField] - | ko'rinishiga o'xshaydi, chunki siz bu cheklash yangi ko'rinishni yuqoridagi asl ko'rinish bilan pastki qismning pastki qismiga suplementning balandligi.

0
qo'shib qo'ydi

Ushbu muammoni muntazam hal qilib berdik. Men qatorda bir nechta tugmachalarim bor va har qanday vaqtda uni yashirishga qaror qilishim mumkin.

enter image description here

Istalgan Kartografiya ulardan har qandayida hidden o'zgarishlar har doim ularni almashtirish uchun.

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
qo'shib qo'ydi

Buning yana bir yo'li topdim. Ushbu metodologiya har qVAay joyda qo'llanishi mumkin, miqdoriy muammolarga ega emas; va shuningdek, chekka joylarni ham ishlaydi. Va buning uchun 3-partiyaning narsalariga kerak emas.

Birinchidan, ushbu tartibni ishlatmang:

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

Buning o'rniga foydalaning:

("|" 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-|

Xo'sh, endi nima qildik? Label2 tartibda to'g'ridan-to'g'ri foydalanilmaydi; u Margin-Container ga joylashtirilgan. Ushbu konteyner Label2 proksi sifatida ishlatilgan, tartibda 0 chekka joyga ega. Haqiqiy chekkalari Margin-Container ning ichki qismiga joylashtiriladi.

Endi biz Label2 -ni yashirishimiz mumkin:

  • Yashirin sozlamasini YES ga o'rnatish

VA

  • Disabling the Top, Bottom, Leading VA 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, VA be reused every time you need to hide smg.

Bu erda C# Xamarin kodi Margin-Container ko'rinishining ichki qirralariga subview (lar) ni belgilovchi cheklovlarni qanday qilib qidirmoq kerak:

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 &= ViewVASubviews.Contains(c.FirstItem);//ViewVASubviews: The View VA View.Subviews
            predicate &= ViewVASubviews.Contains(c.SecondItem);
            return predicate;
        }).ToList();
    }
}
0
qo'shib qo'ydi