HQUIKit 0.0.4

HQUIKit 0.0.4

测试测试
语言语言 Obj-CObjective C
许可证 MIT
发布上次发布2017 年 8 月

HanQi 维护。



HQUIKit 0.0.4

  • 作者:
  • hq

#Masonry

Masonry 仍然得到积极的维护,我们承诺修复问题,并从更广泛的社区合并高质量 PR。然而,如果在您的项目中使用 Swift,我们建议使用 SnapKit,因为它提供了更简单的 API 和更好的类型安全。

Masonry 是一个轻量级的布局框架,它使用更友好的语法定义 AutoLayout。Masonry 有自己的布局 DSL,它提供了一种链式描述 NSLayoutConstraints 的方法,从而使得布局代码更加简洁、易读。Masonry 支持 iOS 和 macOS。

例如,查看 Masonry 工作区中的 Masonry iOS 示例 项目。下载后需要运行 pod install

为什么说 NSLayoutConstraints 不好?

底层,Auto Layout 是一种强大而灵活的方式来组织和布局您的视图。然而,从代码中创建约束可能是冗长且不描述性的。想象一下这样一个简单的例子:您希望一个视图填充其父视图,但每边都要内嵌 10 像素。

UIView *superview = self.view;

UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];

UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);

[superview addConstraints:@[

    //view1 constraints
    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeTop
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeTop
                                multiplier:1.0
                                  constant:padding.top],

    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeLeft
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeLeft
                                multiplier:1.0
                                  constant:padding.left],

    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeBottom
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeBottom
                                multiplier:1.0
                                  constant:-padding.bottom],

    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeRight
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeRight
                                multiplier:1
                                  constant:-padding.right],

 ]];

即使是这样简单的例子,所需的代码也很冗长,在您有超过 2 或 3 个视图时,代码很快就会变得不可读。另一个选项是使用视觉格式语言(VFL),它比 VFL 要简短一些。然而,ASCII 类型语法有其自身的不足,并且由于 NSLayoutConstraint constraintsWithVisualFormat: 返回一个数组,使其动画处理变得更为困难。

准备遇见你的匠人!

以下是使用 MASConstraintMaker 创建的相同约束。

UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
    make.left.equalTo(superview.mas_left).with.offset(padding.left);
    make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
    make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];

或者更短

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(padding);
}];

请注意,在第一个示例中,我们必须将约束添加到父视图:[superview addConstraints:...。然而,Masonry 会自动将约束添加到合适的视图中。

Masonry 也会自动调用 view1.translatesAutoresizingMaskIntoConstraints = NO;

不是所有事物都是平等创造的

.equalTo 等同于 NSLayoutRelationEqual

.lessThanOrEqualTo 等同于 NSLayoutRelationLessThanOrEqual

.greaterThanOrEqualTo 等同于 NSLayoutRelationGreaterThanOrEqual

这三个等式约束接受一个参数,可以是以下之一:

1. MASViewAttribute

make.centerX.lessThanOrEqualTo(view2.mas_left);
MASViewAttribute NSLayoutAttribute
view.mas_left NSLayoutAttributeLeft
view.mas_right NSLayoutAttributeRight
view.mas_top NSLayoutAttributeTop
view.mas_bottom NSLayoutAttributeBottom
view.mas_leading NSLayoutAttributeLeading
view.mas_trailing NSLayoutAttributeTrailing
视图的mas_width NSLayoutAttributeWidth
视图的mas_height NSLayoutAttributeHeight
视图的mas_centerX NSLayoutAttributeCenterX
视图的mas_centerY NSLayoutAttributeCenterY
视图的mas_baseline NSLayoutAttributeBaseline

2. UIView/NSView

如果你想让视图的left边距大于或等于标签的left边距

//these two constraints are exactly the same
make.left.greaterThanOrEqualTo(label);
make.left.greaterThanOrEqualTo(label.mas_left);

3. NSNumber

自动布局允许宽度与高度被设置成固定值。如果你想设置视图的最小和最大宽度,可以向等于块传递一个数字

//width >= 200 && width <= 400
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400)

然而,自动布局不允许设置如left、right、centerY等对齐属性为固定值。所以,如果你传递一个NSNumber给这些属性,Masonry将把它们转换为相对视图父视图的约束,即

//creates view.left = view.superview.left + 10
make.left.lessThanOrEqualTo(@10)

而不是使用NSNumber,你可以使用原始数据类型和结构体来构建约束,如下所示

make.top.mas_equalTo(42);
make.height.mas_equalTo(20);
make.size.mas_equalTo(CGSizeMake(50, 100));
make.edges.mas_equalTo(UIEdgeInsetsMake(10, 0, 10, 0));
make.left.mas_equalTo(view).mas_offset(UIEdgeInsetsMake(10, 0, 10, 0));

默认情况下,支持自动装箱的宏前缀为mas_。在导入Masonry之前定义MAS_SHORTHAND_GLOBALS可以获取无前缀版本。

4. NSArray

任意前述类型的混合数组

make.height.equalTo(@[view1.mas_height, view2.mas_height]);
make.height.equalTo(@[view1, view2]);
make.left.equalTo(@[view1, @100, view3.right]);

学习如何设置优先级

.priority 允许你指定确切优先级

.priorityHigh 等同于 UILayoutPriorityDefaultHigh

.priorityMedium 高低之间的中间值

.priorityLow 等同于 UILayoutPriorityDefaultLow

优先级可以被附加到一个约束链的末尾,如下所示

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

make.top.equalTo(label.mas_top).with.priority(600);

组合,组合,再组合

Masonry还提供了一些便利方法,可以同时创建多个约束。这些方法称为MASCompositeConstraints

边缘

// make top, left, bottom, right equal view2
make.edges.equalTo(view2);

// make top = superview.top + 5, left = superview.left + 10,
//      bottom = superview.bottom - 15, right = superview.right - 20
make.edges.equalTo(superview).insets(UIEdgeInsetsMake(5, 10, 15, 20))

大小

// make width and height greater than or equal to titleLabel
make.size.greaterThanOrEqualTo(titleLabel)

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

中心

// make centerX and centerY = button1
make.center.equalTo(button1)

// make centerX = superview.centerX - 5, centerY = superview.centerY + 10
make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))

你可以将视图属性链式连接以提高可读性

// All edges but the top should equal those of the superview
make.left.right.and.bottom.equalTo(superview);
make.top.equalTo(otherView);

紧紧抓住

有时你需要修改现有的约束以进行动画或者移除/替换约束。在Masonry中有几种不同的方法来更新约束。

1. 引用

你可以通过将约束构建表达式的结果分配给本地变量或类属性来保留特定约束的引用。你还可以通过将它们存储在数组中来引用多个约束。

// in public/private interface
@property (nonatomic, strong) MASConstraint *topConstraint;

...

// when making constraints
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    self.topConstraint = make.top.equalTo(superview.mas_top).with.offset(padding.top);
    make.left.equalTo(superview.mas_left).with.offset(padding.left);
}];

...
// then later you can call
[self.topConstraint uninstall];

2. mas_updateConstraints

或者如果你只是更新约束的常量值,你可以使用方便的mas_updateConstraints方法,而不是使用mas_makeConstraints

// this is Apple's recommended place for adding/updating constraints
// this method can get called multiple times in response to setNeedsUpdateConstraints
// which can be called by UIKit internally or in your code if you need to trigger an update to your constraints
- (void)updateConstraints {
    [self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self);
        make.width.equalTo(@(self.buttonSize.width)).priorityLow();
        make.height.equalTo(@(self.buttonSize.height)).priorityLow();
        make.width.lessThanOrEqualTo(self);
        make.height.lessThanOrEqualTo(self);
    }];

    //according to apple super should be called at end of method
    [super updateConstraints];
}

3. mas_remakeConstraints

mas_updateConstraints对于更新一组约束是有用的,但如果要做的不仅仅是更新常量值,那么会非常耗时。这就是mas_remakeConstraints出现的场合。

mas_remakeConstraintsmas_updateConstraints 类似,但它不是更新常量值,而是在安装之前先删除所有约束。这使得您可以在不保留想要删除的约束引用的情况下提供不同的约束。

- (void)changeButtonPosition {
    [self.button mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.size.equalTo(self.buttonSize);

        if (topLeft) {
        	make.top.and.left.offset(10);
        } else {
        	make.bottom.and.right.offset(-10);
        }
    }];
}

您可以在 Masonry iOS 示例 项目中找到这三种方法的所有更详细的示例。

我应该在哪里创建我的约束?

@implementation DIYCustomView

- (id)init {
    self = [super init];
    if (!self) return nil;

    // --- Create your views here ---
    self.button = [[UIButton alloc] init];

    return self;
}

// tell UIKit that you are using AutoLayout
+ (BOOL)requiresConstraintBasedLayout {
    return YES;
}

// this is Apple's recommended place for adding/updating constraints
- (void)updateConstraints {

    // --- remake/update constraints here
    [self.button remakeConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(@(self.buttonSize.width));
        make.height.equalTo(@(self.buttonSize.height));
    }];
    
    //according to apple super should be called at end of method
    [super updateConstraints];
}

- (void)didTapButton:(UIButton *)button {
    // --- Do your changes ie change variables that affect your layout etc ---
    self.buttonSize = CGSize(200, 200);

    // tell constraints they need updating
    [self setNeedsUpdateConstraints];
}

@end

安装

使用 某些内容CocoaPods

在您的 Podfile 中

pod 'Masonry'

如果您想在没有那些讨厌的 'mas_' 前缀的情况下使用 Masonry,请将 #define MAS_SHORTHAND 添加到您的 prefix.pch 中,然后再导入 Masonry

#define MAS_SHORTHAND

开始 Masonry 的构建

#import "Masonry.h"

代码片段

将包含的代码片段复制到 ~/Library/Developer/Xcode/UserData/CodeSnippets 以闪电般的速度编写您的 Masonry 块!

mas_make -> [<view> mas_makeConstraints:^(MASConstraintMaker *make){<code>}];

mas_update -> [<view> mas_updateConstraints:^(MASConstraintMaker *make){<code>}];

mas_remake -> [<view> mas_remakeConstraints:^(MASConstraintMaker *make){<code>}];

特点

  • 不仅限于 Auto Layout 的子集。任何 NSLayoutConstraint 可以做的事情,Masonry 也可以做到!
  • 优秀的调试支持,为您的视图和约束赋予有意义的名称。
  • 约束就像句子一样阅读。
  • 没有疯狂的宏魔法。Masonry 不会用宏污染全局命名空间。
  • 不是基于字符串或字典的,因此您可以获得编译时检查。

待办事项

  • 眼花缭乱的效果 '
  • Mac示例项目
  • 更多的测试和示例