现在的位置: 首页 > 综合 > 正文

猜图app

2018年05月26日 ⁄ 综合 ⁄ 共 9511字 ⁄ 字号 评论关闭

软件设计思路和需求分析:

1.主要用到UIButton和UILabel,由于在ios7中都是全屏显示,所以需要把状态栏手动显示出来

通过重写preferredStatusBarStyle方法,返回UIStatusBarStyleLightContent;即可显示出状态栏

2.游戏上半部分可以用storyboard设计,下半部分有两个View控件,并用代码动态添加答案按钮和备选按钮

3.素材信息存在plist中,所以程序运行前期可以懒加载plist,并实现字典转模型,这里用到KVC应用

key value coding 键值编码

使用setValuesForKeys时,要求

类中属性必须有字典中的所有键值,不可以少,可以多

类中成员都是字典中的属性,并提供2个类方法

在Controller中通过提供的类方法返回这个对象

4.图片放大:点击图片,点击“大图”

这里可以设置一个蒙板,当图片放大时,使蒙板的alpha从0.0变化到0.5,并设置图片移动到视图顶层,实现穿越功能,全程动画显示

计算好图片放大的目标位置后,动画显示

5.图片缩小:点击图片,点击蒙板

这里可以通过判断蒙板的alpha属性是否有值来决定是否缩小,获取到图片原先frame,动画缩小

6.下一题按钮的操作:

如果已经到最后一题,则返回通关提示

如果没有,则返回索引对象的题目模型,设置一系列属性值,并设置答案按钮的UIView布局和备选按钮的UIView布局

并为答案按钮设置点击事件,为备选按钮设置点击事件

7.提示按钮:

不管答案按钮中输入了多少个字,使用按钮的setTitle nil。。。方法清除已输入的值

获取当前题目的正确答案,并返回答案字符串的第一个字

使用一次提示,金币-1000分

8.备选按钮点击事件

点击一个按钮,隐藏它,并让它的值移动到空的答案按钮中,

如果输入完成后答案错误,则字体变红,

如果答案正确,则显示蓝色,并且金币+500分,等待0.5秒返回下一题事件

9.答案按钮点击事件

点击答案按钮的任意一个,则取消颜色,并返回使点击的按钮Title设为nil,按钮返回到原来的位置

10.收尾工作

app图标,通过images.xcassets中的AppIcon来设置

app初始界面通过LaunchImages来设置,

图片设置的时候还要区分3GS/4/5的像素问题

部分功能还可以使用其他特效或者方法,帮助按钮可以实现其他功能,预留。

一下为全部代码:

======questions.plist========

==============================Controller结构=================================

LFViewController.m:

#import "LFViewController.h"
#import "LFQuestion.h"

#define kButtonW 35.0
#define kButtonH 35.0
#define kButtonMargin 10.0
#define kTotalCol   7

@interface LFViewController ()

@property (weak, nonatomic) IBOutlet UILabel *noLabel;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *scoreButton;

/** 图片 */
@property (weak, nonatomic) IBOutlet UIButton *iconView;
/** 遮罩按钮 */
@property (nonatomic, strong) UIButton *cover;

@property (weak, nonatomic) IBOutlet UIButton *nextButton;
@property (weak, nonatomic) IBOutlet UIView *answerView;
@property (weak, nonatomic) IBOutlet UIView *optionView;

/** 题目列表 */
@property (nonatomic, strong) NSArray *questions;
/** 题目索引 */
@property (nonatomic, assign) int index;

@end

@implementation LFViewController

- (NSArray *)questions
{
    if (!_questions) {
        _questions = [LFQuestion questions];
    }
    
    return _questions;
}

- (UIButton *)cover
{
    if (!_cover) {
        _cover = [[UIButton alloc] initWithFrame:self.view.bounds];
        _cover.backgroundColor = [UIColor blackColor];
        _cover.alpha = 0.0f;
        
        [self.view addSubview:_cover];
        
        [_cover addTarget:self action:@selector(bigImage) forControlEvents:UIControlEventTouchUpInside];
    }
    return _cover;
}

- (void)viewDidLoad
{
    // 如果是"加载"对象的父类方法,父类方法的调用,要放在第一句
    [super viewDidLoad];
    
    self.index = -1;
    [self nextQuestion];
}

/** 修改状态栏 */
- (UIStatusBarStyle)preferredStatusBarStyle
{
    // 修改状态栏的颜色(白色)
    return UIStatusBarStyleLightContent;
}

/** 修改分数 */
// 抽代码的原则:
// 1> 将公共部分的代码抽取出来
// 2> 根据各自的特性设置参数
- (void)changeScore:(int)score
{
    int currentScore = [self.scoreButton.currentTitle intValue];
    currentScore += score;
    [self.scoreButton setTitle:[NSString stringWithFormat:@"%d", currentScore] forState:UIControlStateNormal];
}

/** 提示按钮 */
- (IBAction)tips
{
    // 1. 将答案区的所有按钮清空
    for (UIButton *btn in self.answerView.subviews) {
        [self answerClick:btn];
    }
    
    // 2. 找到正确答案的第一个字,显示到答案区中的第一个按钮上
    LFQuestion *question = self.questions[self.index];
    
    // 越光宝盒
    NSString *firstWord = [question.answer substringToIndex:1];
    // 3. 遍历所有的备选按钮,找到第一个匹配的文字,模拟点击
    for (UIButton *btn in self.optionView.subviews) {
        if ([btn.currentTitle isEqualToString:firstWord]) {
            [self optionClick:btn];
            
            // 减分操作
            [self changeScore:-1000];
            
            break;
        }
    }
}

/** 下一题 */
- (IBAction)nextQuestion
{
    // 1. 题目索引递增
    self.index++;
    
    if (self.index >= self.questions.count) {
        // 播放一个动画效果,或者其他的操作……
        NSLog(@"通关了!");
        
        return;
    }
    
    // 2. 取出索引对应的题目模型
    LFQuestion *question = self.questions[self.index];
    
    // 3. 设置基本信息
    [self setupBasicInfo:question];
    
    // 4. 创建答案按钮
    [self createAnswerButtons:question];
    
    // 5. 创建备选答案按钮
    [self createOptionButtons:question];
}

/** 设置基本信息 */
- (void)setupBasicInfo:(LFQuestion *)question
{
    self.noLabel.text = [NSString stringWithFormat:@"%d/%d", self.index + 1, self.questions.count];
    self.titleLabel.text = question.title;
    [self.iconView setImage:question.image forState:UIControlStateNormal];
    
    self.nextButton.enabled = (self.index != self.questions.count - 1);
}

/** 创建答案按钮 */
- (void)createAnswerButtons:(LFQuestion *)question
{
    // 0> 将答案区的按钮全部删除
    for (UIButton *btn in self.answerView.subviews) {
        [btn removeFromSuperview];
    }
    
    // 1> 按钮个数和答案的字数有关
    int length = question.answer.length;
    CGFloat answerViewW = self.answerView.bounds.size.width;
    CGFloat answerX = (answerViewW - length * kButtonW - (length - 1) * kButtonMargin) * 0.5;
    for (int i = 0; i < length; i++) {
        CGFloat x = answerX + i * (kButtonW + kButtonMargin);
        UIButton *answerBtn = [[UIButton alloc] initWithFrame:CGRectMake(x, 0, kButtonW, kButtonH)];
        [answerBtn setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState:UIControlStateNormal];
        [answerBtn setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState:UIControlStateHighlighted];
        
        [answerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        
        [self.answerView addSubview:answerBtn];
        
        // 添加监听方法
        [answerBtn addTarget:self action:@selector(answerClick:) forControlEvents:UIControlEventTouchUpInside];
    }
}

/** 创建备选答案按钮 */
- (void)createOptionButtons:(LFQuestion *)question
{
    // 判断备选区视图中按钮的个数,如果不等于question.options.count,删除原有按钮,重新新建
    if (self.optionView.subviews.count != question.options.count) {
        for (UIButton *btn in self.optionView.subviews) {
            [btn removeFromSuperview];
        }
        
        CGFloat optionViewW = self.optionView.bounds.size.width;
        CGFloat optionX = (optionViewW - kTotalCol * kButtonW - (kTotalCol - 1) * kButtonMargin) * 0.5;
        
        for (int i = 0; i < question.options.count; i++) {
            int row = i / kTotalCol;
            int col = i % kTotalCol;
            
            CGFloat x = optionX + col * (kButtonW + kButtonMargin);
            CGFloat y = row * (kButtonH + kButtonMargin);
            
            UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(x, y , kButtonW, kButtonH)];
            [btn setBackgroundImage:[UIImage imageNamed:@"btn_option"] forState:UIControlStateNormal];
            [btn setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
            
            [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            
            [self.optionView addSubview:btn];
            
            // 添加监听方法,点击事件
            [btn addTarget:self action:@selector(optionClick:) forControlEvents:UIControlEventTouchUpInside];
        }
    }
    
    // 设置按钮标题,遍历optionView,依次设置每一个按钮的标题
    int i = 0;
    for (UIButton *btn in self.optionView.subviews) {
        // 设置按钮标题
        [btn setTitle:question.options[i++] forState:UIControlStateNormal];
        // 恢复所有隐藏的按钮
        btn.hidden = NO;
    }
}

/** 答案按钮的点击事件 */
- (void)answerClick:(UIButton *)btn
{
    // 1. 是否有文字,如果没有,直接返回
    if (btn.currentTitle.length == 0) return;
    
    // 2. 如果有文字
    // 1> 将对应的备选按钮恢复隐藏
    for (UIButton *button in self.optionView.subviews) {
        if ([button.currentTitle isEqualToString:btn.currentTitle] && button.isHidden) {
            button.hidden = NO;
            
            // 2> 清空答案按钮中的文字
            [btn setTitle:nil forState:UIControlStateNormal];
            
            break;
        }
    }
    
    // 3. 点击答案按钮后,意味这答案不完整了,将所有按钮的颜色设置为黑色
    for (UIButton *btn in self.answerView.subviews) {
        [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    }
}

/** 备选按钮点击事件 */
- (void)optionClick:(UIButton *)btn
{
    // 1> 把备选按钮中的文字,填充到答案区
    // 找答案区中第一个按钮文字为空的按钮
    for (UIButton *button in self.answerView.subviews) {
        if (button.currentTitle.length == 0) {
            [button setTitle:btn.currentTitle forState:UIControlStateNormal];
            
            break;
        }
    }
    
    // 2> 把按钮隐藏
    btn.hidden = YES;
    
    // 3> 判断胜负
    // 3.1 所有的答案按钮都填满,遍历所有答案区的按钮
    BOOL isFull = YES;
    // 临时答案,供下面判断
    NSMutableString *strM = [NSMutableString string];
    
    for (UIButton *btn in self.answerView.subviews) {
        if (btn.currentTitle.length == 0) {
            // 没有填满
            isFull = NO;
            
            break;
        } else {
            [strM appendString:btn.currentTitle];
        }
    }
    
    if (isFull) {
        // 用户选择的答案和当前题目的答案向对比
        LFQuestion *question = self.questions[self.index];
        
        if ([question.answer isEqualToString:strM]) {
            // 修改答案区按钮的颜色 -> 蓝色
            for (UIButton *btn in self.answerView.subviews) {
                [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
            }
            
            // 加分操作
            [self changeScore:500];
            
            // 等待0.5s之后,跳到下一题
            [self performSelector:@selector(nextQuestion) withObject:nil afterDelay:0.5];
        } else {
            NSLog(@"错错错!");
            // 修改答案区按钮的颜色 -> 红色
            for (UIButton *btn in self.answerView.subviews) {
                [btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
            }
        }
    }
}

/** 大图 */
- (IBAction)bigImage
{
    /** 当按钮的alpha < 0.001 的时候,按钮不响应点击事件 */
    // 1. 增加蒙版(跟根视图一样大小)
    if (self.cover.alpha == 0.0) {
        // 2. 将图片移动到视图的顶层
        [self.view bringSubviewToFront:self.iconView];
        
        // 3. 动画放大图片
        // 1> 计算目标位置
        CGFloat viewW = self.view.bounds.size.width;
        CGFloat imageW = viewW;
        CGFloat imageH = imageW;
        CGFloat imageY = (self.view.bounds.size.height - imageH) * 0.5;
        
        [UIView animateWithDuration:1.0f animations:^{
            self.cover.alpha = 0.5;
            self.iconView.frame = CGRectMake(0, imageY, imageW, imageH);
        }];
    } else {
        // 图片已经是放大显示的了
        [UIView animateWithDuration:1.0 animations:^{
            // 1. 动画变小
            self.iconView.frame = CGRectMake(85, 80, 150, 150);
            // 2. 遮罩透明,看不见了
            self.cover.alpha = 0.0f;
        }];
    }
}

@end

================================题目模型结构==============================

LFQuestion.h:

#import <Foundation/Foundation.h>

@interface LFQuestion : NSObject

/** 答案 */
@property (nonatomic, copy) NSString *answer;
/** 提示文字 */
@property (nonatomic, copy) NSString *title;
/** 图片名称 */
@property (nonatomic, copy) NSString *icon;
/** 备选文字数组 */
@property (nonatomic, strong) NSArray *options;
/** 图像 */
@property (nonatomic, strong, readonly) UIImage *image;

/** 用字典实例化对象的成员方法 */
- (instancetype)initWithDict:(NSDictionary *)dict;
/** 用字典实例化对象的类方法,又称工厂方法 */
+ (instancetype)questionWithDict:(NSDictionary *)dict;

/** 从plist加载对象数组 */
+ (NSArray *)questions;

@end

LFQuestion.m:

#import "LFQuestion.h"

@interface LFQuestion()
{
    UIImage *_image;
}

@end

@implementation LFQuestion

- (UIImage *)image
{
    if (!_image) {
        _image = [UIImage imageNamed:self.icon];
    }
    
    return _image;
}

- (instancetype)initWithDict:(NSDictionary *)dict
{
    self = [super init];
    if (self) {
        // 使用setValuesForKeys要求类的属性必须在字典中存在,可以比字典中的键值多,但是不能少!
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

+ (instancetype)questionWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}

+ (NSArray *)questions
{
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"questions.plist" ofType:nil]];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    
    for (NSDictionary *dict in array) {
        [arrayM addObject:[LFQuestion questionWithDict:dict]];
    }
    
    return arrayM;
}

// 如果要在开发时,跟踪对象的明细信息,可以重写description方法,类似于java的toString()
- (NSString *)description
{
    // 包含对象类型名称,以及对象的指针地址
    return [NSString stringWithFormat:@"<%@: %p> {answer: %@, title: %@, icon: %@, options: %@}", [self class], self, self.answer, self.title, self.icon, self.options];
}

@end

【上篇】
【下篇】

抱歉!评论已关闭.