2

次のシナリオでのレイアウト制約の使用について質問があります。すべてがコードです (ニブやストーリーボードはありません)。任意の行数のアイテムを含むビューを作成したいと考えています。各行には、任意の数のサブビューが含まれます。

このビューを作成するには、2 レベルの深さの配列を渡します。第 1 レベルの配列には、各行が含まれます。第 2 レベルの配列には、各行の要素が含まれます。たとえば、これは次のようになります。

NSArray *elements = @[@[subview1, subview2, subview3], @[subview4], @[subview5, subview6]]

この配列には、3 つの行があります。

1) 行 1: subview1、subview2、subview3
2) 行 2: subview4
3) 行 3: subview5、subview6

これらの要素を次のようにフォーマットしたい:

-行はすべて、親ビューの全幅である必要があります(これについては、画面のサイズであると想定できます)
-行内の各要素は同じ幅で、それらの間に同じ量のスペースがある必要があります(たとえば4 つの要素がある場合、1&2 と 2&3 の間のスペースは 10pt になる可能性があります)
- 各行には、それらの間に同じ量の垂直スペースが必要です (たとえば、各行の間に 10pt の垂直スペース)。

上記のシナリオでは、行 1 には等間隔で等間隔​​に配置された等幅の 3 つのサブビューがあり、行 2 には行の全幅を占める 1 つのサブビューがあり、行 3 には等幅で等間隔に配置された 2 つのサブビューがあります。離れて。

では、問題は、これをどのように行うかです。

私はしばらくこれに取り組んできましたが、私の理解はこれ以上良くなっていないようです。助けていただければ幸いです!

4

2 に答える 2

9

このようなものがうまくいくはずです。私は一般的に作ろうとしたので、行数と行ごとの要素が異なる場合に機能するはずです。

#define subviewHeight 44
#define spaceFromTop 10
#define spaceFromSide 10
#define subviewVerticalSpacing 10
#define subviewHorizontalSpacing 10

@implementation ViewController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    UIButton *subview1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [subview1 setTitle:@"View 1" forState:UIControlStateNormal];
    UIButton *subview2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [subview2 setTitle:@"View 2" forState:UIControlStateNormal];
    UIButton *subview3 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [subview3 setTitle:@"View 3" forState:UIControlStateNormal];
    UIButton *subview4 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [subview4 setTitle:@"View 4" forState:UIControlStateNormal];
    UIButton *subview5 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [subview5 setTitle:@"View 5" forState:UIControlStateNormal];
    UIButton *subview6 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [subview6 setTitle:@"View 6" forState:UIControlStateNormal];

    NSArray *arrayOfSubviews = @[@[subview1, subview2, subview3], @[subview4], @[subview5, subview6]];

    [self addSubviewsWithConstraints:arrayOfSubviews];

}

-(void)addSubviewsWithConstraints:(NSArray *) arrayOfArrays {
    NSMutableArray *arrayOfViewsDicts = [NSMutableArray array]; // make the views dictionaries needed for the views parameter of constraintsWithVisualFormat:options:metrics:views:. One for each row.

    for (NSArray *array in arrayOfArrays) {
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        for (int i = 0; i < array.count; i++) {
            [dict setObject:array[i] forKey:[NSString stringWithFormat:@"view%d",i]];
        }
        [arrayOfViewsDicts addObject:dict];
    }

    for (int i=0; i<arrayOfArrays.count; i++) {
        NSString *formatString = [self makeConstraintsForRowOfSubviews:arrayOfArrays[i] withViewsDict:arrayOfViewsDicts[i]]; // Make the format string for a row of subviews

        for (id subview in arrayOfArrays[i]) {
            [subview setTranslatesAutoresizingMaskIntoConstraints:NO];
            [self.view addSubview:subview];
            NSLayoutConstraint *heightCon = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:subviewHeight];
            [subview addConstraint:heightCon];

            NSLayoutConstraint *verticalCon = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:spaceFromTop + ((subviewHeight + subviewVerticalSpacing)*i)];
            [self.view addConstraint:verticalCon];
        }
        NSArray *cons = [NSLayoutConstraint constraintsWithVisualFormat:formatString options:NSLayoutFormatAlignAllBottom metrics:nil views:arrayOfViewsDicts[i]];

        [self.view addConstraints:cons];
    }
}


-(NSString *) makeConstraintsForRowOfSubviews:(NSArray *) arrayOfSubviews withViewsDict:(NSDictionary *) viewsDict {
    NSMutableString *formatString = [NSMutableString string];

    for (int i = 0; i<arrayOfSubviews.count; i++) {
        if (i == 0) {
            [formatString appendFormat:@"|-%d-[%@]",spaceFromSide,[viewsDict allKeysForObject:arrayOfSubviews[i]][0]];
        }else{
            [formatString appendFormat:@"-%d-[%@(==view0)]",subviewHorizontalSpacing,[viewsDict allKeysForObject:arrayOfSubviews[i]][0]];
        }
    }

    [formatString appendFormat:@"-%d-|",spaceFromSide];
    return formatString;
}

このコードにより、次の結果が生成されました。

ここに画像の説明を入力

于 2013-04-25T06:37:20.353 に答える
0

autolayout でこれを行うこともできUICollectionViewますが、独自のカスタムUICollectionViewLayoutサブクラスでa を使用した場合、コードは実際には理解しやすくなると思います。

本当に autolayout を使用したい場合は、中間レベルの「行」ビューを導入して、ビュー階層を配列階層と一致させる必要があると思います。

gridView
├─ rowView0
│  ├─ subview1
│  ├─ subview2
│  └─ subview3
├─ rowView1
│  └─ subview4
└─ rowView2
   ├─ subview5
   └─ subview6

これで、次のように行に制約を設定できます。

// These constraints force the rows to collectively fill gridView:
rowView0.top = gridView.top
rowView1.top = rowView0.bottom + 10
rowView2.top = rowView1.bottom + 10
gridView.bottom = rowView2.bottom

// These constraints force the rows to have equal heights:
rowView1.height = rowView0.height
rowView2.height = rowView0.height

// These constraints force the rows to each be the width of gridView:
rowView0.leading = gridView.leading
rowView0.trailing = gridView.trailing
rowView1.leading = gridView.leading
rowView1.trailing = gridView.trailing
rowView2.leading = gridView.leading
rowView2.trailing = gridView.trailing

これらの制約は、必要 (つまり、過度に制約されない) かつ十分 (つまり、あいまいでない) である必要があります。

次に、X 軸と Y 軸を入れ替えて、同じ制約スキームを各行に適用できます。たとえば、次の制約を行 0 で使用します。

// These constraints collectively force the cells to fill rowView0:
subview1.leading = rowView0.leading
subview2.leading = subview1.trailing + 10
subview3.leading = subview2.trailing + 10
rowView0.trailing = subview3.trailing

// These constraints force the cells to have equal widths:
subview2.width = subview1.width
subview3.width = subview1.width

// These constraints force the cells to each be the height of rowView0:
subview1.height = rowView0.height
subview2.height = rowView0.height
subview3.height = rowView0.height
于 2013-04-25T05:01:05.347 に答える