首页 > 学院 > 开发设计 > 正文

ios开发-UI基础-超级猜图

2019-11-14 19:02:08
字体:
来源:转载
供稿:网友

  [注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.VEVb.com/hukezhu/

 

  本篇文章介绍一个比较综合的小应用----超级猜图.

  功能分析:

    • 根据显示的图片,在下面的待选项按钮中选中正确答案按钮,选中的按钮会显示在正确答案按钮中
    • 答案错误,答案颜色变为红色,分数减小
    • 答案正确,答案颜色变为蓝色,两秒自动跳入下一题,分数增加
    • 点击"下一题"可以进入下一个题目
    • 点击"大图",可以放大显示图片,再次点击图片或者背景,图片缩小至原来大小
    • 点击"提示",自动情况答案选项,并显示正确答案的第一个字,并且分数减小  

  应用截图:

下面附上完成这个小应用的思路:

  

  1 1. 通过storyboard设计"超级猜图"的上半部分界面。  2     1> 使用UIImageView做背景(最后面的背景图片,首先添加这个)  3     2> 分析界面上的控件,显示图片的也使用button,显示内容的使用label,  4         下面显示答案按钮和最下面显示待选项按钮的位置使用view  5     中间的图片可以点击:用button,button有一个inset:分别设置内部内容距离上左下右有多少不能显示  6   7   8 2. 实现点击"下一题"功能.(最开始状态是没有数据的,首先点击下一题,我们家在数据之后,才能做其他的功能,所以最开始先完成"下一题"的功能)  9     * 声明一个index属性来记录当前显示的题目的索引。 10  11     * 当我们点击"下一题"的时候, 从数组中获取对应的题目, 并显示到对应的界面控件上。 12  13  14     * 解决:最后一题之后再次点击"下一题"索引越界问题。(此处进行判断) 15  16 /*    0.判断索引值是否越界,并且弹框 17     if (self.index == self.questions.count - 1) { 18     //        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"恭喜" message:@"过关了" delegate:nil 19     //                                             cancelButtonTitle:@"取消" otherButtonTitles:@"A", nil]; 20     //        [alert show]; 21     UIActionSheet *acionsheet  = [[UIActionSheet alloc]initWithTitle:@"恭喜" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:@"A",@"B", nil]; 22     [acionsheet showInView:self.view]; 23      24     return; 25 } 26  27 */ 28  29  30 3. 在viewDidLoad中初始化第一个问题(显示第一个问题到界面上)。 31     * 设置self.index = -1 32     * 手动调用"下一题"按钮的点击事件 33         [self next]; 34  35  36  37 4. 实现"查看大图"功能(点击右侧"大图"按钮, 显示大图) 38  39     * 实现思路(步骤): 40         1> 添加一个"阴影"按钮, 因为该"阴影"要实现点击, 所以用"按钮" 41         2> 然后再把"头像按钮"显示在"阴影"上面。 42         3> 通过动画的方式改变"头像按钮"的frame(位置和尺寸)变成大图效果。 43     ** 注意: 取消"自动布局(Auto Layout)" 44  45     ** 点击"遮罩阴影", 回到小图 46         1> 通过动画慢慢将"遮罩阴影"的透明度变为0 47         2> 通过动画慢慢将"头像图片"的frame修改为原来的位置 48         3> 在动画执行完毕后, 移除"遮罩阴影" 49  50     ** 点击图片本身显示大图, 再次点击图片本身显示小图 51  52  53  54  55  56 5. 动态生成"答案按钮" 57     * 思路: 58         0> 在点击"下一题"按钮中实现该功能 59         1> 创建一个UIView来存放所有的"答案按钮" 60         2> 根据每个问题的答案的文字个数来创建按钮 61         3> 每次创建按钮之前, 先把旧的按钮都删除 62             此处有两种方案: 63                 1-循环便利数组,执行removefromsuperview 64                 2-使用makeObjectsPerformSelector:@selector(removeFromSuperview) 65         4> 指定每个"答案按钮"的尺寸和中间的margin, 然后计算第一个按钮的x值(marginLeft)。 66         5> 在循环中, 计算每个按钮的x值(y值都是0)。 67  68  69  70 6. 动态生成"待选项按钮" 71     * 思路: 72     0> 在点击"下一题"按钮中实现该功能 73     1> 创建一个UIView来存放所有的"待选项按钮" 74     2> 根据待选项按钮的个数来创建 75     3> 清除之前的待选项按钮 76     4> 利用九宫格的算法创建待选项按钮 77  78 7. 实现"待选按钮"的单击事件 79     * 隐藏当前被点击的"待选按钮" 80     * 将当前被点击的"待选按钮"的文字显示到"答案按钮"的左起第一个为空的按钮上 81     * 如果"答案按钮"已经全部填满了, 不允许再点击"待选按钮" 82  83     ** 注意: 只要父控件不能处理事件, 那么子控件也无法处理事件(另外一种解决方案)。 84     1> 如果"答案按钮"文字填满了, 则设置option view禁止与用户交互 85         self.optionsView.userInteractionEnabled = NO; 86  87     2> 当用户再次点击"答案按钮"时 或 点击"下一题"后在创建"待选按钮"的时候再次启用option view与用户的交互功能 88         self.optionsView.userInteractionEnabled = YES; 89  90  91  92  93 8. 实现"答案按钮"的单击事件 94     * 设置被点击的"答案按钮"文字为空(nil) 95     * 设置与当前被点击的"答案按钮"相对应的"待选按钮"显示出来 96     ( 97      ** 注意:当答案按钮中有两个相同的文字的option按钮时的问题 98      ** 解决方案一: 99         1> 为每个option按钮设置一个唯一的tag100         2> 在点击某个option按钮的时候, 把option按钮的text和tag都设置到answer按钮上101         3> 在点击answer按钮的时候, 判断answer按钮的文字与tag同时都与某个option按钮匹配时, 再显示这个option按钮102      ** 解决方案二:103         执行判断的时候,并且判断字体的hidden属性为YES104      )105     * 设置所有"答案按钮"的文字颜色为黑色106 107 108 9. 在"待选按钮"的单击事件中, 判断当前的答案的正确性109     * 每次点击"待选按钮"都需要做判断, 如果答案按钮"满了", 再去判断正确性110     * 如果正确:111     1> 那么设置"答案按钮"的文字颜色为蓝色112     2> 加分113     3> 2秒钟后自动跳转到下一题114 115     * 如果错误:116     1> 答案按钮的文字设置为红色117 118 119 10. 点击"提示"按钮120     * 加分121     * 清空所有"答案按钮"的文字(相当于点击了每一个"答案按钮", 不是简单的设置"答案按钮"的文字为nil)122     * 并将正确答案的第一个文字设置到第一个"答案按钮"上(相当于正确答案的option按钮被点击了), 通过调用字符串的substringToIndex:来截取第一个字符的字符串

[注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.VEVb.com/hukezhu/

 [注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.VEVb.com/hukezhu/

附上应用代码结构图:

  

storyboard拖线图:

 附上源代码:

KZAppModel.h

 1 // 2 //  KZAppModel.h 3 //  UI基础-04-05-16 4 // 5 //  Created by hukezhu on 15/5/16. 6 // 7 // 8  9 #import <Foundation/Foundation.h>10 11 @interface KZAppModel : NSObject12 @PRoperty (nonatomic,copy) NSString *answer;13 @property (nonatomic,copy) NSString *icon;14 @property (nonatomic,copy) NSString *title;15 @property (nonatomic,strong)NSArray *options;16 17 - (instancetype)initWithDict:(NSDictionary *)dict;18 19 + (instancetype)appWithDict:(NSDictionary *)dict;20 @end

KZAppModel.m

 1 // 2 //  KZAppModel.m 3 //  UI基础-04-05-16 4 // 5 //  Created by hukezhu on 15/5/16. 6 // 7 // 8  9 #import "KZAppModel.h"10 11 @implementation KZAppModel12 -(instancetype)initWithDict:(NSDictionary *)dict{13 14     if (self = [super init]) {15         self.answer = dict[@"answer"];16         self.icon = dict[@"icon"];17         self.title = dict[@"title"];18         self.options = dict[@"options"];19     }20     return self;21 }22 23 + (instancetype)appWithDict:(NSDictionary *)dict{24 25     return  [[self alloc]initWithDict:dict];26 }27 @end

ViewController.m

  1 //  2 //  ViewController.m  3 //  01-超级猜图  4 //  5 //  Created by hukezhu on 15/5/16.  6 //  [注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.VEVb.com/hukezhu/  7 //  8   9 #import "ViewController.h" 10 #import "KZAppModel.h" 11  12 @interface ViewController () 13 @property (nonatomic,assign)int index; 14 @property (weak, nonatomic) IBOutlet UIButton *big; 15 @property (weak, nonatomic) IBOutlet UIButton *head; 16 @property (weak, nonatomic) IBOutlet UILabel *noLabel; 17 @property (weak, nonatomic) IBOutlet UILabel *titleLabel; 18 - (IBAction)nextClick; 19 @property (weak, nonatomic) IBOutlet UIView *answerView; 20 @property (weak, nonatomic) IBOutlet UIView *optionView; 21 @property (weak, nonatomic) IBOutlet UIButton *coinBtn; 22 - (IBAction)tipClick; 23  24 - (IBAction)bigImg; 25 - (IBAction)headClick; 26  27 @property (nonatomic,strong) UIButton *cover; 28 @property (nonatomic,strong)NSArray *questions; 29 @end 30  31 @implementation ViewController 32  33 - (void)viewDidLoad { 34     [super viewDidLoad]; 35     self.index = -1; 36     [self nextClick]; 37  38 } 39  40 /** 41  *  懒记载 42  */ 43 - (IBAction)nextClick { 44     //判断当前索引,如果到达数据数组长度减1 45     if (self.index == self.questions.count - 1  ) { 46         UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"已经到达最后一张图片" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil]; 47         [alert show]; 48         return; 49     } 50      51     self.index++; 52      53     //创建一个模型,存储数据 54     KZAppModel *appModel = self.questions[self.index]; 55  56     //添加数据 57     [self addData:appModel]; 58      59     //添加答案按钮 60     [self addAnswerBtn:appModel]; 61      62     //添加待选项按钮 63     [self addOptionBtn:appModel]; 64 } 65  66  67  68 /** 69  *  添加待选项按钮 70  * 71  *  @param appModel 数据模型 72  */ 73 - (void)addOptionBtn:(KZAppModel *)appModel{ 74  75     //清除之前的待选项按钮 76     [self.optionView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 77     //定义每行显示的待选项按钮的个数 78     int totalCol = 7; 79     CGFloat optionW = 40; 80     CGFloat optionH = 40; 81     CGFloat optionMargin = 10; 82     //左边距 83     CGFloat leftOptionMargin = (self.optionView.frame.size.width - totalCol * optionW - (totalCol - 1 )*optionMargin)*0.5; 84     //遍历数组,创建待选项按钮(九宫格的创建方法) 85     for (int i = 0; i < appModel.options.count; i++) { 86          87         UIButton *optionBtn = [[UIButton alloc]init]; 88         //行号 89         int row = i  / totalCol; 90         //列号 91         int col = i % totalCol; 92         CGFloat optionX = leftOptionMargin + col * (optionMargin + optionW); 93         CGFloat optionY = optionMargin + row * (optionMargin + optionH); 94         optionBtn.frame = CGRectMake(optionX, optionY, optionW, optionH); 95         //设置两种状态下的背景图片 96         [optionBtn setBackgroundImage:[UIImage imageNamed:@"btn_option"] forState:UIControlStateNormal]; 97         [optionBtn setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted]; 98         //给这些待选项按钮添加文字 99         [optionBtn setTitle:appModel.options[i] forState:UIControlStateNormal];100         //设置字体颜色101         [optionBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];102         //将按钮添加到optionView中103         [self.optionView addSubview:optionBtn];104         105         //创建待选项按钮的点击方法106         [optionBtn addTarget:self action:@selector(optionClick:) forControlEvents:UIControlEventTouchUpInside];107         108     }109 110 }111 112 113 /**114  *  添加答案按钮115  *116  *  @param appModel 模型数据117  */118 - (void)addAnswerBtn:(KZAppModel *)appModel{119 120     //清除之前的答案按钮121     [self.answerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];122     123     124     125     CGFloat answerW = 30;126     CGFloat answerH = 30;127     CGFloat answerY = 0;128     CGFloat margin = 10;129     CGFloat leftMargin = (self.answerView.frame.size.width - appModel.answer.length *(margin + answerW))*0.5;130     //循环遍历数组,创建答案按钮131     for(int i = 0;  i < appModel.answer.length; i++){132         133         UIButton *answerBtn = [[UIButton alloc]init];134         135         CGFloat answerX =leftMargin + i *(margin + answerW);136         answerBtn.frame = CGRectMake(answerX, answerY, answerW, answerH);137         //设置背景图片138         [answerBtn setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState:UIControlStateNormal];139 140         //设置显示文字的颜色141         [answerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];142         [self.answerView addSubview:answerBtn];143         144         //创建点击按钮的点击响应方法145         [answerBtn addTarget:self action:@selector(answerClick:) forControlEvents:UIControlEventTouchUpInside];146     }147 148 }149 150 151 152 153 /**154  *  添加数据155  *156  *  @param appModel 数据模型157  */158 -(void)addData:(KZAppModel *)appModel{159 160 161     162     self.noLabel.text = [NSString stringWithFormat:@"%d/%ld",self.index + 1,self.questions.count];163     164     self.titleLabel.text = appModel.title;165     166     [self.head setImage:[UIImage imageNamed:appModel.icon] forState:UIControlStateNormal];167 }168 169 170 - (void)optionClick:(UIButton *)optionBtn{171 172     //首先将被点击的待选项按钮的文字取到(后面会讲这个文字隐藏)173     NSString *title = [optionBtn currentTitle];174     optionBtn.hidden = YES;175 176     //循环遍历答案按钮,遇到第一个不为空的按钮,显示被点击的待选项按钮的文字177     for (UIButton *answerBtn in self.answerView.subviews) {178         if ([answerBtn currentTitle] == nil ) {179             [answerBtn setTitle:title forState:UIControlStateNormal];180             break;181         }182     }183     184     //判断答案是否为满,如果满了,就去判断对不对185     //定义一个可变的字符串,用来拼接循环得到的答案,得到这个答案,去和正确答案比较186     NSMutableString *tempString = [NSMutableString string];187     BOOL full = YES;188     189     //遍历数组,如果遇到按钮为空的话,就赋值full标记为no,表明没有满,否则的话就去拼接190     for (UIButton *answerBtn in self.answerView.subviews) {191          if ([answerBtn currentTitle] == nil ) {192              full = NO;193          }else{194          195              [tempString appendString:[answerBtn currentTitle]];196          }197         198     }199     if (full) {200         201         //NSLog(@"满了");202         KZAppModel *appModel = self.questions[self.index];203         for (UIButton *optionBtn in self.optionView.subviews) {204             optionBtn.enabled = NO;205         }206 207         208         if ([tempString isEqualToString:appModel.answer]) {209             NSLog(@"答对了");210             for (UIButton *answerBtn in self.answerView.subviews){211                 [answerBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];212 213             }214 //            int score = [self.coinBtn currentTitle].intValue ;215 //            score += 50;216 //            [self.coinBtn setTitle:[NSString stringWithFormat:@"%d",score] forState:UIControlStateNormal];217             [self score:50];218             219             [self performSelector:@selector(nextClick) withObject:nil afterDelay:2.0];220             221             222             223         }else{224         225             NSLog(@"没答对");226             for (UIButton *answerBtn in self.answerView.subviews){227                 [answerBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];228                 [self score:-200];229             }230         }231     }232 }233 234 /**235  *  答案选线点击的方法236  *237  */238 - (void)answerClick:(UIButton *)answerBtn{239 240     //循环遍历待选项按钮,找到与答案相同的文字,删除答案文字,显示待选项文字241     for (UIButton *optionBtn in self.optionView.subviews) {242         if ([[optionBtn currentTitle] isEqualToString:[answerBtn currentTitle]] && optionBtn.hidden == YES) {243             [answerBtn setTitle:nil forState:UIControlStateNormal];244             optionBtn.hidden = NO;245             for (UIButton *optionBtn in self.optionView.subviews) {246                 optionBtn.enabled = YES;247             }248         }249     }250     251     for (UIButton *answerBtn in self.answerView.subviews) {252         [answerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];253     }254 }255 256 257 /**258  *  点击提示的响应方法259  */260 - (IBAction)tipClick {261     //清除所有的答案按钮262     for (UIButton *answerBtn in self.answerView.subviews) {263         [self answerClick:answerBtn];264     }265     //取出正确答案,显示出来266     KZAppModel *appModel = self.questions[self.index];267     NSString *str = [appModel.answer substringToIndex:1];268     269     270 //    /**271 //     *  最开始想的是这种方法,但是发现更好的办法,,就相当于点击了对应的待选项按钮272 //     */273 //    [self.answerView.subviews[0] setTitle:str forState:UIControlStateNormal];274 //    [self.answerView.subviews[0] setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];275     276     for (UIButton *optionBtn in self.optionView.subviews) {277         if ([[optionBtn currentTitle] isEqualToString:str]) {278             [self optionClick:optionBtn];279         }280     }281     282     [self score:-100];283     284     285 }286 287 - (IBAction)bigImg {288     //点击大图之后,先创建一个阴影(button),289     UIButton *cover = [[UIButton alloc]init];290     self.cover = cover;291     cover.frame = self.view.bounds;292     [cover setBackgroundColor:[UIColor blackColor]];293     cover.alpha = 0.0;294     [self.view addSubview:cover];295     //调整图片和阴影位置296     [self.view bringSubviewToFront:self.head];297 298     [cover addTarget:self action:@selector(coverClick) forControlEvents:UIControlEventTouchUpInside];299     [UIView animateWithDuration:2.0 animations:^{300         cover.alpha = 0.6;301         //放大图片302         303         CGFloat headW = self.view.frame.size.width;304         CGFloat headH = headW;305         CGFloat headX = 0;306         CGFloat headY = 0.5 * (self.view.frame.size.height- headH);307         self.head.frame = CGRectMake(headX, headY, headW, headH);308         309     }];310     311 }312 313 314 /**315  *  计算分数方法316  *317  *  @param score 传入需要增加或者减少的分数(减为负)318  */319 - (void)score:(int)score{320 321     int tempScore = [self.coinBtn currentTitle].intValue ;322     tempScore += score;323     [self.coinBtn setTitle:[NSString stringWithFormat:@"%d",tempScore] forState:UIControlStateNormal];324     325 }326 327 /**328  *  图片放大状态下,点击阴影缩小图片329  */330 -(void)coverClick{331 332     if (self.cover != nil) {333         [self smallImg];334 335     }336 }337 /**338  *  点击头像图片,放大或缩小339  */340 - (IBAction)headClick {341     if (self.cover == nil) {342         [self bigImg];343     }else{344     345         [self smallImg];346     }347 }348 /**349  *  缩小图片的方法350  */351 - (void)smallImg{352 353 354     [UIView animateWithDuration:2.0 animations:^{355         self.cover.alpha = 0.0;356         self.head.frame = CGRectMake(97, 120, 180, 180);357         self.cover = nil;358     }];359     360 }361 362 363 364 /**365  *  懒加载数据366  *367  *  @return 返回数据368  */369 -(NSArray *)questions{370 371     if(_questions == nil){372         NSString *path = [[NSBundle mainBundle]pathForResource:@"questions" ofType:@"plist"];373         NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];374         NSMutableArray *tempArray = [NSMutableArray array];375         for (NSDictionary *dict in dictArray) {376             KZAppModel *appModel = [KZAppModel appWithDict:dict];377             [tempArray addObject:appModel];378         }379         _questions = tempArray;380     381     }382     return _questions;383 }384 385 @end

KVC大体介绍:

 1 KVC(Key Value Coding) 2     介绍: 通过给定一个对象的属性名称(以字符串方式), 然后找到对象的相应属性进行赋值。 3  4     * setValue:forKeyPath: 5     ** 示例: [self setValue:dict[@"icon"] forKeyPath:@"icon"] 6     ** 含义: 表示根据forKeyPath:@"icon"提供的@"icon"去self对象中查找名字叫icon的属性, 找到以后把dict[@"icon"]中获取到的值赋值给self的icon属性。 7  8  9     * setValuesForKyesWithDictionary:10     ** 含义: 更简便的调用方式。内部相当于调用了多次setValue:forKeyPath:11 12     ** 注意:13     1> 必须保证字典中的key与模型的属性名称一致。14     2> 必须保证模型的属性个数与字典一致或者模型的属性个数要大于等于字典的个数。15 16 * 演示KVC:17 1> 新建一个model类。18 2> 演示对字符串类型、数字类型进行KVC赋值19 3> 通过KVC取值。20 id v = [对象 valueForKeyPath:@"key"];21 int v1 = [[对象 valueForKeyPath:@"key"] intValue];22 23 4> 把模型转成字典, 把对象中指定的属性转换为字典。24 NSDictioanry *dict = [对象 dictionaryWithValuesForKeys:@[@"name", @"age"]];25 26 5> 把一个person数组中的每个person对象的name都获取出来然后放到一个新的数组中。27 (28     NSArray *names = [person数组 valueForKeyPath:@"name"];29 )30 31 6> keyPath介绍, 人拥有一本书, 通过kvc获取人所拥有的书的名称32 (33     NSString *bkName = [person valueForKeyPath:@"book.name"];34     35     等价于36     37     NSString *bkName = person.book.name;38 )39 40 * KVO (Key Value Observing), 监听对象的属性值变化。

[注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.VEVb.com/hukezhu/


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表