實(shí)時(shí)顯示iOS編寫(xiě)UI代碼效果

編寫(xiě)iOS應(yīng)用UI的方式大概有兩種葵孤,一種是Storyboard/Xib,另一種是手寫(xiě)代碼沙郭。采用Storyboard/Xib方式組織UI佛呻,由于提供可視化的特性,只要從UI庫(kù)中拖動(dòng)UI控件病线,便可以顯示結(jié)果吓著,極大地提高開(kāi)發(fā)速度。但面臨一個(gè)問(wèn)題就是多人協(xié)作開(kāi)發(fā)送挑,由于所有的UI都放在同一個(gè)Storyboard文件中绑莺,使用Git/SVN合并代碼就會(huì)出現(xiàn)沖突。多人協(xié)作開(kāi)發(fā)還不是主要問(wèn)題惕耕,有人提出可以創(chuàng)建多個(gè)Storyboard來(lái)分開(kāi)UI編寫(xiě)纺裁,而Storyboard/Xib最主要問(wèn)題是代碼復(fù)用性比較差。所以有些人就選擇手寫(xiě)UI代碼司澎,這樣不僅可以解決多人協(xié)作開(kāi)發(fā)問(wèn)題欺缘,而且通過(guò)自定義控件在多個(gè)View使用。但每次手寫(xiě)UI代碼后都要編譯挤安、構(gòu)建和運(yùn)行谚殊,最后在模擬器顯示,這樣會(huì)拖慢開(kāi)發(fā)速度蛤铜。如果每次修改UI控件后嫩絮,保存修改便實(shí)時(shí)在模擬器顯示修改后結(jié)果,就可以極大的提高編寫(xiě)UI的速度围肥。


Live Change.gif

Auto Layout

Auto Layout是什么

Auto Layout是一個(gè)基于constraint(約束)的布局系統(tǒng)剿干,它根據(jù)UI元素之間約束關(guān)系來(lái)調(diào)整UI元素的位置和大小。

Auto Layout解決什么問(wèn)題

  • 更容易適配不同分辨率設(shè)備的屏幕(iPhone 6 Plus, iPhone 6, iPhone 5s/5, iPhone 4s/4)
  • 當(dāng)設(shè)備旋轉(zhuǎn)時(shí)不需要做額外處理
  • 使用constraint來(lái)描述布局邏輯穆刻,更利于理解和清晰

如何使用Auto Layout

Auto Layout中約束的類對(duì)應(yīng)是NSLayoutConstraint, 而創(chuàng)建NSLayoutConstraint對(duì)象主要有兩種方式置尔,第一種是

+ (id)constraintWithItem:(id)view1
               attribute:(NSLayoutAttribute)attribute1
               relatedBy:(NSLayoutRelation)relation
                  toItem:(id)view2
               attribute:(NSLayoutAttribute)attribute2
              multiplier:(CGFloat)multiplier
                constant:(CGFloat)constant;

上面方法主要意思是,某個(gè)view1的attribute1等于(小于或等于/大于或等于)某個(gè)view2的attribute2的multiplier倍加上constant氢伟。而attribute主要由表示位置(上/下/左/右)和大小(寬/高)的以下幾個(gè)值:

typedef enum: NSInteger {
   NSLayoutAttributeLeft = 1,
   NSLayoutAttributeRight,
   NSLayoutAttributeTop,
   NSLayoutAttributeBottom,
   NSLayoutAttributeLeading,
   NSLayoutAttributeTrailing,
   NSLayoutAttributeWidth,
   NSLayoutAttributeHeight,
   NSLayoutAttributeCenterX,
   NSLayoutAttributeCenterY,
   NSLayoutAttributeBaseline,
   NSLayoutAttributeNotAnAttribute = 0
} NSLayoutAttribute;

簡(jiǎn)化一下撰洗,使用公式可以表達(dá)為:

view1.attribute1 = view2.attribute2 * multiplier + constant

第二種方式是:

+ (NSArray *)constraintsWithVisualFormat:(NSString *)format 
                                 options:(NSLayoutFormatOptions)opts 
                                 metrics:(NSDictionary *)metrics 
                                   views:(NSDictionary *)views;

這種方式主要是采用Visual Format Language(可視化格式語(yǔ)言)來(lái)描述約束布局,雖然語(yǔ)法比較簡(jiǎn)潔腐芍,但是可讀性比較差和容易出錯(cuò)差导。

Auto Layout存在問(wèn)題

雖然Auto Layout在布局view方面是非常強(qiáng)大和靈活,但是創(chuàng)建constraint的語(yǔ)法過(guò)于繁雜猪勇,引用Masonry一個(gè)例子:

UIView *superview = self;

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],

 ]];

如此簡(jiǎn)單的一個(gè)例子都要編寫(xiě)這么多行代碼设褐,想象一下如果創(chuàng)建多個(gè)view的constraint時(shí)會(huì)多么痛苦啊。另一個(gè)方式是采用Visual Format Language (VFL),雖然語(yǔ)法比較簡(jiǎn)潔助析,但是可讀性比較差和容易出錯(cuò)犀被。

Masonry

為什么使用Masonry

Masonry是采用鏈?zhǔn)?a target="_blank" rel="nofollow">DSL(Domain-specific language)來(lái)封裝NSLayoutConstraint,通過(guò)這種方式編寫(xiě)Auto Layout布局代碼更加易讀和簡(jiǎn)潔外冀。
使用Masonry的MASConstraintMaker來(lái)表達(dá)相同constraint

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);
}];

如何使用

使用Masonry創(chuàng)建constraint來(lái)定義布局的方式有三種:mas_makeConstraints寡键,mas_updateConstraintsmas_remakeConstraints雪隧。

1. mas_makeConstraints

使用mas_makeConstraints創(chuàng)建constraint后西轩,你可以使用局部變量或?qū)傩詠?lái)保存以便下次引用它;如果創(chuàng)建多個(gè)constraints脑沿,你可以采用數(shù)組來(lái)保存它們藕畔。

// 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

有時(shí)你需要更新constraint(例如,動(dòng)畫(huà)和調(diào)試)而不是創(chuàng)建固定constraint庄拇,可以使用mas_updateConstraints方法

// 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_remakeConstraintsmas_updateConstraints比較相似注服,都是更新constraint。不過(guò)措近,mas_remakeConstraints是刪除之前constraint溶弟,然后再添加新的constraint(適用于移動(dòng)動(dòng)畫(huà));而mas_updateConstraints只是更新constraint的值瞭郑。

- (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);
        }
    }];
}

想了解以上三個(gè)代碼片段的更多細(xì)節(jié)辜御,可以下載Masonry iOS Examples工程查閱。

Classy

Classy簡(jiǎn)介和特性

Classy是一個(gè)能與UIKit無(wú)縫結(jié)合stylesheet(樣式)系統(tǒng)凰浮。它借鑒CSS的思想我抠,但引入新的語(yǔ)法和命名規(guī)則苇本。

靈活內(nèi)嵌的語(yǔ)法

{ } : ; 這些語(yǔ)法符號(hào)是可選的袜茧,你可以選擇適合自己的風(fēng)格來(lái)表達(dá)stylesheet。

你可以使用{ } : ; 來(lái)限定stylesheet

$main-color = #e1e1e1;

MYCustomView {
 background-color: $main-color;
 title-insets: 5, 10, 5, 10;
 > UIProgressView.tinted {
   progress-tint-color: black;
   track-tint-color: yellow;
 }
}

^UIButton.warning, UIView.warning ^UIButton {
 title-color[state:highlighted]: #e3e3e3;
}

或者你使用空格來(lái)限定stylesheet

$main-color = #e1e1e1

MYCustomView 
  background-color $main-color
  title-insets 5, 10, 5, 10
  > UIProgressView.tinted 
    progress-tint-color black
    track-tint-color yellow

^UIButton.warning, UIView.warning ^UIButton 
  title-color[state:highlighted] #e3e3e3

默認(rèn)樣式

Classy在應(yīng)用程序Bundle默認(rèn)查找文件名為stylesheet.cas的樣式文件瓣窄。如果你采用這個(gè)文件名笛厦,你可以不用做任何東西就能加載樣式文件。
但如果你想指定其他file path(樣式文件名)俺夕,你可以創(chuàng)建[CASStyler defaultStyler]

[CASStyler defaultStyler].filePath = [[NSBundle mainBundle] pathForResource:@"myStyles.cas" ofType:nil];

如果你還想當(dāng)發(fā)生錯(cuò)誤時(shí)裳凸,獲取錯(cuò)誤信息以便于調(diào)試,可以使用-(void)setFilePath:error:

NSError *error = nil;
NSString filePath = [[NSBundle mainBundle] pathForResource:@"myStyles.cas" ofType:nil];
[[CASStyler defaultStyler] setFilePath:filePath error:&error];

如果你是使用Storyboard/Xib組織UI界面劝贸,那就需要在main.mint main(int argc, char * argv[])方法設(shè)置** filePath姨谷,這樣可以確保在創(chuàng)建UIWindow之前加載stylesheet。否則(采用手寫(xiě)UI代碼)映九,你在 AppDelegate.m- (BOOL)application:didFinishLaunchingWithOptions:方法設(shè)置filePath**

Live Reload

Live Reload是實(shí)時(shí)顯示編寫(xiě)UI代碼效果的關(guān)鍵特性梦湘,它能夠?qū)崟r(shí)檢查stylesheet文件變化,無(wú)需重新編譯、構(gòu)建和運(yùn)行模擬器捌议,從而極大提高開(kāi)發(fā)速度哼拔。
為了啟用Live Reload,你需要指定stylesheet路徑瓣颅,并且只運(yùn)行在模擬器上倦逐。

#if TARGET_IPHONE_SIMULATOR
    NSString *absoluteFilePath = CASAbsoluteFilePath(@"../Styles/stylesheet.cas");
    [CASStyler defaultStyler].watchFilePath = absoluteFilePath;
#endif

Selectors

Style Selectors是指定哪個(gè)view使用哪種樣式的方式。主要有三種方法來(lái)指定目標(biāo)view:

  1. Object Class
  2. View Hierarchy
  3. Style Class

你可以混合使用三種方法宫补,例子如下:

/* match views
 * where class is UIButton or UIButton subclass
 * and styleClass is "large"
 * and superview class is UITabBar
 */
 
UITabBar > ^UIButton.large { }

想了解具體如何使用檬姥,請(qǐng)查閱官網(wǎng)Selectors章節(jié)

為了避免與Objective-C的message selectors混淆,術(shù)語(yǔ)style selectors表示Classy stylesheets的selectors

Properties

Classy支持所有UIAppearance的屬性和方法守谓,也支持與UIAppearance無(wú)關(guān)的很多屬性穿铆。Classy使用與UIKit相同屬性命名,所以你不必考慮如何將style property映射到Objective-C的property斋荞。
UIPageControl類的屬性如下:

@property (nonatomic,retain) UIColor *pageIndicatorTintColor;
@property (nonatomic,retain) UIColor *currentPageIndicatorTintColor;

style property的名字采用與objective-c一樣的名字

UIPageControl {
  pageIndicatorTintColor black
  currentPageIndicatorTintColor purple
}

style property的命名規(guī)則采用kebab case

UIPageControl {
  page-indicator-tint-color black
  current-page-indicator-tint-color purple
}

想了解具體如何使用荞雏,請(qǐng)查閱官網(wǎng)Properties章節(jié)

Keep it DRY(Don't Repeat Yourself)

在編程中一個(gè)很重要的原則就是避免重復(fù),這不僅可以大量減少重復(fù)代碼平酿,并且使得代碼更加容易復(fù)用和維護(hù)凤优。Classy提供三種方式避免代碼重復(fù):grouping, nestingvariables

Grouping

如果有兩個(gè)以上的style selectors共用相同的屬性時(shí)

UISlider.info {
  minimum-track-tint-color black
  maximum-track-tint-color purple
}

UISlider.error {
  minimum-track-tint-color black
  maximum-track-tint-color purple
  thumb-tint-color red
}

我們可以提取相同的屬性到分組style selector中

UISlider.info, UISlider.error {
  minimum-track-tint-color black
  maximum-track-tint-color purple
}

UISlider.error {
  thumb-tint-color red
}
Nesting

如果兩個(gè)以上style selectors共用相同的view hierarchy時(shí)

UICollectionView {
  background-color #a2a2a2
}

UICollectionView > UICollectionViewCell {
  clips-to-bounds NO
}

UICollectionView > UICollectionViewCell UILabel {
  text-color purple
}

UICollectionView > UICollectionViewCell UILabel.title {
  font 20
}

我們通過(guò)nesting方式將view hierarchies表達(dá)成這樣方式

UICollectionView {
  background-color #a2a2a2
  
  > UICollectionViewCell {
    clips-to-bounds NO
    
    UILabel {
      text-color purple
      
      &.title {
        font 20
      }
    }
  }
}
Variables

Classy讓你通過(guò)定義variables來(lái)將多個(gè)相同的style property值存儲(chǔ)以便共享蜈彼。Variable命名規(guī)則如下:

  • 必須以大小寫(xiě)字母$符號(hào)開(kāi)頭
  • 可以包含_筑辨,-或任何字母數(shù)字
// prefix with ' $ ' to help distinguish variables
$brand-color = #e1e1e1

// OR not
insets = 5, 10, 5, 10

UIButton {
   background-color $brand-color
   contentEdgeInsets insets
   background-image[state:selected] bg_button insets
}

最后官方還提供一個(gè)實(shí)例來(lái)解釋具體如何使用:Custom Views Example

ClassyLiveLayout

ClassyLiveLayout通過(guò)結(jié)合Classy stylesheets與Masonry一起使用,能夠在運(yùn)行的模擬器中微調(diào)Auto Layout約束實(shí)時(shí)顯示效果的工具幸逆。

ClassyLiveLayout一個(gè)核心category:UIView+ClassyLayoutProperties棍辕,在UIView定義以下屬性:

@property(nonatomic, assign) UIEdgeInsets cas_margin;
@property(nonatomic, assign) CGSize cas_size;

// shorthand properties for setting only a single constant value
@property(nonatomic, assign) CGFloat cas_sizeWidth;
@property(nonatomic, assign) CGFloat cas_sizeHeight;

@property(nonatomic, assign) CGFloat cas_marginTop;
@property(nonatomic, assign) CGFloat cas_marginLeft;
@property(nonatomic, assign) CGFloat cas_marginBottom;
@property(nonatomic, assign) CGFloat cas_marginRight;

cas_margincas_size分別表示UI元素的位置和大小,而其余的屬性都是對(duì)兩個(gè)屬性進(jìn)一步細(xì)分还绘。我們可以從stylesheets中訪問(wèn)style properties來(lái)定義constraints布局楚昭,做到將數(shù)據(jù)與代碼分離,有利于修改和復(fù)用代碼拍顷。

UIView.blue-box {
    cas_size: 80 100
    cas_margin-top: 60
    cas_margin-left: 50
}

UIView.red-box {
    cas_size-width: 120
    cas_margin-left: 20
}

我們可以在updateConstraintsupdateViewConstrains定義布局時(shí)引用style properties

- (void)updateViewConstraints {
  [super updateViewConstraints];

  [_blueBoxView mas_updateConstraints:^(MASConstraintMaker *make) {
      make.width.equalTo(@(_blueBoxView.cas_size.width));
      make.height.equalTo(@(_blueBoxView.cas_size.height));
      make.top.equalTo(@(_blueBoxView.cas_margin.top));
      make.left.equalTo(@(_blueBoxView.cas_margin.left));
  }];

  [_redBoxView mas_updateConstraints:^(MASConstraintMaker *make) {
      make.width.equalTo(@(_redBoxView.cas_size.width));
      make.height.equalTo(_blueBoxView);
      make.top.equalTo(_blueBoxView);
      make.left.equalTo(_blueBoxView.mas_right).with.offset(_redBoxView.cas_margin.left);
  }];
}

當(dāng)定義view layouts時(shí)抚太,將Auto Layout的constraints都放在stylesheets中實(shí)時(shí)加載(Live reload)。如果你修改constraints昔案,無(wú)需重新編譯尿贫、構(gòu)建和運(yùn)行模擬器便能實(shí)時(shí)看到修改后的效果。

示例工程

配置工程

由于需要引用Masonry踏揣,Classy和ClassyLiveLayout庆亡,Podfile配置如下:

pod 'Masonry', '~> 0.6.1'
pod 'Classy', '~> 0.2.4'
pod 'ClassyLiveLayout', '~> 0.6.0'

編寫(xiě)代碼

1. 添加stylesheet.cas文件到工程

當(dāng)安裝好Masonry,Classy和ClassyLiveLayout后捞稿,第一次運(yùn)行項(xiàng)目會(huì)出現(xiàn)沒(méi)有stylesheet.cas文件錯(cuò)誤:


No stylesheet.cas file error.png

只要向工程添加空的stylesheet.cas文件即可又谋。


Create stylesheet.cas file.png
2. 創(chuàng)建LiveView類钝尸,該類繼承SHPAbstractView

Create LiveView inherit SHPAbstractView.png

ViewController創(chuàng)建LiveView對(duì)象搂根,然后被self.view引用珍促。

Setup root view in ViewController.png

當(dāng)編譯運(yùn)行時(shí),在SHPAbstractView.h由于找不到UIView出現(xiàn)編譯錯(cuò)誤剩愧。
SHPAbstractView Compile error.png

只需引入U(xiǎn)IKit便可以解決猪叙,但運(yùn)行一下應(yīng)用程序,出現(xiàn)一下錯(cuò)誤:
Must override methods.png

主要原因是任何自定義UIView繼承SHPAbstractView都需要override兩個(gè)方法:- (void)addSubviews- (void)defineLayout仁卷,我們可以查看SHPAbstractView的源碼可知:

SHPAbstractView Source Code .png

所以只要在LiveView.m文件覆蓋兩個(gè)方法即可

#pragma mark - Add subviews and define layout
- (void)addSubviews
{
}

- (void)defineLayout
{
}
3. LiveView類設(shè)計(jì)

LiveView主要由包含redBoxViewblueBoxView兩個(gè)屬性穴翩,redBoxView表示紅色方塊,blueBoxView表示藍(lán)色方塊锦积。

#import "SHPAbstractView.h"

@interface LiveView : SHPAbstractView

@property (strong, nonatomic) UIView *redBoxView;
@property (strong, nonatomic) UIView *blueBoxView;

@end

4. LiveView類實(shí)現(xiàn)

由于SHPAbstractView類如何初始化View已經(jīng)做了處理芒帕,暴露兩個(gè)接口- (void)addSubviews-(void)defineLayout分別處理構(gòu)建view hierarchy和定義布局,子類只要覆蓋SHPAbstractView這兩個(gè)方法就可以創(chuàng)建LiveView了丰介。
但是我們將Auto Layout的constraints都放在stylesheets中實(shí)時(shí)加載(Live reload)背蟆,即放在本工程的stylesheet.cas文件,將布局?jǐn)?shù)據(jù)和布局代碼分離哮幢。

UIView.redBox {
    cas_marginTop 50
    cas_marginLeft 20

    cas_size 100 100
}

UIView.blueBox {
    cas_marginTop 50
    cas_marginRight -20

    cas_size 100 100
}

有了constraints數(shù)據(jù)后带膀,便可以在代碼布局:

@implementation LiveView

#pragma mark - Add subviews and define layout
- (void)addSubviews
{
    self.backgroundColor = [UIColor whiteColor];
    [self addSubview:self.redBoxView];
    [self addSubview:self.blueBoxView];
}

- (void)defineLayout
{
    [self.redBoxView mas_updateConstraints:^(MASConstraintMaker* make){
        make.top.equalTo(@(self.redBoxView.cas_marginTop));
        make.left.equalTo(@(self.redBoxView.cas_marginLeft));
        make.width.equalTo(@(self.redBoxView.cas_sizeWidth));
        make.height.equalTo(@(self.redBoxView.cas_sizeHeight));
    }];
    
    [self.blueBoxView mas_updateConstraints:^(MASConstraintMaker *make){
        make.top.equalTo(@(self.blueBoxView.cas_marginTop));
        make.right.equalTo(@(self.blueBoxView.cas_marginRight));
        make.width.equalTo(@(self.blueBoxView.cas_sizeWidth));
        make.height.equalTo(@(self.blueBoxView.cas_sizeHeight));
    }];
}

#pragma mark - Lazy initialization
- (UIView*)redBoxView
{
    if (!_redBoxView) {
        _redBoxView = [UIView new];
        _redBoxView.cas_styleClass = @"redBox";
        _redBoxView.backgroundColor = [UIColor redColor];
    }
    
    return _redBoxView;
}

- (UIView*)blueBoxView
{
    if (!_blueBoxView) {
        _blueBoxView = [UIView new];
        _blueBoxView.cas_styleClass = @"blueBox";
        _blueBoxView.backgroundColor = [UIColor blueColor];
    }
    
    return _blueBoxView;
}
5. 模擬器支持Live Reload

為了啟用Live Reload,你需要指定stylesheet路徑橙垢,并且只運(yùn)行在模擬器上垛叨。

Support Live Reload.png

此時(shí)效果:

Live Change.gif

6. 分離樣式文件

由于有網(wǎng)友提出這樣一個(gè)問(wèn)題:如果所有view的樣式都放在同一個(gè)stylesheet.cas文件,會(huì)讓stylesheet.cas文件繁雜柜某,并且當(dāng)多個(gè)人協(xié)同開(kāi)發(fā)時(shí)嗽元,不易于合并代碼,所以有必要將樣式文件分離到多個(gè)文件中喂击。

  1. 創(chuàng)建variable.cas文件剂癌,并將redBox對(duì)應(yīng)UIView的樣式放在variable.cas文件中。

    variable.cas file.png

  2. stylesheet.cas樣式文件使用@import指令引用variable.cas文件

stylesheet.cas file.png

最后效果

Live Change 1.gif
Live Change 2.gif

示例代碼存放地址:LiveAutoLayout

總結(jié)

之前手寫(xiě)UI代碼每次更改一般都要重新編譯惭等、構(gòu)建和運(yùn)行模擬器才能看到效果珍手,但結(jié)合使用Masonry办铡,Classy和ClassLiveLayout之后辞做,告別這個(gè)費(fèi)時(shí)過(guò)程,極大地提高開(kāi)發(fā)速度寡具;不僅如此秤茅,我們將Auto Layout的constraints都放在stylesheets中實(shí)時(shí)加載(Live reload),將布局?jǐn)?shù)據(jù)和布局代碼分離童叠,使得代碼更加復(fù)用和維護(hù)框喳。Classy還提供三種避免重復(fù)方法:Grouping, Nestting和Variable课幕,盡可能復(fù)用樣式數(shù)據(jù)。
這是本人第一次編寫(xiě)技術(shù)博客五垮,可能有很多錯(cuò)誤和漏洞乍惊,希望大家多多指點(diǎn),也希望這篇文章能夠幫助到大家放仗。

擴(kuò)展閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莉撇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惶傻,更是在濱河造成了極大的恐慌棍郎,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件银室,死亡現(xiàn)場(chǎng)離奇詭異涂佃,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蜈敢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)巡李,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人扶认,你說(shuō)我怎么就攤上這事侨拦。” “怎么了辐宾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵狱从,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我叠纹,道長(zhǎng)季研,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任誉察,我火速辦了婚禮与涡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘持偏。我一直安慰自己拍鲤,他們只是感情好袄秩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般溯香。 火紅的嫁衣襯著肌膚如雪事秀。 梳的紋絲不亂的頭發(fā)上惠呼,一...
    開(kāi)封第一講書(shū)人閱讀 48,954評(píng)論 1 283
  • 那天,我揣著相機(jī)與錄音恳守,去河邊找鬼。 笑死贩虾,一個(gè)胖子當(dāng)著我的面吹牛催烘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缎罢,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼颗圣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了屁使?” 一聲冷哼從身側(cè)響起在岂,我...
    開(kāi)封第一講書(shū)人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛮寂,沒(méi)想到半個(gè)月后蔽午,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酬蹋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年及老,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片范抓。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骄恶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出匕垫,到底是詐尸還是另有隱情僧鲁,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布象泵,位于F島的核電站寞秃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏偶惠。R本人自食惡果不足惜春寿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忽孽。 院中可真熱鬧绑改,春花似錦、人聲如沸兄一。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瘾腰。三九已至皆的,卻和暖如春覆履,著一層夾襖步出監(jiān)牢的瞬間蹋盆,已是汗流浹背费薄。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留栖雾,地道東北人楞抡。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像析藕,于是被迫代替她去往敵國(guó)和親召廷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)账胧、插件竞慢、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,022評(píng)論 4 62
  • 昨天上的補(bǔ)丁交叉檢查沒(méi)做好!今天處理了幾個(gè)問(wèn)題還差保存的治泥,還有還款單的bug以及bug系統(tǒng)的bug.
    zzzzw閱讀 208評(píng)論 0 0
  • 利安人壽保險(xiǎn)公司經(jīng)常組織客戶外出旅游筹煮,我的好朋友就是公司客戶經(jīng)理,這次應(yīng)她之邀居夹,我們一起去安徽九華山腳下佛緣...
    上善若水南京人閱讀 459評(píng)論 1 3
  • 每日一畫(huà)100.86:世界給我以灰暗准脂,我還世界以顏色 最近在繪畫(huà)過(guò)程中劫扒,似乎體察到一直都存在卻被我忽略的一些東西。...
    費(fèi)漠塵閱讀 688評(píng)論 3 2
  • 費(fèi)城的第一個(gè)春日狸膏,阿加莎從監(jiān)獄里逃了出來(lái)沟饥。此時(shí)的她已經(jīng)在監(jiān)獄里老老實(shí)實(shí)地待了30年,在過(guò)很短的時(shí)間湾戳,就可以刑滿釋放...
    水婉汝閱讀 2,024評(píng)論 0 3