【iOS7的一些总结】12、使用UIView的一种有效方法

在一个典型的MVC结构中,Model部分负责保存目标数据,View部分主要负责实现数据的界面以及将数据显示出来,二者在Controller的操作下协同工作。在iOS应用中,View的实现主要由UIView及其派生类实现,主要由UILabel、UIImageView等等类来显示不同的信息。

这里展示一个demo来说明个人对UIView同数据交互的一种观点,个人意见仅供参考,欢迎讨论。

1、首先建立一个UIView的子类用于定制我们的视图对象。

头文件:

#import <UIKit/UIKit.h>

@interface UserInfoView : UIView

//@property (nonatomic,copy) NSString *imgString;
//@property (nonatomic,copy) NSString *nameString;
//@property (nonatomic,copy) NSString *addrString;
//@property (nonatomic,copy) NSString *infoString;
//@property (nonatomic,copy) NSString *countString;
//@property (nonatomic,copy) NSString *attString;
//@property (nonatomic,copy) NSString *fansString;

@property (nonatomic,retain) NSDictionary *param;

- (void)loadData;

@end
m文件:

#import "UserInfoView.h"
#import "RectButton.h"

@interface UserInfoView()

//UI控件
@property (nonatomic,retain) UIImageView    *userImage;
@property (nonatomic,retain) UILabel        *nameLabel;
@property (nonatomic,retain) UILabel        *addressLabel;
@property (nonatomic,retain) UILabel        *infoLabel;
@property (nonatomic,retain) UILabel        *countLabel;
@property (nonatomic,retain) RectButton     *attButton;
@property (nonatomic,retain) RectButton     *fansButton;
@property (nonatomic,retain) UIButton       *profileButton;
@property (nonatomic,retain) UIButton       *moreButton;

//数据成员
//@property (nonatomic,copy) NSString *imgString;
@property (nonatomic,copy) NSString *nameString;
@property (nonatomic,copy) NSString *addrString;
@property (nonatomic,copy) NSString *infoString;
@property (nonatomic,copy) NSString *countString;
//@property (nonatomic,copy) NSString *attString;
//@property (nonatomic,copy) NSString *fansString;

@end

@implementation UserInfoView

- (id)init
{
    CGRect frameRect = CGRectMake(0, 0, 320, 200);
    self = [self initWithFrame:frameRect];
    if (self)
    {
        NSLog(@"Init called");
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.backgroundColor = [UIColor lightGrayColor];
        
        _userImage = [[UIImageView alloc] initWithFrame:CGRectZero];
        [self addSubview:_userImage];

        _nameLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        [self addSubview:_nameLabel];

        _addressLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        [self addSubview:_addressLabel];

        _infoLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        [self addSubview:_infoLabel];

        _attButton = [[RectButton alloc] initWithFrame:CGRectZero];
        [self addSubview:_attButton];
        
        _fansButton = [[RectButton alloc] initWithFrame:CGRectZero];
        [self addSubview:_fansButton];
        
        _profileButton = [[UIButton alloc] initWithFrame:CGRectZero];
        [self addSubview:_profileButton];
        
        _moreButton = [[UIButton alloc] initWithFrame:CGRectZero];
        [self addSubview:_moreButton];
        
        _countLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        [self addSubview:_countLabel];
    }
    return self;
}

- (void)setParam:(NSDictionary *)param
{
    _param = param;
    
    _nameString = [_param objectForKey:@"Name"];
    _addrString = [_param objectForKey:@"Address"];
    _infoString = [_param objectForKey:@"Infomation"];
    _countString = [_param objectForKey:@"Count"];
    
    [self loadData];
}

- (void)layoutSubviews
{
    _userImage.frame = CGRectMake(20, 20, 80, 80);
    _userImage.backgroundColor = [UIColor yellowColor];
    
    _nameLabel.frame = CGRectMake(120, 20, 180, 20);
    _nameLabel.backgroundColor = [UIColor yellowColor];
    
    _addressLabel.frame = CGRectMake(120, 50, 180, 20);
    _addressLabel.backgroundColor = [UIColor yellowColor];
    
    _infoLabel.frame = CGRectMake(120, 80, 180, 20);
    _infoLabel.backgroundColor = [UIColor yellowColor];
    
    _attButton.frame = CGRectMake(20, 110, 60, 60);
    _attButton.backgroundColor = [UIColor greenColor];
    
    _fansButton.frame = CGRectMake(93, 110, 60, 60);
    _fansButton.backgroundColor = [UIColor greenColor];

    _profileButton.frame = CGRectMake(167, 110, 60, 60);
    _profileButton.backgroundColor = [UIColor greenColor];

    _moreButton.frame = CGRectMake(240, 110, 60, 60);
    _moreButton.backgroundColor = [UIColor greenColor];

    _countLabel.frame = CGRectMake(20, 180, 280, 15);
    _countLabel.backgroundColor = [UIColor whiteColor];
    
    [self loadData];
}

- (void)loadData
{
    if (self.nameString.length != 0)
    {
        _nameLabel.text = self.nameString;
    }
    if (self.addrString.length != 0)
    {
        _addressLabel.text = self.addrString;
    }
    if (self.infoString.length != 0)
    {
        _infoLabel.text = self.infoString;
    }
    if (self.countString.length != 0)
    {
        _countLabel.text = self.countString;
    }
}

@end

在这个UserInfoView新建的时候,在initWithFrame中建立各个子视图,但是只是单纯新建一个对象而已,其frame设置为0。另外,还重写了init函数,在函数中设置了指定的View大小,这样在Controller新建视图的时候不需要指定参数直接按照指定值进行操作。


UserInfoView中各个子视图的设置,在layoutSubView中完成,包括设置子视图的frame和背景颜色。layoutSubView函数可能经常被调用到,主要由以下几种情况:

  1. 当addSubView被调用时,被添加视图以及其子视图的layoutSubView会被调用;
  2. 当视图的frame发生改变时,会调用该视图的layoutSubView;
  3. 当滚动UIScrollView的时候会调用该视图及其父视图的layoutSubView;
  4. 旋转设备的时候;
  5. 向该视图发送setNeedLayout消息的时候。

2、由Controller向View中发送数据。

ViewController类的实现如下:

#import "ViewController.h"
#import "UserInfoView.h"

@interface ViewController ()

@property (nonatomic,retain) UIButton *People1;
@property (nonatomic,retain) UIButton *People2;
@property (nonatomic,retain) UserInfoView *userView;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
     _userView = [[UserInfoView alloc] init];
    [self.view addSubview:_userView];
    
    _People1 = [UIButton buttonWithType:UIButtonTypeSystem];
    _People1.frame = CGRectMake(20, 240, 120, 40);
    [_People1 setTitle:@"张三" forState:UIControlStateNormal];
    _People1.backgroundColor = [UIColor lightGrayColor];
    [_People1 addTarget:self action:@selector(setPeople1Data) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_People1];
    
    _People2 = [UIButton buttonWithType:UIButtonTypeSystem];
    _People2.frame = CGRectMake(180, 240, 120, 40);
    [_People2 setTitle:@"李四" forState:UIControlStateNormal];
    _People2.backgroundColor = [UIColor lightGrayColor];
    [_People2 addTarget:self action:@selector(setPeople2Data) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_People2];
    
/*    view.nameString = @"张三";
    view.addrString = @"北京";
    view.infoString = @"学生";
    view.countString = @"12345";
    
    view.nameString = @"李四";
    view.addrString = @"上海";
    view.infoString = @"工程师";
    view.countString = @"54321";*/
}

- (void)setPeople1Data
{
    NSLog(@"setPeople1Data called.");
    NSDictionary *param = @{@"Name": @"张三", @"Address" : @"北京", @"Infomation" : @"学生", @"Count" : @"12345"};
    _userView.param = param;
}

- (void)setPeople2Data
{
    NSLog(@"setPeople2Data called.");
    NSDictionary *param = @{@"Name": @"李四", @"Address" : @"上海", @"Infomation" : @"工程师", @"Count" : @"54321"};
    _userView.param = param;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

ViewController的默认视图上,分别实现了两个按钮并分别设置了响应函数。我们的目的是通过选择不同的按钮来改变UserInfoView中显示的数据。从两个响应函数setPeople1Data和setPeople2Data的实现可知,UserInfoView所需要的信息都被封装在了一个字典型变量param中,对view的修改仅仅做了一个操作,即将该字典变量赋给了UserInfoView实例的一个property,通过这种改变一下目标view属性的方式即可完成对显示信息的更改。这样,Controller并不关心UserInfoView实例是如何解析字典参数的,也不需要对该实例进行其他操作,当需要更新数据的时候只需要一次赋值就可以了。如此可以最大程度地解除Controller和View的耦合性,提高代码的逻辑简洁度和可复用性。

再回到UserInfoView类中的实现方法。如何实现在字典类property改变的同时对自己的子视图进行重写数据操作呢?方法很简单。首先将重写子视图数据的代码分离到loadData函数中,然后重写NSDictionary *param这个property的set方法(即setParam),然后在该set方法和layoutSubView方法中调用loadData方法就可以了。

demo下载链接:点这里

上一篇:Anacnoda镜像在阿里云镜像站首发上线


下一篇:linux内核分析笔记----中断和中断处理程序