iOS 第三方框架-Masonry 的视图模块化

来源:互联网 发布:excel2016数据分析在哪 编辑:程序博客网 时间:2024/05/17 00:15

Masonry,是一个基于纯代码的AutoLayout库.初次涉及时,只是感觉它很方便,既有Xib的易读性,又有纯代码的灵活性.试用一段时间之后,突然想到: 或许借助Masonry,建立一个纯代码的不依赖Xib的AutoLayout视图组件机制.

GitHub地址:https://github.com/SnapKit/Masonry

Masonry安装:

source 'https://github.com/CocoaPods/Specs.git'platform :ios, "8.0"use_frameworks!target :testMasonry  pod 'Masonry'

目前能得到的效果

  • 视图基于 AutoLayout;
  • 视图自动适配不同屏幕尺寸;
  • 视图完全独立于数据与业务逻辑;
  • 视图严肃仅与父视图有位置关系;
  • 可以将视图模块的元素与模块同名属性自动关联;
  • 仅需知道父视图的宽高,模块内某一个UI元素的宽高, UI元素的 bottom 与 right, 就可以唯一确定任意元素的位置.

核心理论基础: AutoLayout中,如何唯一确定元素在不同尺寸屏幕上的位置?

  • 既定方案,必须基于AutoLayout,至于AutoLayout与Frame的区别于优势,不做赘述.

  • 在不考虑多屏幕兼容的情况下, AutoLayout,可以直接使用固定的约束常量值来确定,但是 马上iPhone 7 都要出来了,指不定什么尺寸呢? 一个机型,一个UI代码?是不是想想都让人头大!

  • 考虑到多屏幕尺寸,UI设计图等比缩放的常用情况,我分享一个可以唯一确定UI元素的方案:

[subView makeConstraints:^(MASConstraintMaker *make) {    UIView * superView = subView.superview;    make.width.equalTo(superView).multipliedBy(subWidth / superWidth);    make.height.equalTo(superView).multipliedBy(subHeight / superHeight);    make.right.equalTo(superView).multipliedBy(subRight / superWidth);    make.bottom.equalTo(superView).multipliedBy(subBottom / superHeight);}];

以上代码,是整个代码的核心,其巧妙之处在于:不使用constant,而是使用比例来指定约束.选取的是 width,height,right,bottom,而不是其他属性,其巧妙之处,大家试用下其他属性就知道了.


核心代码,打造自己的视图模块库.

直接继承YFViewComponent类,然后实现类方法 subViewsConfig 即可.

////  YFViewComponent.h//  testMasonry////  Created by xiao on 16/6/6.//  Copyright © 2016年 xiao. All rights reserved.//#import <UIKit/UIKit.h>/** *  预定义常量的声明. *///!< 同一设计图中,视图模块本身的宽度.extern const NSString *  YFViewComponentSelfHolderWidthKey;//!< 同一设计图中,视图模块本身的高度.extern const NSString *  YFViewComponentSelfHolderHeightKey;//!< 同一设计图中,模块的所有子视图.extern const NSString *  YFViewComponentSubViewsKey;//!< 子视图的类型.extern const NSString *  YFViewComponentSubViewClassNameKey;//!< 子视图对应的属性,模块中应有属性与其对应,且可通过此属性访问对应的子视图.extern const NSString *  YFViewComponentSubViewPropNameKey;//!< 同一设计图中,子视图的宽度.extern const NSString *  YFViewComponentSubViewHolderWidthKey;//!< 同一设计图中,子视图的高度.extern const NSString *  YFViewComponentSubViewHolderHeightKey;//!< 同一设计图中,子视图的右内边距值(right).extern const NSString *  YFViewComponentSubViewHolderRightKey;//!< 同一设计图中,子视图的底部边距值(bottom).extern const NSString *  YFViewComponentSubViewHolderBottomKey;@interface YFViewComponent : UIView/** *  子视图配置信息. * *  子类应重写覆盖此方法. * 一个示例: @{     YFViewComponentSelfHolderWidthKey: @640.0,     YFViewComponentSelfHolderHeightKey: @155.0,     YFViewComponentSubViewsKey:         @[@{             YFViewComponentSubViewClassNameKey: NSStringFromClass([UIImageView class]) ,             YFViewComponentSubViewPropNameKey: @"imageView",              YFViewComponentSubViewHolderWidthKey: @160,              YFViewComponentSubViewHolderHeightKey: @120,              YFViewComponentSubViewHolderBottomKey: @140,             YFViewComponentSubViewHolderRightKey: @180         }] } * *  @return 返回子视图的配置信息. */+ (NSDictionary *) subViewsConfig;@end
////  YFViewComponent.m//  testMasonry////  Created by xiao on 16/6/6.//  Copyright © 2016年 xiao. All rights reserved.//#import "YFViewComponent.h"#import "Masonry.h"/** *  预定义常量的定义. */const NSString *  YFViewComponentSelfHolderWidthKey = @"YFViewComponentSelfHolderWidthKey";const NSString *  YFViewComponentSelfHolderHeightKey = @"YFViewComponentSelfHolderHeightKey";const NSString *  YFViewComponentSubViewsKey = @"YFViewComponentSubViewsKey";const NSString *  YFViewComponentSubViewClassNameKey = @"YFViewComponentSubViewClassNameKey";const NSString *  YFViewComponentSubViewPropNameKey = @"YFViewComponentSubViewPropNameKey";const NSString *  YFViewComponentSubViewHolderWidthKey = @"YFViewComponentSubViewHolderWidthKey";const NSString *  YFViewComponentSubViewHolderHeightKey = @"YFViewComponentSubViewHolderHeightKey";const NSString *  YFViewComponentSubViewHolderRightKey = @"YFViewComponentSubViewHolderRightKey";const NSString *  YFViewComponentSubViewHolderBottomKey = @"YFViewComponentSubViewHolderBottomKey";@implementation YFViewComponent- (instancetype)init{    self = [super init];    if (nil != self) {        UIView * holderView = self;        NSDictionary * config = [[self class] subViewsConfig];        CGFloat superHeight = [[config objectForKey: YFViewComponentSelfHolderHeightKey] floatValue];        CGFloat superWidth = [[config objectForKey: YFViewComponentSelfHolderWidthKey] floatValue];;        NSArray * locatArray = [config objectForKey: YFViewComponentSubViewsKey];        [locatArray enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL *stop) {            NSString * classString = [obj objectForKey: YFViewComponentSubViewClassNameKey];            Class viewClass = NSClassFromString(classString);            if (YES != [viewClass  isSubclassOfClass:[UIView class]]) {                return;            }            UIView * subView = [[viewClass alloc] init];            [holderView addSubview: subView];            NSString * viewKey = [obj objectForKey: YFViewComponentSubViewPropNameKey];            [holderView setValue: subView forKey: viewKey];            CGFloat subWidth = [[obj objectForKey: YFViewComponentSubViewHolderWidthKey] floatValue];            CGFloat subHeight = [[obj objectForKey: YFViewComponentSubViewHolderHeightKey] floatValue];            CGFloat subBottom = [[obj objectForKey: YFViewComponentSubViewHolderBottomKey] floatValue];            CGFloat subRight = [[obj objectForKey: YFViewComponentSubViewHolderRightKey] floatValue];            [subView mas_makeConstraints:^(MASConstraintMaker *make) {                UIView * superView = subView.superview;                make.width.equalTo(superView).multipliedBy(subWidth / superWidth);                make.height.equalTo(superView).multipliedBy(subHeight / superHeight);                make.right.equalTo(superView).multipliedBy(subRight / superWidth);                make.bottom.equalTo(superView).multipliedBy(subBottom / superHeight);            }];        }];    }    return self;}+ (NSDictionary *) subViewsConfig{    return nil;}@end

一个示例: 仿网易新闻的新闻单元格.

网易原图

这个示例,取材自网易新闻.图示中已经标注了单元格的宽高,单元格内各个UI元素的width,height,bottom,right.此处UI设计师可根据屏幕尺寸出图,我们根据一份跟定的设计图,直接使用 MarkMan(一个非常好用的标准工具)丈量标记即可. 因为我们是基于比例来添加约束,不同屏幕下,会自动等比变换.

元素效果图

这是一个简单的示例,为了方便演示,临时加上了:

////  YFAutoTransView.h//  testMasonry////  Created by xiao on 16/6/6.//  Copyright © 2016年 xiao. All rights reserved.//#import "YFViewComponent.h"@interface YFAutoTransView : YFViewComponent@property (weak, nonatomic) UIImageView * imageView;@property (weak, nonatomic) UILabel * titleLabel;@property (weak, nonatomic) UILabel * detailLabel;@property (weak, nonatomic) UIButton * chatBtn;@end
////  YFAutoTransView.m//  testMasonry////  Created by xiao on 16/6/6.//  Copyright © 2016年 xiao. All rights reserved.//#import "YFAutoTransView.h"@implementation YFAutoTransView+ (NSDictionary *) subViewsConfig{    NSNumber * holderWidth = @640.0;    NSNumber * holderHeight = @155.0;    NSArray * subConfig = @[                            @[NSStringFromClass([UIImageView class]), @"imageView",                              @160, @120, @140, @180],                            @[NSStringFromClass([UILabel class]), @"titleLabel",                              @420, @31, @55, @615],                            @[NSStringFromClass([UILabel class]), @"detailLabel",                              @410, @60, @136, @605],                            @[NSStringFromClass([UIButton class]), @"chatBtn",                              @120, @32, @141, @628]];    NSMutableArray * subViewsConfig = [NSMutableArray arrayWithCapacity: 42];    [subConfig enumerateObjectsUsingBlock:^(NSArray * obj, NSUInteger idx, BOOL *stop) {        if (6 != obj.count) {            return;        }        NSDictionary * configDict =        @{          YFViewComponentSubViewClassNameKey: obj[0],          YFViewComponentSubViewPropNameKey: obj[1],          YFViewComponentSubViewHolderWidthKey: obj[2],          YFViewComponentSubViewHolderHeightKey: obj[3],          YFViewComponentSubViewHolderBottomKey: obj[4],          YFViewComponentSubViewHolderRightKey: obj[5]          };        [subViewsConfig addObject: configDict];    }];    NSDictionary * config = @{                              YFViewComponentSelfHolderWidthKey: holderWidth,                              YFViewComponentSelfHolderHeightKey: holderHeight,                              YFViewComponentSubViewsKey: subViewsConfig};    return config;}@end

这是与数据结合之后的效果图.只是个初稿,还需要进一步调试.也就是说,以后再写UI界面,你的注意力将可以集中在 数据与视图本身的交互处理上.

////  ViewController.m//  testMasonry////  Created by xiao on 16/6/6.//  Copyright © 2016年 xiao. All rights reserved.//#import "ViewController.h"#import "YFAutoTransView.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    YFAutoTransView * autoTestView = [[YFAutoTransView alloc] init];    autoTestView.backgroundColor = [UIColor grayColor];    autoTestView.frame = CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 155.0/2);    autoTestView.imageView.image = [UIImage imageNamed:@"autoTrans.png"];    autoTestView.imageView.backgroundColor = [UIColor yellowColor];    autoTestView.titleLabel.text = @"爱马仕版苹果表开售8688元起";    autoTestView.titleLabel.font = [UIFont systemFontOfSize:15];    [autoTestView.titleLabel adjustsFontSizeToFitWidth];    autoTestView.detailLabel.text = @"爱马仕版苹果表盘和表带并不会单独销售.";    autoTestView.detailLabel.numberOfLines = 0;    autoTestView.detailLabel.font = [UIFont systemFontOfSize:12];    [autoTestView.chatBtn setTitle:@"跟帖" forState: UIControlStateNormal];    autoTestView.chatBtn.backgroundColor = [UIColor greenColor];    [self.view addSubview: autoTestView];}@end

运行结果:

这里写图片描述

0 0
原创粉丝点击