Masonry框架詳細解析(二) —— 基本結構API和約束入口(一)

版本記錄

版本號 時間
V1.0 2018.07.16

前言

我們做APP界面恶守,也就是布局UI第献,那么關于布局,我們有很多方法兔港,蘋果也都提供了支持庸毫,市場上我們用的并不是系統提供原生的layout,對于OC語言一般都是使用一個第三方的布局框架 —— Masonry衫樊。接下來幾篇我們就一起深入看一下這個框架飒赃。感興趣的看上面幾篇文章利花。
1. Masonry框架詳細解析(一) —— 基本概覽(一)

基本結構和API

首先我們看一下框架的基本結構。

接著载佳,一起看一下API接口

Masonry.h
#import <Foundation/Foundation.h>

//! Project version number for Masonry.
FOUNDATION_EXPORT double MasonryVersionNumber;

//! Project version string for Masonry.
FOUNDATION_EXPORT const unsigned char MasonryVersionString[];

#import "MASUtilities.h"
#import "View+MASAdditions.h"
#import "View+MASShorthandAdditions.h"
#import "ViewController+MASAdditions.h"
#import "NSArray+MASAdditions.h"
#import "NSArray+MASShorthandAdditions.h"
#import "MASConstraint.h"
#import "MASCompositeConstraint.h"
#import "MASViewAttribute.h"
#import "MASViewConstraint.h"
#import "MASConstraintMaker.h"
#import "MASLayoutConstraint.h"
#import "NSLayoutConstraint+MASDebugAdditions.h"

一起看一下這個API框架結構炒事。


約束入口

我們都是對視圖進行約束,所以入口就是一個UIView的分類蔫慧。

View+MASAdditions.h

大家對這個入口應該很熟悉吧

#import "MASUtilities.h"
#import "MASConstraintMaker.h"
#import "MASViewAttribute.h"

/**
 *  Provides constraint maker block
 *  and convience methods for creating MASViewAttribute which are view + NSLayoutAttribute pairs
 */
@interface MAS_VIEW (MASAdditions)

/**
 *  following properties return a new MASViewAttribute with current view and appropriate NSLayoutAttribute
 */
@property (nonatomic, strong, readonly) MASViewAttribute *mas_left;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_top;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_right;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottom;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_leading;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_trailing;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_width;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_height;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerX;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerY;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_baseline;
@property (nonatomic, strong, readonly) MASViewAttribute *(^mas_attribute)(NSLayoutAttribute attr);

#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)

@property (nonatomic, strong, readonly) MASViewAttribute *mas_firstBaseline;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_lastBaseline;

#endif

#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000)

@property (nonatomic, strong, readonly) MASViewAttribute *mas_leftMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_rightMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_topMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_leadingMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_trailingMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerXWithinMargins;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerYWithinMargins;

#endif

#if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 110000) || (__TV_OS_VERSION_MAX_ALLOWED >= 110000)

@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuide API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideTop API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideBottom API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideLeft API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideRight API_AVAILABLE(ios(11.0),tvos(11.0));

#endif

/**
 *  a key to associate with this view
 */
@property (nonatomic, strong) id mas_key;

/**
 *  Finds the closest common superview between this view and another view
 *
 *  @param  view    other view
 *
 *  @return returns nil if common superview could not be found
 */
- (instancetype)mas_closestCommonSuperview:(MAS_VIEW *)view;

/**
 *  Creates a MASConstraintMaker with the callee view.
 *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing
 *
 *  @param block scope within which you can build up the constraints which you wish to apply to the view.
 *
 *  @return Array of created MASConstraints
 */
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

/**
 *  Creates a MASConstraintMaker with the callee view.
 *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.
 *  If an existing constraint exists then it will be updated instead.
 *
 *  @param block scope within which you can build up the constraints which you wish to apply to the view.
 *
 *  @return Array of created/updated MASConstraints
 */
- (NSArray *)mas_updateConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

/**
 *  Creates a MASConstraintMaker with the callee view.
 *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.
 *  All constraints previously installed for the view will be removed.
 *
 *  @param block scope within which you can build up the constraints which you wish to apply to the view.
 *
 *  @return Array of created/updated MASConstraints
 */
- (NSArray *)mas_remakeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

@end

這里有幾點需要說明:

1. 幾個屬性

首先我們看一下幾個屬性

/**
 *  following properties return a new MASViewAttribute with current view and appropriate NSLayoutAttribute
 */
@property (nonatomic, strong, readonly) MASViewAttribute *mas_left;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_top;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_right;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottom;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_leading;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_trailing;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_width;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_height;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerX;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerY;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_baseline;
@property (nonatomic, strong, readonly) MASViewAttribute *(^mas_attribute)(NSLayoutAttribute attr);

這里挠乳,這些屬性返回一個當前view的一個新的MASViewAttribute以及合適的NSLayoutAttribute

我們先看一下這個返回的MASViewAttribute對象

/**
 *  An immutable tuple which stores the view and the related NSLayoutAttribute.
 *  Describes part of either the left or right hand side of a constraint equation
 */
@interface MASViewAttribute : NSObject

這個對象是一個存儲視圖和相關NSLayoutAttribute的不可變元組姑躲。描述約束方程左側或右側的一部分睡扬。

2. 宏判斷

接著就是幾個宏判斷。

#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)

@property (nonatomic, strong, readonly) MASViewAttribute *mas_firstBaseline;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_lastBaseline;

#endif

#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000)

@property (nonatomic, strong, readonly) MASViewAttribute *mas_leftMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_rightMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_topMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_leadingMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_trailingMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerXWithinMargins;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerYWithinMargins;

#endif

#if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 110000) || (__TV_OS_VERSION_MAX_ALLOWED >= 110000)

@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuide API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideTop API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideBottom API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideLeft API_AVAILABLE(ios(11.0),tvos(11.0));
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideRight API_AVAILABLE(ios(11.0),tvos(11.0));

#endif

可能有人會問黍析,這塊是做什么的卖怜,其實就是根據不同系統定義的不同屬性,比如說11系統出來的safeAreaLayoutGuide阐枣,這個就只有在11系統中使用马靠,所以才需要進行版本判斷。

// 表示系統大于8.0
__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000

// 當前SDK的最高版本, 在手機上, 就是該手機上支持的SDK最高版本侮繁,這里表示最大的支持的版本是11.0
__IPHONE_OS_VERSION_MAX_ALLOWED >= 110000

3. 幾個重要入口方法

下面這幾個方法大家都用過虑粥,也是Masonry應用的基本入口,下面我們就分著看一下宪哩。

1)尋找兩個視圖的最近的父視圖

/**
 *  Finds the closest common superview between this view and another view
 *
 *  @param  view    other view
 *
 *  @return returns nil if common superview could not be found
 */
- (instancetype)mas_closestCommonSuperview:(MAS_VIEW *)view;

該方法的作用就是尋找本視圖和另外一個視圖最近的父視圖娩贷。這個我們用的其實比較少,大家熟悉理解下就好锁孟。

2)make構建約束

我們一般使用下面這個方法構建約束彬祖。

/**
 *  Creates a MASConstraintMaker with the callee view.
 *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing
 *
 *  @param block scope within which you can build up the constraints which you wish to apply to the view.
 *
 *  @return Array of created MASConstraints
 */
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

這個方法大家基本都用過,也是最熟悉的品抽,就是用來進行約束的储笑。該方法根據傳入的view創(chuàng)建一個MASConstraintMaker,一旦block結束執(zhí)行圆恤,任何定義的約束都被添加到view或者合適的superview上突倍。返回值就是一個創(chuàng)建的MASConstraints數組。

3)update約束

/**
 *  Creates a MASConstraintMaker with the callee view.
 *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.
 *  If an existing constraint exists then it will be updated instead.
 *
 *  @param block scope within which you can build up the constraints which you wish to apply to the view.
 *
 *  @return Array of created/updated MASConstraints
 */
- (NSArray *)mas_updateConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

該方法根據傳入的view創(chuàng)建一個MASConstraintMaker盆昙,一旦block結束執(zhí)行羽历,任何定義的約束都被添加到view或者合適的superview上。如果一個約束存在淡喜,那么它會替代到本次更新的約束秕磷。返回值是一個創(chuàng)建的/更新的約束的數組。

4)remake約束

/**
 *  Creates a MASConstraintMaker with the callee view.
 *  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.
 *  All constraints previously installed for the view will be removed.
 *
 *  @param block scope within which you can build up the constraints which you wish to apply to the view.
 *
 *  @return Array of created/updated MASConstraints
 */
- (NSArray *)mas_remakeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

該方法用于根據傳入的view創(chuàng)建一個MASConstraintMaker炼团,一旦block結束執(zhí)行澎嚣,任何定義的約束都被添加到view或者合適的superview上疏尿。該view的所有以前的約束都將被remove掉,返回值是一個創(chuàng)建的/更新的約束的數組易桃。該方法與update的區(qū)別是褥琐,update是更新相同的約束,而remake是完全刪除以前的約束晤郑,使用本次重新創(chuàng)建的約束踩衩。


你為什么可以make很多個布局屬性

其實這個是一個響應式編程的問題,我們在使用的時候一般都是下面這種類似的使用方式贩汉。

make.height.width.equalTo(@(100));

這里的make其實是block的回調,帶的類型的參數MASConstraintMaker锚赤,MASConstraintMaker從名字上大家都可以猜測的差不多匹舞,這個其實就是進行約束的工廠方法。

@property (nonatomic, strong, readonly) MASConstraint *width;
@property (nonatomic, strong, readonly) MASConstraint *height;

...  ...

當我們調用make.height的時候其實就是實現了下面這個方法

- (MASConstraint *)height {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}

該getter方法返回的是一個MASConstraint對象线脚,
然后調用.width方法赐稽,就會調用MASConstraint對象中width的getter方法。

/**
 *  Creates a new MASCompositeConstraint with the called attribute and reciever
 */
- (MASConstraint *)width;

getter方法實現如下所示:

- (MASConstraint *)width {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];
}

大家可以看見返回的仍然是MASConstraint浑侥,所以你就一直可以點語法進行約束姊舵。

關于這個以后會分篇幅進行詳細的說明,這里只是簡單的提一下寓落。

參考文章

1. __IPHONE_OS_VERSION_MIN_REQUIRED 和 __IPHONE_OS_VERSION_MAX_ALLOWED
2. iOS開發(fā)之Masonry框架源碼解析

后記

本篇主要講述了基本結構API和約束入口括丁,感興趣的給個贊或者關注~~~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市伶选,隨后出現的幾起案子史飞,更是在濱河造成了極大的恐慌,老刑警劉巖仰税,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件构资,死亡現場離奇詭異,居然都是意外死亡陨簇,警方通過查閱死者的電腦和手機吐绵,發(fā)現死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來河绽,“玉大人己单,你說我怎么就攤上這事】眩” “怎么了荷鼠?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長榔幸。 經常有香客問我允乐,道長矮嫉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任牍疏,我火速辦了婚禮蠢笋,結果婚禮上,老公的妹妹穿的比我還像新娘鳞陨。我一直安慰自己昨寞,他們只是感情好,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布厦滤。 她就那樣靜靜地躺著援岩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掏导。 梳的紋絲不亂的頭發(fā)上享怀,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音趟咆,去河邊找鬼添瓷。 笑死,一個胖子當著我的面吹牛值纱,可吹牛的內容都是我干的鳞贷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼虐唠,長吁一口氣:“原來是場噩夢啊……” “哼搀愧!你這毒婦竟也來了?” 一聲冷哼從身側響起疆偿,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤妈橄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后翁脆,有當地人在樹林里發(fā)現了一具尸體眷蚓,經...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年反番,在試婚紗的時候發(fā)現自己被綠了沙热。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡罢缸,死狀恐怖篙贸,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情枫疆,我是刑警寧澤爵川,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站息楔,受9級特大地震影響寝贡,放射性物質發(fā)生泄漏扒披。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一圃泡、第九天 我趴在偏房一處隱蔽的房頂上張望碟案。 院中可真熱鬧,春花似錦颇蜡、人聲如沸价说。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳖目。三九已至,卻和暖如春缤弦,著一層夾襖步出監(jiān)牢的瞬間疑苔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工甸鸟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人兵迅。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓抢韭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親恍箭。 傳聞我的和親對象是個殘疾皇子刻恭,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內容