轻量级xib和重量级storyboard提高开发效率。
需求分析:
- 需要实现一个宫格自定义类,该宫格包含:图片、文字、按钮。分别对应组件:UIImageView、UILabel、UIButton。其中,点击后按钮变为不可选状态。
- 在点击下载后弹出的消息框,该框还需要一个渐变出现和渐变消失的动画。
- 需要创建数据:plist。
实现:
本案例由三部分组成:调用、组件、数据。
代码的实现思路是:
- 在调用处创建plist总条数个组件,然后添加到View上。此外,消息提示框的实现也放在调用处。
- 组件的布局也放在调用处。动画也在调用处
调用处代码实现:
包含了创建多个组件、排列多个组件、数据读取。
- 在ViewController处声明数据成员变量,并用懒加载方式初始化数据。
@interface ViewController ()
// 九宫格Demo的plist信息
@property (nonatomic, strong) NSArray * apps;
@end
// 数据
- (NSArray *) apps
{
if(_apps == nil)
{
// 1. 获取app.plist文件
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
// 2. 根据路径加载数据
_apps = [NSArray arrayWithContentsOfFile:path];
}
return _apps;
}
- 布局:通过父视图来计算每个组件中的横纵坐标。同时绑定按钮的点击事件。
- (void)viewDidLoad {
[super viewDidLoad];
// 九宫格:其实有12格
[self testsquare];
}
- (void) testsquare{
// 设置上下边距、坐标、大小放在创建View处,如果封装在视图类中,还得传参
CGFloat appW = 75;
CGFloat appH = 90;
// App距离手机顶部的边距
CGFloat marginTop = 100;
CGFloat bgView = self.view.frame.size.width;
// 九宫格4行3列
int columns = 3;
// 整个屏幕的宽度 - 一行宫格View的宽度 / 宫格数+1,因为间隔总比宫格数多1
CGFloat marginX = (bgView - columns * appW) / (columns+1);
// 令行间距等于列间距
CGFloat marginY = marginX;
for (int i = 0; i < 12; i++)
{
// 读取plist数据
// 获取当前的kv:字典中存着 图标名和图片名
NSDictionary *appDict = self.apps[i];
// 0~2=0行, 3~5 = 1行,所以行号除以3即可
// 0、3、6、9->0列,1、4、7、10->1列 列号取模
int row = i / 3;
int col = i % 3;
// 动态计算每个宫格的X、Y坐标:
// x:(列号+1)*列边距 上述计算的行列边距值一样
// X坐标:左边距+列号*边距
CGFloat appX = marginX + (marginX+appW) * col;
// y:行号*列边距 + 到顶部距离, 上述计算的行列边距值一样
CGFloat appY = marginTop + row * (marginY+appH);
squaredDemo *sqview = [[squaredDemo alloc] init];
sqview.frame = CGRectMake(appX, appY, appW, appH);
// sqview.backgroundColor = [UIColor blueColor];
// 设置宫格视图中的组件样式 imgview的icon
// icon大小占宫格一半:
// 不必addSub 因已add
CGFloat iconW = 45;
CGFloat iconH = 45;
CGFloat iconX = (sqview.frame.size.width-iconW) / 2; // 居中
CGFloat iconY = 0; // icon紧贴顶部,Y为0
// sqview.imgview.backgroundColor = [UIColor yellowColor];
sqview.imgview.frame = CGRectMake(iconX, iconY, iconW, iconH);
// 设置label
CGFloat nameW = sqview.frame.size.width; // 紧贴label
CGFloat nameH = 20; //
CGFloat nameX = 0; // Label贴着View
CGFloat nameY = iconY+iconH; // name紧贴图标icon底部,iconY=0
// 设置label的颜色:
// label文字需要设置居中,默认是左对齐,注意背景色的函数和字体颜色的函数
//sqview.label.backgroundColor = [UIColor redColor];
// 如果找不到某个控件,很可能是你的坐标给错了:之前错误地把宫格view中label的坐标给成了view的宽度,位置直接到了宫格view以外,所以看不见
sqview.label.frame = CGRectMake(nameX, nameY, nameW, nameH);
// 设置btn
CGFloat btnW = iconW; // 和icon一致
CGFloat btnH = 20; //
CGFloat btnX = iconX; // 居中
CGFloat btnY = nameY+nameH; // name紧贴图标icon底部,iconY=0
sqview.btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
// = = = = = = = 数据填充、格式设置 = = = = = = =
// 设置宫格view的数据
sqview.imgview.image = [UIImage imageNamed:appDict[@"icon"]];
sqview.label.text = appDict[@"icon"];
sqview.label.font = [UIFont systemFontOfSize:12];
// 设置文字居中对齐
sqview.label.textAlignment = NSTextAlignmentCenter;
// 按钮背景
[sqview.btn setBackgroundImage:[UIImage imageNamed:@"buttongreen.png"] forState:UIControlStateNormal];
[sqview.btn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted.png"] forState:UIControlStateHighlighted];
// btn title设置
[sqview.btn setTitle:@"下载" forState:UIControlStateNormal];
// 已安装状态是不可点击时
[sqview.btn setTitle:@"已安装" forState:UIControlStateDisabled];
// btn title 大小
sqview.btn.font = [UIFont systemFontOfSize:14];
// 按钮绑定单击事件
[sqview.btn addTarget:self action:@selector(btnDownClick:) forControlEvents:UIControlEventTouchUpInside];
//
[self.view addSubview: sqview];
}
}
- 点击弹出消息并实现动画的显示和消失:
消息提示框动画逻辑稍微复杂一点,思路是:先设置不透明度为0值,即初始完全透明,随后设置动画中不透明度变为0.6,接着实现消息框的消失效果,通过再把透明度设置为0的方式,最后移除该消息框,通过removeFromSuperview()来实现。
- (void) btnDownClick:(UIButton *)sender{
NSLog(@"点击了下载");
// 先禁用按钮
sender.enabled = NO;
CGFloat viewW = (self.view.frame.size.width);
CGFloat viewH = (self.view.frame.size.height);
// 点击下载后,创建UILabel,并添加动画:需要init,不然好像直接报错了
UILabel *labMsg = [[UILabel alloc] init];
CGFloat msgW = 200;
CGFloat msgH = 30;
CGFloat msgX = (viewW - msgW) / 2; // 横纵坐标就用屏幕的宽高来求
CGFloat msgY = (viewH - msgH) * 0.5;
labMsg.frame = CGRectMake(msgX, msgY, msgW, msgH);
[labMsg setBackgroundColor:[UIColor blackColor]];
labMsg.textColor = [UIColor redColor];
labMsg.text = @"正在下载...";
labMsg.font = [UIFont boldSystemFontOfSize:17];
// 初始透明度为0,即:全透明不显示
labMsg.alpha = 0.0;
// 设置圆角半径
labMsg.layer.cornerRadius = 10;
// 裁剪半径外部分
labMsg.layer.masksToBounds = YES;
// 设置消息提示框逐渐变黑并显示:
[UIView animateWithDuration:1.5 animations:^{
labMsg.alpha = 0.6;
}completion:^(BOOL finished) {
// 如果执行完了,则启动变暗消失动画
if(finished){
// 代码含义:执行完,再执行以下:透明度变0,即:消失
[UIView animateWithDuration:1.5 delay:1.0 options:UIViewAnimationOptionCurveLinear animations:^{
// 变化内容是:透明度变0,即隐藏
labMsg.alpha = 0;
} completion:^(BOOL finished) {
if(finished){
// 当Label透明度变0后,把Label从view移除
[labMsg removeFromSuperview];
}
}];
}
}];
// 加入视图
[self.view addSubview: labMsg];
}
- 自定义宫格组件视图
// 宫格
@interface squaredDemo : UIView
// App的展示图标
// 可点击的按钮
// 显示名称的UILabel
@property(strong, nonatomic) UIImageView *imgview;
@property(strong, nonatomic) UILabel *label;
@property(strong, nonatomic) UIButton *btn;
@end
```objectivec
@implementation squaredDemo
-(instancetype) initWithFrame:(CGRect)frame{
// 整个视图
self = [super initWithFrame:frame];
if(self){
// 循环创建
_btn = [[UIButton alloc]init];
// 按钮文字
//[_btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
_imgview = [[UIImageView alloc] init];
/*_imgview = [[UIImageView alloc] initWithFrame:CGRectMake(appW, appH, appX, appY)]*/
// UILabel:
_label = [[UILabel alloc] init];
//_label.text = @"123";
// 添加到子View
[self addSubview:_btn];
[self addSubview:_label];
[self addSubview:_imgview];
}
return self;
}
@end
遇到的错误和注意点:
- 组件没显示,且报错bad thread的原因是
没有把视图View添加成功,组件创建后除了要用alloc,还要用init。
- 添加UILabel没显示:
UILabe的背景颜色没设置,文字也没设置。故添加subView后没看到效果