浅谈MVC模式下--动态计算并设置view的frame

相信大家对MVC这种模式都很熟悉,但是真正理解的并不是很多,也包括我,通俗地说model是数据模型,view是视图模型(一般包含model模型),而controller就是控制model和view的桥梁,有传递数据(传给model)功能,也能控制view(包括大小及位置,展示的样式等等)。


下面就通过一个小小的例子来理解一下MVC怎样使用,并能动态计算view的高度?

首先我们看看整个例子的框架图:


然后我们具体实现的view是这样的


开始动工


Model

两个数据模型:Person和PersonFrame都继承NSObject

FTYPersonModel.h

#import <Foundation/Foundation.h>

@interface FTYPersonModel : NSObject
/**
 *  头像名
 */
@property (copy, nonatomic) NSString *icon;
/**
 *  姓名
 */
@property (copy, nonatomic) NSString *name;
/**
 *  介绍
 */
@property (copy, nonatomic) NSString *intro;

- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)personModelWithDict:(NSDictionary *)dict;
@end

FTYPersonModel.m

#import "FTYPersonModel.h"

@implementation FTYPersonModel
- (instancetype)initWithDict:(NSDictionary *)dict{
    if (self == [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}
+ (instancetype)personModelWithDict:(NSDictionary *)dict{
    return [[FTYPersonModel alloc] initWithDict:dict];
}
@end

PersonModel模型作用是声明属性


FTYPersonFrameModel.h

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

@class FTYPersonModel;
@interface FTYPersonFrameModel : NSObject
/**
 *  person模型
 */
@property (strong, nonatomic) FTYPersonModel *person;
/**
 *  头像Frame
 */
@property (assign, nonatomic, readonly) CGRect iconFrame;
/**
 *  名称Frame
 */
@property (assign, nonatomic, readonly) CGRect nameFrame;
/**
 *  介绍Frame
 */
@property (assign, nonatomic, readonly) CGRect introFrame;
/**
 *  view的高度
 */
@property (assign, nonatomic, readonly) CGFloat viewHeight;
@end

FTYPersonFrameModel包含一个personModel

FTYPersonFrameModel.m


#import "FTYPersonFrameModel.h"
#import "FTYPersonModel.h"

@implementation FTYPersonFrameModel

/**
 *  重置person
 *
 *  @param person person
 */
- (void)setPerson:(FTYPersonModel *)person{
    _person = person;

    CGFloat mainWidth = [UIScreen mainScreen].bounds.size.width;
    CGFloat margin = 10;
    CGFloat iconWH = 70;

    _iconFrame = CGRectMake(margin, margin, iconWH, iconWH);

    CGFloat nameX = CGRectGetMaxX(_iconFrame)+margin;
    CGFloat maxWidth = mainWidth - margin*2 - iconWH - margin;
    CGSize size = CGSizeMake(maxWidth, MAXFLOAT);
    CGSize nameSize = [self sizeCustomWithString:person.name font:[UIFont systemFontOfSize:16.0] constrainedToSize:size];
    _nameFrame = CGRectMake(nameX, margin, nameSize.width, nameSize.height);

    CGFloat introX = nameX;
    CGFloat introY = CGRectGetMaxY(_nameFrame)+margin;
    CGSize introSize = [self sizeCustomWithString:person.intro font:[UIFont systemFontOfSize:14.0] constrainedToSize:size];
    _introFrame = CGRectMake(introX, introY, introSize.width, introSize.height);

    if (CGRectGetMaxY(_introFrame) > CGRectGetMaxY(_iconFrame)) {

        _viewHeight = CGRectGetMaxY(_introFrame) + margin;
    } else {

        _viewHeight = CGRectGetMaxY(_iconFrame) + margin;
    }

}

/**
 *  获取最大宽度的字符串size
 *
 *  @param str      字符串
 *  @param font     字体大小
 *  @param constrainedToSize 最大区域
 *
 *  @return size
 */

- (CGSize)sizeCustomWithString:(NSString *)str font:(UIFont *)font constrainedToSize:(CGSize)size
{
    CGSize resultSize;
    if([self respondsToSelector:@selector(sizeWithAttributes:)]){
        NSDictionary *attributes = @{NSFontAttributeName: font};
        CGRect rect = [str boundingRectWithSize:size
                                        options:NSStringDrawingUsesLineFragmentOrigin
                                     attributes:attributes
                                        context:nil];
        resultSize.width = ceilf(rect.size.width);
        resultSize.height = ceilf(rect.size.height);
    }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        resultSize = [str sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByWordWrapping];
#pragma clang diagnostic pop
    }
    return resultSize;
}

@end

FTYPersonFrameModel的作用就是通过person的值来具体计算出控件所需要的宽度和高度,并赋值给对应的frame;


View

接着我们新建一个视图

FTYPersonView.h

#import <UIKit/UIKit.h>
@class FTYPersonFrameModel;
@interface FTYPersonView : UIView

/**
 *  personFrame模型
 */
@property (strong, nonatomic) FTYPersonFrameModel *personFrame;
@end

FTYPersonView.m


#import "FTYPersonView.h"
#import "FTYPersonFrameModel.h"
#import "FTYPersonModel.h"

@interface FTYPersonView()
/**
 *  头像
 */
@property (weak, nonatomic) UIImageView *iconView;
/**
 *  名称
 */
@property (weak, nonatomic) UILabel *nameLabel;
/**
 *  介绍
 */
@property (weak, nonatomic) UILabel *introLabel;

@end

@implementation FTYPersonView

- (instancetype)initWithFrame:(CGRect)frame{
    if (self == [super initWithFrame:frame]) {

        self.backgroundColor = [UIColor grayColor];

        // 初始化控件
        UIImageView *imageView = [[UIImageView alloc] init];
        _iconView = imageView;
        [self addSubview:imageView];

        UILabel *name = [[UILabel alloc] init];
        name.numberOfLines = 0;
        name.backgroundColor = [UIColor redColor];
        name.font = [UIFont systemFontOfSize:16.0];
        _nameLabel = name;
        [self addSubview:name];

        UILabel *intro = [[UILabel alloc] init];
        intro.numberOfLines = 0;
        intro.font = [UIFont systemFontOfSize:14.0];
        intro.backgroundColor = [UIColor redColor];
        _introLabel = intro;
        [self addSubview:intro];

    }
    return self;
}

/**
 *  重置personFrame
 *
 *  @param personFrame personFrame
 */
- (void)setPersonFrame:(FTYPersonFrameModel *)personFrame{
    _personFrame = personFrame;

    FTYPersonModel *person = personFrame.person;

    if (person.icon.length > 0 ) {
        self.iconView.image = [UIImage imageNamed:person.icon];
    } else {
        self.iconView.image = [UIImage imageNamed:@"center_add_friend"];
    }
    self.iconView.frame = personFrame.iconFrame;

    if (person.name.length > 0) {
        self.nameLabel.text = person.name;
    } else {
        self.nameLabel.text = @"匿名";
    }
    self.nameLabel.frame = personFrame.nameFrame;

    self.introLabel.text = person.intro;
    self.introLabel.frame = personFrame.introFrame;

}

@end

视图view初始化所需要的控件,然后通过一个personFrame属性传值,重置这个属性,获取相对应得值和frame,并设置值和frame。


Controller

FTYPersonViewController.h

#import <UIKit/UIKit.h>

@interface FTYPersonViewController : UIViewController

@end

FTYPersonViewController.m

#import "FTYPersonViewController.h"
#import "FTYPersonFrameModel.h"
#import "FTYPersonModel.h"

#import "FTYPersonView.h"

@interface FTYPersonViewController ()

@end

@implementation FTYPersonViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    FTYPersonModel *person = [[FTYPersonModel alloc] init];
    person.icon = nil;
    person.name = @"圣诞节不发了苏打粉";
    person.intro = @"风把类似的反感本拉萨的高发速度跟法师不东风公司的发放第三方把死灵法大陆is发生的部分就爱上当老板发生";
    FTYPersonFrameModel *personFrame = [[FTYPersonFrameModel alloc] init];
    personFrame.person = person;


    FTYPersonView *personView = [[FTYPersonView alloc] init];
    personView.personFrame = personFrame;
    personView.frame = CGRectMake(0, 100, self.view.frame.size.width, personFrame.viewHeight);
    [self.view addSubview:personView];
}

FTYPersonViewController初始化数据,并设置view的frame。


效果


包结构


总结:这里可能写的不是很清楚,也非常简单,但是如果你能理解的话,那就进步了不少。其实MVC模式也并不是要理解非常清楚,有时候用多了也就理解了,大家都按照这样的规范写代码,自然而然就形成一种很好的规范,MVC也能很好的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值