Hello, 大家好,又到了周末,今天我要来分享的是一篇“字母饼干惊险记”,一个可爱的 ios 小程序。
今天只有不到两个小时的时间写这篇,为了更直观,首先我们上效果图:
在 iPhone 7 plus 的模拟器界面,我们看到界面上方有两个可爱的瑞典字母,是我从朋友圈盗图来的,很感谢这位朋友分享好看的图片,在完成这个程序时为我带来了许多乐趣。
好啦,回归正题,这两个字母是两个按钮,可以点击的哦。每点击一次,下方的深色面板就会添加一项控件。我在这里选取的是一张图片,当然你也可以添加图片和文本的组合,这时就要用到父控件了,我们在后面也会讲到。细心的盆友们肯定会发现,咦,为什么右边是灰色的?这就说这个按钮是不可点击的 display 状态,当点击完成后,我们可以看到下面的界面:
这时,添加按钮变为不可点击的状态,这里的控件都是依次添加的,那么这里就要涉及换行的操作。下面我们来进行代码的讲解,这个小程序与非在学的时候需要注意的点有点多哦。
在最终版的代码里,我们需要做的有四部分:
1/懒加载——加载数据的一种方式,当且仅当用到这个数据时加载一次,这样做就会加载完全部数据后再进行方法调用而增加了冗余,只有当用到这些数据时才会加载,并且在后面的程序再次用到这些数据时不用重新加载,它是不是又聪明又懒呢?所以加懒加载,懒得加载你。
2/在界面中添加按钮——这里也就是指我们那两个可爱的字母,它们的类是 UIButton 的类型,当界面加载完成后,按钮需要被创建好,可以使用代码的方式添加,但我们有一种更便捷好用的方式就是 xib,这点我们在接下来也会讲到。
3/添加和删除的方法——对这两个方法进行调用,才能将下方的图片依次添加到我们的 UIView 里。
4/检查按钮状态——这是字母饼干什么时候变为灰色不可点击状态,和什么时候满血复活的关键。
在添加方法里涉及到一个九宫格的数值计算,也就是这些图片之间的间隙怎么计算,你该不会以为是要一张一张拖上去吧?(其实我一开始就会这么以为)
//每张图片的尺寸
CGFloat characterW = 80;
CGFloat characterH = 80;
//一行的列数
int cols = 4;
//一列的行数
int rows= 5;
//列间距
CGFloat colMargin = (self.myboard.frame.size.width - cols * characterW) / (cols - 1);
//行间距
CGFloat rowMargin = (self.myboard.frame.size.height - rows * characterH) / (rows - 1);
这里需要解释的是列间距与行间距的计算。其实很简单,间距就是深蓝色的界面宽度减去你所拥有的 n 张图片总宽度,将剩下的宽度分给 n-1 个空隙。然后根据索引分别计算出每张图片的横纵坐标:
NSUInteger col = index % cols;
CGFloat characterX = col * (characterW + colMargin);
NSUInteger row = index / cols;
CGFloat characterY = row * (characterH + rowMargin);
计算机会帮你计算每次点击后那张图片该放在哪个位置,这时你只有要用它能懂的方法把图片放在相应的位置就好。
在这个小程序里我们采用完全面向模型的方法加载数据,也就是说在懒加载的时候,我们从 .plist 文件加载的是一个字典数组,即这个数组里装的都是字典,我们需要将它们转成模型,在数据加载的那一刻就转换完成:
-(NSArray *)chars
{
if(_chars == nil){
NSArray *charsArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"chars" ofType:@"plist"]];
NSMutableArray *chArray = [NSMutableArray array];
for(NSDictionary *ch in charsArray){
chs *cModel = [chs charWithCh:ch];
[chArray addObject:cModel];
}
_chars = chArray;
}
return _chars;
}
这里需要注意的一点是,在用懒加载时,我们利用 mainBundle 获得 .plist 文件的全路径。这个方法以后也会多次用到。
这里的模型是什么等模型呢?好问题。我们这就来看一下,原来它是在 xib 里直接使用 UIImageView 设好的,这里有一句关键的代码是:
charView *myboard = [charView myboard];
这里不应该是 UIView 吗?charView 能用吗?小心哦,这里的确是个雷区,要想让你的模型好使(哎呀东北话都跑出来了就是这个意思),你需要将这里的类写为继承自UIView的接口,也就是charView,charView 是一个自定义的类名,在哪里有呢?就在xib文件里的View,注意:是最上方的 View 控件需要改,别改那一小块区域的类(我才不说我改了好半天才发现错呢)。与非在这里费了一些无用功,还以为是代码错了呢。之所以改整体的,是因为它从大窗口那里继承后,才会再加载里面的小东西。
面向模型的好处是:根据索引从数组里取出的就是模型。这时,从模型直接获取图片,再添加到子视图即可,是不是方便了很多呢?这里要注意的一点是我们要用 CGRectMake 设置好尺寸,图片才会显示出来,否则你可能什么都看不到会很失望,记得检查一下是否设置好了尺寸让它显现。
添加方法到这里就差不多完成了,什么?还有删除方法?别担心,删除方法意外的只有短短一行代码:
[[self.myboard.subviews lastObject] removeFromSuperview];
移除最后一项?竟然还有这种操作?! 太简单了吧,你有想到吗?
好的,你想到了,我们继续下一项。我们给它删删删删……
好了,它中间状态就是这样的,好想给大家展示动图啊,在鼠标点击的时候,有一个高亮状态,你会看到字母饼干惊悚的表情,系统自带?开什么玩笑,这么好看的效果当然是我加了一个渐变映射在上面,瞬间变彩色,好吧是没什么用,看着开心啊有木有呢。那么,我要说重点了,这里的这些按钮也是控件,你要对一个它进行操作,首先你要拿到它,怎么拿呢,你对它进行操作,一定是想改变它的属性对不对,那么你就要先拥有这个属性:
@property(weak,nonatomic) UIButton *addBtn;
然后……拖线,对~!就是拖线,按住 control(mac上的写着 control 字的键哦)。要让它有惊悚的效果:高亮状态的奇异彩色,不可点击状态的灰色,平时的可爱样子,你需要在获得这个按钮后为它添加 3 张不同的图片:
self.addBtn = [self addButtonWithImage:@"img-a" highImage:@"A-light" disabledImage:@"img-ah" frame:CGRectMake(20, 20, 40, 40) action:@selector(add)];
竟然是只是变换图片?对的,就是这么 low,最后我们在讲讲 HUD,那是什么?我们上图:
ok, fine?Ok,就是这层透明指示层,是不是整个界面瞬间复杂了?而它在你设定的秒数过去后就可以消失,自动消失?是的,但是需要我们用设置透明度的方式来让它消失:
self.HUD.alpha = 1.0;
self.HUD.text = @"ok,fine";
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.HUD.alpha = 0.0;
dispatch_after() 就是让它消失的咒语,来跟我读一遍,dispatch after 消失!
好的,今天的总结就到这里,我们下周再见!
后记:
还有十几分钟,我就要欢快的运动去啦(睡前玩手机运动),在结束之前,我还要提几个问题。在这个小程序里,涉及到了封装的概念,初步接触,觉得这的确是一个非常神奇有用的东西,还需要进一步的学习,我自己也没搞懂,所以今天的总结中没有提及,但在之后的某一篇文章必然会有它的。
谢谢大家!源代码附上(竟然写完了……):
#import "ViewController.h"
#import "chs.h"
#import "charView.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *myboard;
/**添加按钮*/
@property(weak,nonatomic) UIButton *addBtn;
/**删除按钮*/
@property(weak,nonatomic) UIButton *removeBtn;
/**全部数据*/
@property(strong,nonatomic) NSArray *chars;
/**HUD显示器*/
@property (weak, nonatomic) IBOutlet UILabel *HUD;
@end
@implementation ViewController
#pragma mark 懒加载:加载plist数据
-(NSArray *)chars
{
if(_chars == nil){
NSArray *charsArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"chars" ofType:@"plist"]];
NSMutableArray *chArray = [NSMutableArray array];
for(NSDictionary *ch in charsArray){
chs *cModel = [chs charWithCh:ch];
[chArray addObject:cModel];
}
_chars = chArray;
}
return _chars;
}
-(void)viewDidLoad
{
[super viewDidLoad];
//加入“添加按钮”
self.addBtn = [self addButtonWithImage:@"img-a" highImage:@"A-light" disabledImage:@"img-ah" frame:CGRectMake(20, 20, 40, 40) action:@selector(add)];
//加入“删除按钮‘
self.removeBtn = [self addButtonWithImage:@"img-q" highImage:@"Q-light" disabledImage:@"img-qh" frame:CGRectMake(360, 20, 40, 40) action:@selector(remove)];
self.removeBtn.enabled = NO;
}
#pragma mark 添加按钮
-(UIButton *)addButtonWithImage:(NSString *)Image highImage:(NSString *)highImage disabledImage:(NSString *)disabledImage frame:(CGRect)frame action:(SEL)act
{
//创建按钮
UIButton *btn=[[UIButton alloc] init];
//设置背景图片
[btn setBackgroundImage:[UIImage imageNamed:Image] forState:UIControlStateNormal];
[btn setBackgroundImage:[UIImage imageNamed:highImage] forState:UIControlStateHighlighted];
[btn setBackgroundImage:[UIImage imageNamed:disabledImage] forState:UIControlStateDisabled];
//设置位置和尺寸
btn.frame=frame;
//监听按钮点击
[btn addTarget:self action:act forControlEvents:UIControlEventTouchUpInside];
//添加按钮
[self.view addSubview:btn];
return btn;
}
#pragma mark 添加
-(void)add
{
CGFloat characterW = 80;
CGFloat characterH = 80;
int cols = 4;
int rows= 5;
CGFloat colMargin = (self.myboard.frame.size.width - cols * characterW) / (cols - 1);
CGFloat rowMargin = (self.myboard.frame.size.height - rows * characterH) / (rows - 1);
charView *myboard = [charView myboard];
NSUInteger index = self.myboard.subviews.count;
myboard.mychar = self.chars[index];
NSUInteger col = index % cols;
CGFloat characterX = col * (characterW + colMargin);
NSUInteger row = index / cols;
CGFloat characterY = row * (characterH + rowMargin);
chs *cModel = self.chars[index];
//获取图片
UIImageView *character = [[UIImageView alloc] init];
character.image=[UIImage imageNamed:cModel.character];
character.frame=CGRectMake(characterX, characterY, characterW, characterH);
[self.myboard addSubview:character];
//控制按钮的状态
[self checkIt];
}
#pragma mark删除
-(void)remove
{
[[self.myboard.subviews lastObject] removeFromSuperview];
[self checkIt];
}
#pragma mark 检查按钮状态
-(void)checkIt
{
self.addBtn.enabled = (self.myboard.subviews.count < self.chars.count);
self.removeBtn.enabled = (self.myboard.subviews.count != 0);
/**显示HUD*/
if(self.removeBtn.enabled == NO){
self.HUD.alpha = 1.0;
self.HUD.text = @"I came running";
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.HUD.alpha = 0.0;
});
}else if(self.addBtn.enabled == NO){
self.HUD.alpha = 1.0;
self.HUD.text = @"ok,fine";
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.HUD.alpha = 0.0;
});
}
}
@end