首页 > 代码库 > [iOS基础控件 - 4.5] 猜图游戏

[iOS基础控件 - 4.5] 猜图游戏

A.需要掌握的
1.添加图片资源(暂时认为@2x跟非@2x代表同一张图片)

2.搭建UI界面
* 文本标签
* 4个按钮
* 中间的图片

3.设置状态栏样式

4.监听下一题按钮的点击

5.延迟加载数据
* 加载plist
* 字典转模型
* KVC的引入

6.切换下一题的序号、图片、标题,下一题按钮的可用性

7.默认显示第1条题目

8.显示大图
* 监听中间图片点击
* 添加遮盖
* 移动图片(注意头像图片的层级顺序)
* 监听“大图按钮”

9.展示答案的个数

10.展示待选答案

11.答案处理

12.提示功能

13.Icon和Launch、@2x
 
B.实现思路
1.构建基本UI:
(1)背景
(2)按钮
(3)图片
(4)选项
 
2.数据存储与加载
(1)标题数据
(2)图片数据
(3)可选项数据
(4)答案数据
(5)得分数据
 
3.大图功能 (点击图片或者按钮)
(1)放大并调整图片位置
(2)虚化背景,使用半透明全覆盖的button
(3)点击背景或者图片,删除半透明背景、恢复图片
     a.动画效果, 使用带block参数方法
     b.播放完动画再移除阴影元素
 
4.下一题功能
其调用的功能是整个APP的核心,包含了初始化控件、加载文件数据、删除旧控件、加入新控件、刷新界面
 
5.提示功能
给出一定的答案
 
6.帮助功能
(在线分享功能,没有实现)
 
C.知识点
1.设置状态栏 (iOS7开始)
(1)设置样式
在Controller中重写preferredStateBarStyle方法,返回要设置的值
 1 // 设置状态栏是否隐藏 2 - (BOOL)prefersStatusBarHidden { 3     return NO; 4 } 5   6 // 设置状态栏 7 - (UIStatusBarStyle)preferredStatusBarStyle { 8     // 设置状态栏字体为白色 9     return UIStatusBarStyleLightContent;10 }
 
状态栏是显示黑色字体:
Image(21)
 
修改之后:
Image(22)
 
2.APP图标
只要文件名为 “Icon.png”,就会被设置为APP图标
 
3.启动画面
               一个app在启动过程中会全屏显示叫做Default.png的图片
               不用规格Default的使用场合
  1.      Default.png:非retina-iPhone屏幕,320x480
  2.          Default@2x.png:retina-iPhone屏幕,640x960
  3.          Default-568h@2x.png:4inch的retina-iPhone屏幕,640x1136
  4.          Default-Portrait~ipad.png:非retain-iPad竖屏屏幕,768x1024
  5.          Default-Portrait~ipad@2x.png:retain-iPad竖屏屏幕,1536x2048
  6.          Default-Landscape~ipad.png:非retain-iPad横屏屏幕,1024x768
  7.          Default-Landscape~ipad@2x.png:retain-iPad横屏屏幕,2048x1536
 
 
4.背景图和前景元素之间的层次关系
一般按照storyboard中的顺序排列
使用代码把某个元素提到最前
    // 2.更换阴影和图片的位置
    [self.view bringSubviewToFront:self.icon];
 
 
5.使用Button做出中间的图片
为了做出有白边效果的图片,使用了白色图片作为背景,然后设置图片的边距Inset,露出白色背景图
EA99AFD1-D3CC-4752-B1C2-C403A53469B2                   Image(23)
 
 
6.延迟加载数据
改写controller中的题目数组questions 的get方法,在调用get方法的时候检测questions是否已经存在,否则才开始加载
 
7.“大图”功能
虚化背景:使用一张半透明的图片遮挡
图片放大:使用形变转换
动画效果:使用带block参数的动画方法,设置动画事件、完成动画后消除遮盖回收内存
Image(24)
 
8.恢复图片
点击遮盖 / 点击放大后的图片:消除遮盖,恢复图片
 
9.消除button被点击的时候变灰
取消勾选 “Highlighted Adjusts Image”
310D161E-984E-467C-A35B-982ABEC2528B
 
10.显示答案
使用button, 动态生成相应数量的button
使用UIView作为父控件包含多个答案button
在storyboard中创建一个UIView,放到合适位置,调整尺寸
Image(25)
 
点击 "下一题” 按钮:
删除旧答案,自己控制自己从父视图删除
1     // 5.1 删除全部旧答案的button2     [self.answerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
 
添加新答案
Image(26)
 
 
11.加入选项
原理同答案模块,多了在行上面的位置计算
Image(27)
 
删除旧的所有选项,添加新的选项
1     // 6.1 删除旧选项2     [self.optionsView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
 
12.点击选项
(1)被点击的选项按钮消失(hidden = YES)
(2)将选中选项的文字放到答案区的按钮上
(3)把文字放到第一个没有文字的答案按钮上
(4)点击有文字的答案按钮,文字恢复到选项
(5)答案填满后,阻止事件触发
33FD92B2-FAD9-4C42-BB83-6C39A18794B9
 
13.点击有文字的答案按钮
(1)被点击的答案按钮文字消失
(2)让答案文字对应的选项重新出现
遍历所有选项,找到对应的选项进行设置
BC7D8FF5-C521-4D10-878C-1AF6A21CD412
 
14.判断答案正确
(1)遍历答案区,判断每个答案按钮是否有文字,如果都有文字,证明已经完成,检查答案
(2)答错答案文字变红,退选答案恢复文字颜色为黑色
(3)答对了给出提示,延迟1秒后跳入下一题
Image(28)
 
17.分数计算
答对加分
FA22DACD-0B66-4600-872C-1D9C1C64CE60
 
18.提示功能
取消现有的所有答案,给出正确答案的第一个字,扣一定分数
Image(29)
 
 
19.更改图标
图标有命名规范,最好使用 “icon.png"
把所有图标文件拖放到 “Images.xcassets” 的”AppIcon” 里面
70E67CAB-3903-4DCD-9FD8-056C59554929
 
Image(30)
 
20.修改启动画面
 
注意:
在现时最新版Xcode6.1中,默认使用 LaunchScreen.xib 作为启动画面
现在有两种方式设置启动图片
  • 使用 xib (LaunchScreen)
  • 使用 LaunchImage
 
启动页面配置:
项目 ==> general ==> App Icons and Launch Images
(1)使用 xib
a.默认状态就是使用 xib
Image(31)
 
b.如果现状态是使用LaunchImage, 设置 “Launch Images Source” 为 “Don’t use asset catalogs”
Image(32)
 
c.设置 xib 的文件名
Image(33)
 
d.在 xib 中设计
Image(34)
 
e.效果
Image(35)
 
 
(2)使用 LaunchImage
a.更改配置
项目 ==> general ==> App Icons and Launch Images ==> Launch Images Source 中选择 images,再把Launch Screen File 选项设置为空
922EB7CD-0780-4E6F-A2BD-7488C6B0CB0F
 
 
b.会发现Images.xcassets 下自动生成了一个 LaunchImage 的Imageset
Image(36)
 
c.拖入画面
Image(37)
 
d.效果
Image(38)
 
 
主要代码:
ViewController.m:
  1 //  2 //  ViewController.m  3 //  CrazyGuessGame  4 //  5 //  Created by hellovoidworld on 14/11/26.  6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved.  7 //  8   9 #import "ViewController.h" 10 #import "Question.h" 11  12 @interface ViewController () 13  14 @property (weak, nonatomic) IBOutlet UILabel *noLabel; // 序号 15 @property (weak, nonatomic) IBOutlet UILabel *titleLabel; // 标题 16 @property (weak, nonatomic) IBOutlet UIButton *icon; 17 @property (weak, nonatomic) IBOutlet UIButton *nextImageButton; 18 @property (weak, nonatomic) IBOutlet UIView *answerView; 19 @property (weak, nonatomic) IBOutlet UIView *optionsView; 20 @property (weak, nonatomic) IBOutlet UIButton *scoreButton; 21  22 - (IBAction)onTipsButtonClicked; 23 - (IBAction)onHelpButtonClicked; 24 - (IBAction)onEnlargeImgButtonClicked; 25 - (IBAction)onNextImgButtonClicked; 26 - (IBAction)onImageClicked; 27  28 /** 所有题目 */ 29 @property(nonatomic, strong) NSArray *questions; 30  31 /** 当前题目序号 */ 32 @property(nonatomic, assign) int index; 33  34 /** 遮盖阴影 */ 35 @property(nonatomic, weak) UIButton *cover; 36  37 /** 原始图片位置、尺寸 */ 38 @property(nonatomic, assign) CGRect imageOriginalFrame; 39  40 /** 答案是否已经填满标识 */ 41 @property(nonatomic, assign) BOOL isAnswerCompleted; 42  43 /** 得分 */ 44 @property(nonatomic, assign) int score; 45  46 @end 47  48 @implementation ViewController 49  50 - (void)viewDidLoad { 51     [super viewDidLoad]; 52     // Do any additional setup after loading the view, typically from a nib. 53     54     //存储原始图片的位置、尺寸信息 55     self.imageOriginalFrame = self.icon.frame; 56     57     self.index = -1; 58     [self onNextImgButtonClicked]; // 初次加载,index是0 59 } 60  61 - (void)didReceiveMemoryWarning { 62     [super didReceiveMemoryWarning]; 63     // Dispose of any resources that can be recreated. 64 } 65  66 // 改写getter, 延迟加载,此处不要使用self.questions来取得questions,否则陷入死循环 67 - (NSArray *)questions { 68     if (nil == _questions) { 69         // 1.加载plist数据 70         NSArray *questionDictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"questions" ofType:@"plist"]]; 71         72         NSMutableArray *questionsArray = [NSMutableArray array]; 73         for (NSDictionary *questionDict in questionDictArray) { 74             // 2.将数据封装到Model "Question" 75             Question *question = [Question initWithDictionary:questionDict]; 76             [questionsArray addObject:question]; 77         } 78  79         // 3.赋值 80         _questions = questionsArray; 81     } 82     83     return _questions; 84 } 85  86 // 设置状态栏是否隐藏 87 - (BOOL)prefersStatusBarHidden { 88     return NO; 89 } 90  91  92 // 设置状态栏 93 - (UIStatusBarStyle)preferredStatusBarStyle { 94     // 设置状态栏字体为白色 95     return UIStatusBarStyleLightContent; 96 } 97  98  99 // 点击“提示”按钮100 - (IBAction)onTipsButtonClicked {101     // 1.清除现有的答案102     for (UIButton *currentAnswerButton in self.answerView.subviews) {103         [self onAnswerClicked:currentAnswerButton];104     }105    106     // 2.取出正确答案片段107     Question *question = self.questions[self.index];108     NSString *partOfCorrectAnswer = [question.answer substringToIndex:1];109    110     // 3.填充到答案区111     for (UIButton *optionButton in self.optionsView.subviews) {112         if ([partOfCorrectAnswer isEqualToString:optionButton.currentTitle]) {113             [self onOptionClicked:optionButton];114         }115     }116    117     // 5.扣取相应分数118     [self calScore:-500];119 }120 121 // 点击“帮助”按钮122 - (IBAction)onHelpButtonClicked {123 }124 125 // 点击“大图”按钮126 - (IBAction)onEnlargeImgButtonClicked {127     // 1.1添加阴影128     UIButton *cover = [[UIButton alloc] init];129     cover.frame = self.view.bounds;130     cover.backgroundColor = [UIColor blackColor];131     cover.alpha = 0;132    133     // 1.2给阴影添加变回小图的触发事件134     [cover addTarget:self action:@selector(smallImg) forControlEvents:UIControlEventTouchUpInside];135    136     self.cover = cover;137     [self.view addSubview:cover];138    139     // 2.更换阴影和图片的位置140     [self.view bringSubviewToFront:self.icon];141    142     // 3.更改图像大小,显示阴影143     [UIView animateWithDuration:1 animations:^{144         cover.alpha = 0.7;145        146         CGFloat iconWidth = self.view.frame.size.width;147         CGFloat iconHeight = iconWidth;148         CGFloat iconX = 0;149         CGFloat iconY = (self.view.frame.size.height / 2) - (iconHeight / 2);150         self.icon.frame = CGRectMake(iconX, iconY, iconWidth, iconHeight);151     }];152 }153 154 /** 缩小图片 */155 - (void) smallImg {156     [UIView animateWithDuration:1 animations:^{157         // 1.删除阴影158         self.cover.alpha = 0;159        160         // 2.恢复图片161         self.icon.frame = self.imageOriginalFrame;162        163     } completion:^(BOOL finished) {164         // 动画执行完成后165        166         [self.cover removeFromSuperview];167         self.cover = nil;168     }];169    170 }171 172 // 点击“下一题”按钮173 - (IBAction)onNextImgButtonClicked {174     self.index++;175    176     // 1.取出相应地Model数据177     Question *question = self.questions[self.index];178 179     // 2.设置控件180     [self setControls:question];181    182     // 3.设置答案183     [self addAnswer:question];184    185     // 4.设置选项186     [self addOptions:question];187    188 189 }190 191 /** 设置控件 */192 - (void) setControls:(Question *) question {193     // 1.答案是否已经填满194     self.isAnswerCompleted = NO;195    196     // 2.得分197     [self.scoreButton setTitle:[NSString stringWithFormat:@"%d", self.score] forState:UIControlStateNormal];198    199     // 2.设置序号200     self.noLabel.text = [NSString stringWithFormat:@"%d/%d", self.index + 1, self.questions.count];201    202     // 3.设置标题203     self.titleLabel.text = question.title;204    205     // 4.设置图片206     [self.icon setImage:[UIImage imageNamed:question.icon] forState:UIControlStateNormal];207    208     // 5.设置“下一题”按钮209     self.nextImageButton.enabled = (self.index + 1) != self.questions.count;210 }211 212 /** 加入答案区 */213 - (void) addAnswer:(Question *) question {214     // 5.1 删除全部旧答案的button215     [self.answerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];216    217     // 5.1 加入新答案218     int answerCount = question.answer.length; // 答案字数219    220     // 初始化尺寸信息221     CGFloat answerWidth = 35;222     CGFloat answerHeight = self.answerView.frame.size.height;223     CGFloat answerMargin = 10;224     CGFloat answerMarginLeft = (self.answerView.frame.size.width - answerWidth * answerCount - answerMargin * (answerCount - 1) ) / 2;225    226     for (int i=0; i<question.answer.length; i++) {227         // 计算位置228         CGFloat answerX = answerMarginLeft + i * (answerWidth + answerMargin);229         CGFloat answerY = 0;230        231         UIButton *answerButton = [[UIButton alloc] initWithFrame:CGRectMake(answerX, answerY, answerWidth, answerHeight)];232        233         // 设置背景234         [answerButton setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState: UIControlStateNormal];235         [answerButton setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState: UIControlStateHighlighted];236        237         // 设置按钮点击事件,让按钮文字消失,相应的选项恢复238         [answerButton addTarget:self action:@selector(onAnswerClicked:) forControlEvents:UIControlEventTouchUpInside];239        240         [self.answerView addSubview:answerButton];241     }242    243     [self.view addSubview:self.answerView];244 }245 246 /**247     设置按钮点击事件,让按钮文字消失,相应的选项恢复248 */249 - (void) onAnswerClicked:(UIButton *) answerButton {250     // 1.设置答案标识251     self.isAnswerCompleted = NO;252    253     // 2.恢复相应的选项254     NSString *answerTitle = [answerButton titleForState:UIControlStateNormal];255     for (UIButton *optionButton in self.optionsView.subviews) {256         if ([answerTitle isEqualToString:[optionButton titleForState:UIControlStateNormal]]257             && optionButton.isHidden) {258             optionButton.hidden = NO;259             break;260         }261     }262    263     // 3.清除按钮上的文字264     [answerButton setTitle:nil forState:UIControlStateNormal];265    266     // 4.恢复答案文字颜色267     for (UIButton *answerButton in self.answerView.subviews) {268         [answerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];269     }270 }271 272 /** 加入选项区 */273 - (void) addOptions:(Question *) question {274     // 6.1 删除旧选项275     [self.optionsView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];276    277     // 6.2 加入新选项278     int optionsCount = question.options.count;279     CGFloat optionWidth = 35;280     CGFloat optionHeight = 35;281     int columnCount = 7;282     CGFloat optionMargin = 10;283     CGFloat optionMarginLeft = (self.optionsView.frame.size.width - optionWidth * columnCount - optionMargin * (columnCount - 1)) / 2;284    285     for (int i=0; i<optionsCount; i++) {286         int rowNo = i / columnCount; // 当前行号,从0开始287         int columnNo = i % columnCount; // 当前列号,从0开始288         CGFloat optionX = optionMarginLeft + columnNo * (optionWidth + optionMargin);289         CGFloat optionY = rowNo * (optionHeight + optionMargin);290        291         UIButton *optionButton = [[UIButton alloc] initWithFrame:CGRectMake(optionX, optionY, optionWidth, optionHeight)];292        293         [optionButton setBackgroundImage:[UIImage imageNamed:@"btn_option"] forState:UIControlStateNormal];294         [optionButton setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];295        296         [optionButton setTitle:question.options[i] forState:UIControlStateNormal];297        298         [optionButton addTarget:self action:@selector(onOptionClicked:) forControlEvents:UIControlEventTouchUpInside];299        300         [self.optionsView addSubview:optionButton];301     }302    303     [self.view addSubview:self.optionsView];304 }305 306 // 使点击到的选项消失 307 - (void) onOptionClicked:(UIButton *) optionButton {308     // 1.如果答案尚未填满,使选中的选项消失309     if (self.isAnswerCompleted) {310         return;311     }312    313     optionButton.hidden = YES;314    315     // 2.使消失的文字出现在答案区上,判断是否已经完成316     NSString *optionTitle = [optionButton titleForState:UIControlStateNormal];317    318     // 遍历答案按钮319     for (int i=0; i<self.answerView.subviews.count; i++) {320         // 已经遍历到了最后一个答案按钮,证明已经完成了所有答案321         if (i == self.answerView.subviews.count - 1) {322             self.isAnswerCompleted = YES;323         }324        325         UIButton *answerButton = self.answerView.subviews[i];326         NSString *answerTitle = [answerButton titleForState:UIControlStateNormal];327        328         // 如果该答案按钮上没有文字,则是空,填入文字329         if (answerTitle.length == 0) {330             // 按钮默认的字体颜色是白色, 手动设为黑色331             [answerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];332             [answerButton setTitle:optionTitle forState:UIControlStateNormal];333            334             break;335         }336     }337    338     [self dealWithAnswer];339 }340 341 /** 处理答案 */342 - (void) dealWithAnswer {343     if (self.isAnswerCompleted) {344         Question *question = self.questions[self.index];345         NSMutableString *answerStr = [NSMutableString string];346        347         // 拼接已经完成的答案348         for (UIButton *completedAnswerButton in self.answerView.subviews) {349             [answerStr appendString:[completedAnswerButton titleForState:UIControlStateNormal]];350         }351        352         // 如果答对了353         if ([answerStr isEqualToString:question.answer]) {354             // 答案字体转换称为蓝色355             for (UIButton *correctAnswerButton in self.answerView.subviews) {356                 [correctAnswerButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];357             }358            359             // 延迟指定时间后跳入下一题360             [self performSelector:@selector(onNextImgButtonClicked) withObject:nil afterDelay:0.5];361            362             // 加分363             [self calScore:1000];364         }365         else {366             for (UIButton *correctAnswerButton in self.answerView.subviews) {367                 // 答案字体转换称为红色368                 [correctAnswerButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];369             }370         }371     }372 }373 374 /** 原图状态点击放大,大图状态点击恢复原状 */375 - (IBAction)onImageClicked {376     // 使用遮盖是否存在判断图片状态377    378     // 1.遮盖不存在,放大图片379     if (nil == self.cover) {380         [self onEnlargeImgButtonClicked];381     }382     else {383     // 2.遮盖存在,恢复图片384         [self smallImg];385     }386 }387 388 /** 计算分数 */389 - (void) calScore:(int) score {390     self.score += score;391     [self.scoreButton setTitle:[NSString stringWithFormat:@"%d", self.score] forState:UIControlStateNormal];392 }393 394 @end
 
Question.h:
 1 // 2 //  Question.h 3 //  CrazyGuessGame 4 // 5 //  Created by hellovoidworld on 14/11/26. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8  9 #import <Foundation/Foundation.h>10 11 @interface Question : NSObject12 13 @property(nonatomic, copy) NSString *answer;14 @property(nonatomic, copy) NSString *title;15 @property(nonatomic, copy) NSString *icon;16 @property(nonatomic, strong) NSArray *options;17 18 - (instancetype) initWithDictionary:(NSDictionary *) dictionary;19 + (instancetype) initWithDictionary:(NSDictionary *) dictionary;20 21 @end
 
Question.m
 1 // 2 //  Question.m 3 //  CrazyGuessGame 4 // 5 //  Created by hellovoidworld on 14/11/26. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8  9 #import "Question.h"10 11 @implementation Question12 13 - (instancetype) initWithDictionary:(NSDictionary *) dictionary {14     if (self = [super init]) {15         self.title = dictionary[@"title"];16         self.icon = dictionary[@"icon"];17         self.answer = dictionary[@"answer"];18         self.options = dictionary[@"options"];19     }20    21     return self;22 }23 24 + (instancetype) initWithDictionary:(NSDictionary *) dictionary {25     return [[self alloc] initWithDictionary:dictionary];26 }27 28 @end
 
 

[iOS基础控件 - 4.5] 猜图游戏