UI之04 超级猜图

展示效果

Snip20160311_3.png

1. 界面分析

  • 发现我们的程序背景为深棕色的, 所以我们在搭建界面的时候, 首先要添加一个imageView
  • 发现最上面的状态栏为白色, 所以,我们需要专门设置一下状态栏的颜色
  • 上面有两个Lable一个显示第几题和总共有多少题 ; 另一个则显示对应图片相应的描述
  • 中间的那张图片必须是个button, 因为下面我们还要做关于放大缩小的操作
  • 中下的那几个白色的框框 , 是用来预先存储用户给的答案的, 当然, 真正的答案的字数是几个, 白色的框框也应相应的提供几个. 一旦答案正确文字显示蓝色, 一旦答案错误文字显示红色
  • 最下面的那个好几个待选答案, 其实是一个很大的UIView, 当然上面的白色框框后面也是一个UIView
Snip20160311_4.png
  • 当我们点击提示按钮的时候, 我们需要程序给出答案的第一个字
  • 当我们点击帮助的时候, 是没效果的(由于我们现在学的是UI基础, 所以还没有牵扯到这个联网方面的东西)
  • 当我们点击大图的时候, 中间的图片会放大, 而且一旦点击其他的地方, 或者是图片本身, 图片就会缩小到原来的尺寸
  • 当我们点击下一题的时候, 就会跳入下一题
  • 当我们点击下面的文字的时候, 文字相应的字会显示在上面的白色框框中, 如果答案正确, 会自动跳入下一题, 不正确也会跳入下一题
  • 当我们给的答案正确, 上面的金币数值会增加, 答错的时候, 会减少
  • 有一个注意点: 我们上面的分数, 其实是一个按钮button(因为只有button才可以完成既可以放图片, 又有可以放数据)但是这样做的话, 会使有些用户点击我们的分数的时候, 该按钮会有反馈, 所以我们需要这样做:
Snip20160311_7.png

其他具体的原理其实是和我们上一次讲的应用管理很相似所以这里关于剩下的就不做过多介绍了

2. 使用知识点分析

  • Xib的使用

  • plist文件如果做到由数组转模型, 再由模型向界面传入数据

  • 遮盖:
    这个遮盖用于当我们的图片放大的时候, 我们需要有一个遮盖将后面的所有的东西都遮盖起来, 防止用户点击:

Snip20160311_6.png
   // 1.添加阴影
UIButton *cover = [[UIButton alloc] init];
cover.frame = self.view.bounds;
cover.backgroundColor = [UIColor blackColor];
cover.alpha = 0.0;
[cover addTarget:self action:@selector(smallImg) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:cover];
self.cover = cover;

// 2.更换阴影和头像的位置
[self.view bringSubviewToFront:self.iconBtn];

// 3.执行动画
[UIView animateWithDuration:0.25 animations:^{
    // 3.1.阴影慢慢显示出来
    cover.alpha = 0.7;

这里面的执行动画是为了让我们的遮盖操作显得更加顺畅一些

3 . 连线

Snip20160311_5.png

关于上面的状态栏的改法:

/**
 *  控制状态栏的样式
 */
- (UIStatusBarStyle)preferredStatusBarStyle
{
    // 白色
    return UIStatusBarStyleLightContent;
}

4. 代码:

由于我们的plist文件, 中的数据转模型, 还有界面加载模型数据, 都是差不多的只是一个文件名称不一样而已,同样的需要增加一个模型类来存储我们的数据. 所以这里, 就不再写这个代码了 .
其实我就是想偷个懒罢了, 但是发现后面的知识点居然还要用这个代码, 我以为这个知识点我已经讲过了, 抱歉哈, 各位. 后面有补充的

#import "MJViewController.h"
#import "MJQuestion.h"

@interface MJViewController ()
- (IBAction)tip;
- (IBAction)bigImg;
- (IBAction)help;
- (IBAction)nextQuestion;
- (IBAction)iconClick;
@property (weak, nonatomic) IBOutlet UIButton   *scoreBtn;

/** 存放正确答案按钮的view */
@property (weak, nonatomic) IBOutlet UIView *answerView;
@property (weak, nonatomic) IBOutlet UIView *optionView;


/** 序号 */
@property (weak, nonatomic) IBOutlet UILabel *noLabel;
/** 标题 */
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
/** 头像(图标) */
@property (weak, nonatomic) IBOutlet UIButton *iconBtn;
/** 下一题按钮 */
@property (weak, nonatomic) IBOutlet UIButton *nextQuestionBtn;

  /** 遮盖 */
@property (nonatomic, weak) UIButton *cover;

/** 所有的题目 */
@property (nonatomic, strong) NSArray *questions;

/** 当前是第几题(当前题目的序号) */
@property (nonatomic, assign) int index;
@end

@implementation MJViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 默认显示index=0对应的题目
    self.index = -1;
    [self nextQuestion];
}

- (NSArray *)questions
{
    if (_questions == nil) {
        // 1.加载plist
        NSArray *dictArray = [NSArray     arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"questions" ofType:@"plist"]];
    
        // 2.字典转模型
        NSMutableArray *questionArray = [NSMutableArray array];
        for (NSDictionary *dict in dictArray) {
            MJQuestion *question = [MJQuestion questionWithDict:dict];
            [questionArray addObject:question];
        }
    
        // 3.赋值
        _questions = questionArray;
    }    
    return _questions;
}

/**
 *  添加分数
 *
 *  @param deltaScore 需要添加多少分
 */
- (void)addScore:(int)deltaScore
{
    int score = [self.scoreBtn     titleForState:UIControlStateNormal].intValue;
    score += deltaScore;
    [self.scoreBtn setTitle:[NSString     stringWithFormat:@"%d", score]     forState:UIControlStateNormal];
}

/**
 *  提示
 */
- (IBAction)tip {
    // 1.点击所有的答案按钮
    for (UIButton *answerBtn in self.answerView.subviews) {
        [self answerClick:answerBtn];
    }

    // 2.取出答案
    MJQuestion *question = self.questions[self.index];
    // 答案的第一个文字
    NSString *firstAnswer = [question.answer substringToIndex:1];
    for (UIButton *optionBtn in self.optionView.subviews) {
        if ([optionBtn.currentTitle isEqualToString:firstAnswer]) {
            [self optionClick:optionBtn];
            break;
        }
    }

    // 3.扣分
    [self addScore:-1000];
}

/**
 *  控制状态栏的样式
 */
- (UIStatusBarStyle)preferredStatusBarStyle
{
    // 白色
    return UIStatusBarStyleLightContent;
}

/**
 *  下一题
 */
- (IBAction)nextQuestion {
    // 1.增加索引
    self.index++;

    // 2.取出模型
    MJQuestion *question = self.questions[self.index];

    // 3.设置控件的数据
    [self settingData:question];

    // 4.添加正确答案
    [self addAnswerBtn:question];

    // 5.添加待选项
    [self addOptionBtn:question];
}

/**
 *  设置控件的数据
 */
- (void)settingData:(MJQuestion *)question
{
    // 3.1.设置序号
    self.noLabel.text = [NSString     stringWithFormat:@"%d/%d", self.index + 1,     self.questions.count];

    // 3.2.设置标题
    self.titleLabel.text = question.title;

    // 3.3.设置图片
    [self.iconBtn setImage:[UIImage     imageNamed:question.icon]     forState:UIControlStateNormal];

    // 3.4.设置下一题按钮的状态
    self.nextQuestionBtn.enabled = self.index !=     (self.questions.count - 1);
}

/**
 *  添加待选项
 */
- (void)addOptionBtn:(MJQuestion *)question
{
    // 6.1.删掉之前的所有按钮
    [self.optionView.subviews     makeObjectsPerformSelector:@selector(removeFromSuperview)];
//    for (UIView *subview in self.optionView.subviews) {
//        [subview removeFromSuperview];
//    }

    // 6.2.添加新的待选按钮
    int count = question.options.count;
    for (int i = 0; i<count; i++) {
        // 6.2.1.创建按钮
        UIButton *optionBtn = [[UIButton alloc] init];
    
        // 6.2.2.设置背景
        [optionBtn setBackgroundImage:[UIImage imageNamed:@"btn_option"]   forState:UIControlStateNormal];
        [optionBtn setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
    
        // 6.2.3.设置frame
        // 按钮尺寸
        CGFloat optionW = 35;
        CGFloat optionH = 35;
        // 按钮之间的间距
        CGFloat margin = 10;
        // 控制器view的宽度
        CGFloat viewW = self.view.frame.size.width;
        // 总列数
        int totalColumns = 7;
        // 最左边的间距 = 0.5 * (控制器view的宽度 - 总列数 * 按钮宽度 - (总列数 - 1) * 按钮之间的间距)
        CGFloat leftMargin = (viewW - totalColumns * optionW - margin * (totalColumns - 1)) * 0.5;
        int col = i % totalColumns;
        // 按钮的x = 最左边的间距 + 列号 * (按钮宽度 + 按钮之间的间距)
        CGFloat optionX = leftMargin + col * (optionW + margin);
        int row = i / totalColumns;
        // 按钮的y = 行号 * (按钮高度 + 按钮之间的间距)
        CGFloat optionY = row * (optionH + margin);
        optionBtn.frame = CGRectMake(optionX, optionY, optionW, optionH);
    
        // 6.2.4.设置文字
        [optionBtn setTitle:question.options[i] forState:UIControlStateNormal];
        [optionBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    
        // 6.2.5.添加
        [self.optionView addSubview:optionBtn];
    
        // 6.2.6.监听点击
        [optionBtn addTarget:self action:@selector(optionClick:)     forControlEvents:UIControlEventTouchUpInside];
    }
}

/**
 *  监听待选按钮的点击
 */
- (void)optionClick:(UIButton *)optionBtn
{
    // 1.让被点击的待选按钮消失
    optionBtn.hidden = YES;

    // 2.显示文字到正确答案上
    for (UIButton *answerBtn in     self.answerView.subviews) {
        // 判断按钮是否有文字
        NSString *answerTitle = [answerBtn titleForState:UIControlStateNormal];
    
        if (answerTitle.length == 0) { // 没有文字
            // 设置答案按钮的 文字 为 被点击待选按钮的文字
            NSString *optionTitle = [optionBtn titleForState:UIControlStateNormal];
            [answerBtn setTitle:optionTitle forState:UIControlStateNormal];
            break; // 停止遍历
        }
    }

    // 3.检测答案是否填满
    BOOL full = YES;
    NSMutableString *tempAnswerTitle = [NSMutableString string];
    for (UIButton *answerBtn in self.answerView.subviews) {
        // 判断按钮是否有文字
        NSString *answerTitle = [answerBtn titleForState:UIControlStateNormal];
    
        if (answerTitle.length == 0) { // 没有文字(按钮没有填满)
            full = NO;
        }  
        // 拼接按钮文字
        if(answerTitle) {
            [tempAnswerTitle appendString:answerTitle];
        }
    }

    // 4.答案满了
    if (full) {
        MJQuestion *question = self.questions[self.index];
    
  
          if ([tempAnswerTitle isEqualToString:question.answer]) { // 答对了(文字显示蓝色)
            for (UIButton *answerBtn in self.answerView.subviews) {
                [answerBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
            }
            // 加分
            [self addScore:800];
            // 0.5秒后跳到下一题
            [self performSelector:@selector(nextQuestion) withObject:nil afterDelay:0.5];
        } else { // 答错了(文字显示红色)
            for (UIButton *answerBtn in self.answerView.subviews) {
                [answerBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
            }
        }
    }
}

/**
 *  添加正确答案
 */
- (void)addAnswerBtn:(MJQuestion *)question
{
    // 5.1.删除之前的所有按钮
    // 让数组中的所有对象都执行removeFromSuperview方法
    [self.answerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

    // 5.2.添加新的答案按钮
    int length = question.answer.length;
    for (int i = 0; i<length; i++) {
        // 5.2.1.创建按钮
        UIButton *answerBtn = [[UIButton alloc] init];
        [answerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    
        // 5.2.2.设置背景
        [answerBtn setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState:UIControlStateNormal];
        [answerBtn setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState:UIControlStateHighlighted];
    
        // 5.2.3.设置frame
        CGFloat viewW = self.view.frame.size.width;
        // 按钮之间的间距
        CGFloat margin = 10;
        // 按钮的尺寸
        CGFloat answerW = 35;
        CGFloat answerH = 35;
        // 最左边的间距 = 0.5 * (控制器view的宽度 - 按钮个数 * 按钮宽度 - (按钮个数 - 1) * 按钮之间的间距)
        CGFloat leftMargin = (viewW - length * answerW - margin * (length - 1)) * 0.5;
        // 按钮的x = 最左边的间距 + i * (按钮宽度 + 按钮之间的间距)
        CGFloat answerX = leftMargin + i * (answerW + margin);
        answerBtn.frame = CGRectMake(answerX, 0, answerW, answerH);
    
        // 5.2.4.添加
        [self.answerView addSubview:answerBtn];
    
        // 5.2.5.监听点击
        [answerBtn addTarget:self action:@selector(answerClick:) forControlEvents:UIControlEventTouchUpInside];
    }
}

/**
 *  监听答案按钮的点击
 */
- (void)answerClick:(UIButton *)answerBtn
{
    // 1.让答案按钮文字对应的待选按钮显示出来(hidden = NO)
    for (UIButton *optionBtn in self.optionView.subviews) {
        if ([optionBtn.currentTitle isEqualToString:answerBtn.currentTitle]
        
        && optionBtn.hidden == YES) { // 发现跟答案按钮相同文字的待选按钮
        
            optionBtn.hidden = NO;
            break;
        }
    }

    // 2.让被点击答案按钮的文字消失(去除文字)
    [answerBtn setTitle:nil     forState:UIControlStateNormal];

    // 3.让所有的答案按钮变为黑色
    for (UIButton *answerBtn in self.answerView.subviews) {
        [answerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    }
}

/**
 *  点击头像
 */
- (IBAction)iconClick {
    if (self.cover == nil) { // 没有遮盖,要放大
        [self bigImg];
    } else { // 有遮盖,要缩小
        [self smallImg];
    }
}

/**
 *  大图
 */
- (IBAction)bigImg {
    // 1.添加阴影
    UIButton *cover = [[UIButton alloc] init];
    cover.frame = self.view.bounds;
    cover.backgroundColor = [UIColor blackColor];
    cover.alpha = 0.0;
    [cover addTarget:self action:@selector(smallImg)     forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:cover];
    self.cover = cover;

    // 2.更换阴影和头像的位置
    [self.view bringSubviewToFront:self.iconBtn];

    // 3.执行动画
    [UIView animateWithDuration:0.25 animations:^{
        // 3.1.阴影慢慢显示出来
        cover.alpha = 0.7;
    
        // 3.2.头像慢慢变大,慢慢移动到屏幕的中间
        CGFloat iconW = self.view.frame.size.width;
        CGFloat iconH = iconW;
        CGFloat iconY = (self.view.frame.size.height - iconH) * 0.5;
        self.iconBtn.frame = CGRectMake(0, iconY, iconW, iconH);
    }];
}

/**
 *  小图
 */
- (void)smallImg
{
    // 执行动画
    [UIView animateWithDuration:0.25 animations:^{
        // 存放需要执行动画的代码
    
        // 1.头像慢慢变为原来的位置和尺寸
        self.iconBtn.frame = CGRectMake(85, 80, 150, 150);
    
        // 2.阴影慢慢消失
        self.cover.alpha = 0.0;
    } completion:^(BOOL finished) {
        // 动画执行完毕后会自动调用这个block内部的代码
    
        // 3.动画执行完毕后,移除遮盖(从内存中移除)
        [self.cover removeFromSuperview];
        self.cover = nil;
    }];
}

/**
 *  帮助
 */
- (IBAction)help {

}
@end

其他效果:

Snip20160311_9.png

以前我们做的应用都是像这个红色框框周围的一样, 没有图标, 现在我来说如何做出这样的图标

Snip20160311_10.png

很简单, 就是将这个资源直接拖入到这个文件夹中, 他会自动识别的:

还有一个: 打开应用之后显示的画面, 我们的手机中打开的一个程序之后, 就会出现类似的画面:

Snip20160311_12.png

这个也是直接拖入到我们的这个文件夹中

KVC

作用: 通过一个字符串类型的key找到对象相应的属性进行赋值
作用域: 一般用在字典和模型上

算了, 我还是老老实的把那个模型的代码写出来吧:

.h文件

#import <Foundation/Foundation.h>

@interface MJQuestion : NSObject
/**
 *  答案
 */
@property (nonatomic, copy) NSString *answer;
/**
 *  标题
 */
@property (nonatomic, copy) NSString *title;
/**
 *  图标
 */
@property (nonatomic, copy) NSString *icon;
/**
 *  待选项
 */
@property (nonatomic, strong) NSArray *options;

- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)questionWithDict:(NSDictionary *)dict;
@end

**.m文件代码: **

要是我们以前写应该怎么写???

    [self setValue:dict[@"icon"] forKeyPath:@"icon"];
    [self setValue:dict[@"title"] forKeyPath:@"title"];
   [self setValue:dict[@"answer"] forKeyPath:@"answer"];
   [self setValue:dict[@"options"] forKeyPath:@"options"];
    
    
    dict = @{
      @"icon" : @"abc.png",
      @"title" : @"黑社会大片",
      @"answer" : @"教父",
      @"options" : [@"哈", @"人"]
      };
     
     [self setValue:dict[@"icon"] forKeyPath:@"icon"];
     
     
    
    self.icon = dict[@"icon"];
   self.title = dict[@"title"];
   self.answer = dict[@"answer"];
    self.options = dict[@"options"];

大概就是这样吧. 但是一旦我们使用KVC之后我们的代码就变成这样了:

#import "MJQuestion.h"

@implementation MJQuestion
- (instancetype)initWithDict:(NSDictionary *)dict
{
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];

    }
    return self;
}

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

整个代码就是这样的, 所以KVC对我们来说是很有用的

当我们想集中取出我们某个对象的属性的时候(例如字典)但是我们的字典有没有这个属性,我们的系统就会更加深层次的将我们的字典里面的某些对象中的凡是含有这个属性的对象的这个属性给提取出来

当我们的某个对象含有某个对象属性的时候(例如我们的这个人具有书这个对象的属性)我们可以利用我们的KVC将我们的这个对象的属性对象的某个属性给提取出来
即:以上关于KVC的代码与我们下面的普通方法的作用相同

作者说:

  • 其实这只是KVC中浅层的东西, 但是现在我们用足够了, 所以, 以后我们在用plist文件导入的时候, 我们就可以直接用KVC这样会很省代码量的

  • 还有就是这学期的学业特别重, 好多都是比较难的科目, 外加上, 本人还要学习UI新的内容. 有可能更新的又慢了, 请各位见谅哈.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,509评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • ‖ 晚风迎来 梨柳悦动, 窗花纷落 喧景泷泷。 婕人观景 然愁忆君, 遥地碌碌 其独守禁。
    微yy阅读 169评论 12 5
  • 太过热情,总不被珍惜 但如果真的想要留住 还是要敞开怀抱吧 温柔地善良地拥抱着整个世界 因为总需要一个人先打开窗子...
    心蕊1999阅读 258评论 2 1