Masonry進階

weixin_33866037發表於2015-12-10
  1. 九宮格

類似九宮格效果:
意思就是一排3個一共三排 寬度自適應
本文Demo
以及@劉棟 棟神的Demo Demo
效果如下:

982286-8246fc5272bddc3d.png
豎屏

982286-0a0e27d0272736d6.png
橫屏

程式碼實現:

// 建立一個空view 代表上一個view
   __block UIView *lastView = nil;
   // 間距為10
   int intes = 10;
   // 每行3個
   int num = 3;
   // 迴圈建立view
   for (int i = 0; i < 12; i++) {

      UIView *view = [UIView new];
       [self.view addSubview:view];
       view.backgroundColor = [UIColor colorWithHue:(arc4random() % 256 / 256.0 ) saturation:( arc4random() % 128 / 256.0 ) + 0.5
                                         brightness:( arc4random() % 128 / 256.0 ) + 0.5 alpha:0.2];

       // 新增約束
       [view mas_makeConstraints:^(MASConstraintMaker *make) {
           // 給個高度約束
           make.height.mas_equalTo(80);

           // 1. 判斷是否存在上一個view
           if (lastView) {
               // 存在的話寬度與上一個寬度相同
               make.width.equalTo(lastView);
           } else {
               // 否則計算寬度  !!!此處的判斷條件是為了避免 最後一列約束衝突
               /**
                *  這裡可能大家會問 為什麼上面我說最後一列會有衝突?
                *  如果不新增判斷的話會造成:
                *  1新增了寬度約束 2所有列加了左側約束 第3步給 最後一列新增了右側約束
                *  這裡最後一列既有左側約束又有右側約束還有寬度約束 會造成約束衝突
                *  所以這裡新增寬度時將最後一列剔除
                */
               if (i % num != 0) {
               make.width.mas_equalTo((view.superview.frame.size.width - (num + 1)* intes)/4);
               }
           }
           // 2. 判斷是否是第一列
           if (i % num == 0) {
               // 一:是第一列時 新增左側與父檢視左側約束
               make.left.mas_equalTo(view.superview).offset(intes);
           } else {
               // 二: 不是第一列時 新增左側與上個view左側約束
               make.left.mas_equalTo(lastView.mas_right).offset(intes);
           }
           // 3. 判斷是否是最後一列 給最後一列新增與父檢視右邊約束
           if (i % num == (num - 1)) {
               make.right.mas_equalTo(view.superview).offset(-intes);
           }
           // 4. 判斷是否為第一列
           if (i / num == 0) {
               // 第一列新增頂部約束
               make.top.mas_equalTo(view.superview).offset(intes*10);
           } else {
               // 其餘新增頂部約束 intes*10 是我留出的距頂部高度
               make.top.mas_equalTo(intes * 10 + ( i / num )* (80 + intes));
           }
           
       }];
       // 每次迴圈結束 此次的View為下次約束的基準
       lastView = view;

   }

下面文章的參考來自 iOS122 非常感謝 地址

上面說明了Masonry不僅僅可以表達相等關係
看圖:

982286-cc36cd9b02ec2568.png
Masonry部分程式碼

由上圖可以看出一些等價關係
equalTo == NSLayoutRelationEqual
mas_equalTo == NSLayoutRelationEqual

  • 並且Masonry不止可以表達相等關係
    greaterThanOrEqualTo == NSLayoutRelationGreaterThanOrEqual
    mas_greaterThanOrEqualTo == NSLayoutRelationGreaterThanOrEqual
    lessThanOrEqualTo == NSLayoutRelationLessThanOrEqual
    mas_lessThanOrEqualTo == NSLayoutRelationLessThanOrEqual

所以如果你需要view的寬度在一定範圍內:

        make.width.greaterThanOrEqualTo(@100);
        make.width.lessThanOrEqualTo(@150); 
        或者:
        make.width.mas_greaterThanOrEqualTo(100);
        make.width.mas_lessThanOrEqualTo(150);

如果你希望view.left大於或等於button.left

        make.left.greaterThanOrEqualTo(button);
        make.left.greaterThanOrEqualTo(button.mas_left);

        make.left.mas_greaterThanOrEqualTo(button);
        make.left.mas_greaterThanOrEqualTo(button.mas_left);
  • 此外上面的文章還提到了利用陣列表達三個view等高的情況

        // 表達三個檢視等高的約束.
       make.height.equalTo(@[view1.mas_height, view2.mas_height]);
       make.height.equalTo(@[view1, view2]);
    
  • 以及定義約束的優先順序

.priority 允許你指定一個精確的優先順序,數值越大優先順序越高.最高1000.

.priorityHigh 等價於 UILayoutPriorityDefaultHigh.優先順序值為 750.

.priorityMedium 介於高優先順序和低優先順序之間,優先順序值在 250~750之間.

.priorityLow 等價於 UILayoutPriorityDefaultLow, 優先順序值為 250.
優先順序可以在約束尾部新增:

    make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow();

    make.top.equalTo(label.mas_top).with.priority(600);
  • Masonry還可以支援兩個View等比例變化
    multipliedBy允許你指定一個兩個檢視的某個屬性等比例變化item1.attribute1 = multiplier × item2.attribute2 + constant,此為約束的計算公式,.multipliedBy本質上是用來限定 multiplier的.

但是因為座標系的原點是左上角開始的,所以指定基於父檢視的left或者top的multiplier是沒有意義的,因為父檢視的left和top總為0.
如果你需要一個檢視隨著父檢視的寬度和高度,位置自動變化,你應該同時指定 right,bottom,width,height與父檢視對應屬性的比例(基於某個尺寸下的相對位置計算出的比例),並且constant必須為0.

     // 寬度為父檢視的一半
     make.width.equalTo(superview).multipliedBy(0.5);
  • 此外除了上一篇Masonry初探提到的edges
    還有其他比較方便的寫法:

    // width = superview.width + 100, height = superview.height - 50
     make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50))
    

比如之前對於center的偏移量一般會寫:
make.centerX.equalTo(self.view.mas_centerX).offset(-10);
make.centerY.equalTo(self.view.mas_centerY).offset(50);
其實可以這麼寫:
make.center.equalTo(self.view).centerOffset(CGPointMake(-10, 50));

  • 並且返回的約束和約束陣列我們可以用屬性接收 方便操作

        self.widthConstraint = make.width.equalTo(lastV.mas_width);
        [self.widthConstraint uninstall];
    

感謝@劉棟 同學以及@暮落晨曦 小殭屍同學的幫助

未完待續......