UI基础xib的使用及xib的封装
一:
1、xib和stroryboard
Storyboard 描述软件界面,相对于xib比较重量级,一个stroryboard可以有多个场景。可以描述整个软件的所有界面
xib 描述软件界面,一般用来描述一个界面中的某一个部分
本质就是代码创建的
xib的加载过程,从xml中加载进来对界面的描述,并以此创建出来 JSAppView *view = [[JSAppView alloc] init];
View.frame = CGRectMake(0,0,85,90);
UIImageView *imageView = .......; [view addSubView:imageView];
...............
xib和storyboard的共同点 都用来描述软件界面
都用Interface Builder工具来编辑 都使用xml来存储 对界面的描述
xib和storyboard的区别,查看xib和storyboard的xml代码发现他们的区别仅仅是xib少了
Scenes和viewController
xib是轻量级的,用来描述局部的UI界面 stroryboard是重量级的,用来描述整个软件的多个界面,并且能展示 多个界面之间的跳转关系
2:查看Xcode中storyBoard的xml展示文件
3 补充:、storyBoard或者xib中拖一个UIImageView 上不能拖其他控件到它上面
// 通过xib创建view UIView *subView = [[[NSBundle mainBundle] loadNibNamed:@"LLAppInfoView" owner:nil options:nil] lastObject];
#import <UIKit/UIKit.h> @class LLAppInfo; @interface LLAppInfoView : UIView @property (nonatomic, strong) LLAppInfo *appInfo; + (instancetype)appInfoView; @end
#import "LLAppInfoView.h" #import "LLAppInfo.h" @interface LLAppInfoView () @property (weak, nonatomic) IBOutlet UIImageView *iconView; @property (weak, nonatomic) IBOutlet UIButton *downView; @property (weak, nonatomic) IBOutlet UILabel *nameView; - (IBAction)downBtnClick:(UIButton *)sender; @end @implementation LLAppInfoView + (instancetype)appInfoView { LLAppInfoView *subView = [[[NSBundle mainBundle] loadNibNamed:@"LLAppInfoView" owner:nil options:nil] lastObject]; return subView; } - (void)setAppInfo:(LLAppInfo *)appInfo { _appInfo = appInfo; self.iconView.image = [UIImage imageNamed:_appInfo.icon]; self.nameView.text = _appInfo.name; } - (IBAction)downBtnClick:(UIButton *)sender { self.superview.userInteractionEnabled = NO; sender.enabled = NO; UILabel *textLab = [[UILabel alloc] init]; [self.superview addSubview:textLab]; textLab.text = [NSString stringWithFormat:@"%@ 正在下载", _appInfo.name]; textLab.backgroundColor = [UIColor grayColor]; textLab.alpha = 0; textLab.textAlignment = NSTextAlignmentCenter; CGFloat textLabW = 200; CGFloat textLabH = 30; CGFloat textLabX = (self.superview.frame.size.width -textLabW) * 0.5; CGFloat textLabY = (self.superview.frame.size.height - textLabH) * 0.5; textLab.frame = CGRectMake(textLabX, textLabY, textLabW, textLabH); textLab.layer.cornerRadius = 10; textLab.layer.masksToBounds = YES; [UIView animateWithDuration:1.0 animations:^{ textLab.alpha = 0.9; [UIView animateWithDuration:1 delay:5 options:UIViewAnimationOptionAllowUserInteraction animations:^{ textLab.alpha = 0; } completion:^(BOOL finished) { [textLab removeFromSuperview]; self.superview.userInteractionEnabled = YES; }]; }]; } @end
数据模型
#import <Foundation/Foundation.h> // 封装数据模型 @interface LLAppInfo : NSObject /** 图片 */ @property (nonatomic, copy) NSString *icon; /** 名称 */ @property (nonatomic, copy) NSString *name; #warning instancetype 和 id的区别 + (instancetype)appInfoWithDic:(NSDictionary *)dic; - (instancetype)initWithDic:(NSDictionary *)dic; + (NSArray *)array; @end
#import "LLAppInfo.h" @implementation LLAppInfo - (instancetype)initWithDic:(NSDictionary *)dic { if (self = [super init]) { self.name = dic[@"name"]; self.icon = dic[@"icon"]; } return self; } + (instancetype)appInfoWithDic:(NSDictionary *)dic { return [[self alloc] initWithDic:dic]; } + (NSArray *)array { NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil]; NSArray *dicArray = [NSArray arrayWithContentsOfFile:path]; NSMutableArray *appInfoM = [[NSMutableArray alloc] initWithCapacity:dicArray.count]; for (NSDictionary *dic in dicArray) { [appInfoM addObject:[self appInfoWithDic:dic]]; } return appInfoM; } @end
控制器
#import "ViewController.h" #import "LLAppInfo.h" #import "LLAppInfoView.h" @interface ViewController () // 1,创建接受模型数据的数组 @property (nonatomic, strong) NSArray *appInfos; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 创建九宫格 [self createView]; } #pragma mark - 创建九宫格 - (void)createView { // 1, // 1,1 列数 int colnumCount = 3; CGFloat subViewWH= 100; CGFloat marginX = (self.view.frame.size.width - 3*subViewWH) / (colnumCount + 1); for (int i = 0; i<self.appInfos.count; i++) { // 计算行、列 int row = i/colnumCount; int col = i%colnumCount; // 通过xib创建view // UIView *subView = [[[NSBundle mainBundle] loadNibNamed:@"LLAppInfoView" owner:nil options:nil] lastObject]; // 通过xib封装的view创建view LLAppInfoView *subView = [LLAppInfoView appInfoView]; [self.view addSubview:subView]; // 确定subView的frame CGFloat subViewX = marginX + (marginX + subViewWH) * col; CGFloat subViewY = 30 + (marginX + subViewWH) * row; subView.frame = CGRectMake(subViewX, subViewY, subViewWH, subViewWH); #warning 将子控件添加到一个定义的view中的好处 LLAppInfo *appInfo = self.appInfos[i]; subView.appInfo = appInfo; // 2,取子控件给子控件赋值(这里有两种方法) /** 1,通过viewWithTag 2,通过subViews */ // 这样写还是有问题,如果有多个控件tag标记太多,而且tag的性能很差 UIImageView *iconView = (UIImageView *)[subView viewWithTag:10]; iconView.image = [UIImage imageNamed:appInfo.icon]; UILabel *nameView =(UILabel *) [subView viewWithTag:20]; nameView.text = appInfo.name; } } #pragma mark - 懒加载模型数据 - (NSArray *)appInfos { if (!_appInfos) { #warning NSBundle // NSLog(@"%@", NSHomeDirectory()); // 1,重plist中读取数据 // NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil]; // NSArray *appInfo = [NSArray arrayWithContentsOfFile:path]; // // // _appInfos = appInfo; // NSLog(@"%@", _appInfos); // 直接从封装好的代码中取数据 _appInfos = [LLAppInfo array]; } return _appInfos; } @end
1)使用xib封装一个自定义view的步骤
1、新建一个继承UIView的自定义view,类名AppInfoView
2、创建xib(xib的名字和自定义view的名字一样AppInfoView),来描述AppInfoView的内部结构
3、修改xib中的UIView的类型改为AppInfoView
4、把xib中控件连线到AppInfoView
5、AppInfoView提供一个模型属性
6、重写模型的set方法,在set方法中给xib中对应的子控件赋值
2)封装的好处
xib中完成的代码 controller得知道xib中具体的控件,产生依赖 为了减少依赖,把xib内部控件的赋值给封装起来
如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部的子控件的创建屏蔽起来,不让外界关心,这样不 管view内部怎么变化外界都不需要知道