iOS学习之路-超级猜图

超级猜图,这个项目的代码敲完的时候,发现已经超过了400行,代码量已经远远超出了之前所学的了 。虽然代码量很多,但是知识点却都是之前学的,纵观整个项目,都没有新的知识点,可以这样说。在这个项目中,比较难理解的,就是添加答案按钮和待选项按钮的计算,以及对应的X轴和Y轴的计算了,也是比较繁琐的,还包括各种按钮的监听事件吧,要使用for循环遍历,使每个按钮都要注册监听器。整体情况完成的差不多,还有点bug吧,就看有没有大牛看到帮我解决了。

一、功能分析

1. 主要功能有提示、大图、下一题,回答问题。当用户点击提示时,会自动扣取相应的分数,并且将答案的第一个字填写到答案按钮中;当用户点击大图按钮或者图片时,将图片放大后放到屏幕的中央,并且屏幕的后面有一层阴影效果,当用户点击图片或者后面的阴影时,图片就会自动缩小会原来的位置,并且阴影消失。当用户点击下一题按钮时,图片会更换自下一题,对应的答案按钮的数量和待选项按钮和文字也会相对应的更改。

2. 当用户点击待选项按钮时,待选项按钮会被隐藏,而对应的文字则会显示在答案按钮中。当用户点击的答案正确时,字会变成蓝色,分数会增加,并且0.5秒后,自动跳到下一题 ;若答案不正确,则字体颜色变成红色。

3. 当进行到最后一道题时,用户再次点击了正确的答案后,答案按钮的字体仍变成蓝色,但是不会跳转道下一题,因为没有了下一题。


二、步骤分析

1. 先用storyboard搭建出基本的界面。显示题号的UILabel,显示题目的UILabel,显示图片的UIImageView,显示金币的UIButton,4个功能按钮UIButton。

2. 用for循环,创建出答案相对应个数的答案按钮以及待选项个数的待选项按钮。

3. 分别监听答案按钮、待选项按钮以及各种UIButton和UILabel等。

4. 完成答题的逻辑处理。


三、用户界面的设置和更改

1. 改变状态栏的样式

-(UIStatusBarStyle)perferredStatusBarStyle{
	return UIStatusBarStyleLightContent;
}
如果不添加该段代码的话,状态栏的颜色为黑色。添加这段代码后,状态栏颜色则变为白色。

2. 更还图片的内边距。为了美观,我们在UIImageView的Background设置成一张白色的图片,将Image设置成我们要的图片。然后在UIImageView的Attributes inspectors一栏中,将inset的四个数值分别设置成自己想要的边距就可以了。

3. 分数按钮的设置。为了让分数按钮失去点击的作用。我们一般将其Attributes inspectors一栏中user Interaction Enabled勾去掉。当然,将Control下的Content的Enabled的勾去掉也行,不过一般以去掉前者为主。

4.为了能让图片的大小可以被我们所更改,我们需要将File inspectors 下的use Auto Layout的选项取消打勾。不然,当我们点击图片和大图按钮的时候,图片的尺寸不会更改。


四、添加答案按钮和待选项按钮的算法分析

(1)每一行的y值相同,行号决定y的值。计算行号:int row = i / totalColumns;

(2)每一行的x值相同,列号觉得x的值。计算列号:int col = i % totalColumns;

(3)待选项按钮和答案按钮距离view的间距以及答案按钮的X值和待选项按钮的X值和Y值的计算,如下图所示。

这是计算答案按钮的leftMargin和X值。其中,answerW的值和margin的值需要我们自己定义。

这是计算待选项按钮的leftMargin和X的值以及Y的值。其中,optionW的值、optionH的值需要我们定义。

4. 相关代码

①添加存放答案的按钮

- (void)addAnswerBtn: (KIMQuestion *)question{
    //5.1 删除之前的答案框
    [self.answerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    //5.2 添加新的答案框
    unsigned long length = question.answer.length;
    for (int i = 0; i < length; i++) {
        UIButton *answerBtn = [[UIButton alloc]init];
        [answerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        // 设置背景
        [answerBtn setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState:UIControlStateNormal];
        [answerBtn setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState:UIControlStateHighlighted];
        // 设置frame
        CGFloat margin = 10;
        CGFloat answerW = 35;
        CGFloat answerH = 35;
        // 存放答案按钮的view的width = 当前view的width
        CGFloat viewW = self.view.frame.size.width;
        // 第一个按钮距离view的间距 = (viewW - 答案的长度 * 按钮的width - 每个按钮间距 *(个数 -1 ) )*0.5
        CGFloat leftMargin = (viewW - length * answerW - margin * (length - 1) )* 0.5;
        CGFloat answerX = leftMargin + i * (answerW + margin);
        answerBtn.frame = CGRectMake(answerX, 0, answerW, answerH);
        // 将answerBtn添加到answerView
        [self.answerView addSubview:answerBtn];
        // 监听点击
        [answerBtn addTarget:self action:@selector(answerClick:) forControlEvents:UIControlEventTouchUpInside];
    }

}
②添加待选项的按钮

- (void)addOptionBtn: (KIMQuestion *)question{
    //6.1 删除之前的待选项
    [self.optionView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    //6.2 添加新的待选按钮
    unsigned long count = question.options.count;
    for (int i = 0; i < count; i++) {
        UIButton *optionBtn = [[UIButton alloc]init];
        // 设置背景
        [optionBtn setBackgroundImage:[UIImage imageNamed:@"btn_option"] forState:UIControlStateNormal];
        [optionBtn setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
        // 设置frame
        CGFloat optionW = 35;
        CGFloat optionH = 35;
        CGFloat margin = 10;
        int totalColumns = 8;
        CGFloat viewW = self.view.frame.size.width;
        CGFloat leftMargin = (viewW - totalColumns * optionW - margin * (totalColumns - 1)) * 0.5;
        int col = i % totalColumns;
        CGFloat optionX = leftMargin + col * (optionW + margin);
        int row = i / totalColumns;
        CGFloat optionY = row * (optionH + margin);
        optionBtn.frame = CGRectMake(optionX, optionY, optionW, optionH);
        // 设置文字
        [optionBtn setTitle:question.options[i] forState:UIControlStateNormal];
        [optionBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        // 将optionBtn添加到optionView
        [self.optionView addSubview:optionBtn];
        // 监听点击
        [optionBtn addTarget:self action:@selector(optionClick:) forControlEvents:UIControlEventTouchUpInside];
    }

}


五、部分代码及说明

(1)监听答案按钮的点击。

当待选项按钮optionBtn的hidden属性 = NO时,显示之前被隐藏的optionBtn。

② optionBtn.currentTitle 和answerBtn.currentTitle 是获取当前待选项按钮和答案按钮的Title。

③ 想让用户点击的答案按钮的文字消失时,只需要将其Title设置成nil即可。

- (void)answerClick:(UIButton *)answerBtn{
    // 1.让答案按钮文字对应的待选按钮显示(hidden = NO)
    for (UIButton *optionBtn in self.optionView.subviews) {
        if ([optionBtn.currentTitle isEqualToString:answerBtn.currentTitle]) {
            optionBtn.hidden = NO;
            break;           // 停止遍历
        }
    }
    // 2.让被点击的答案按钮的文字消失
    [answerBtn setTitle:nil forState:UIControlStateNormal];
    // 3.让所有的答案按钮变为黑色
    for (UIButton *answerBtn in self.answerView.subviews) {
        [answerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    }
    
}
(2)监听待选项按钮的点击

① 当optionBtn的hidden属性 = YES时,对应点击的optionBtn将会暂时被隐藏。

② 调用的titleForState方法。传的参数一般设置为UIControlStateNormal,即普通状态下的文字。

- (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.判断答案的正确性
    [self chickAnswer];
}
(3)判断答案的正确性

① 先判断答案按钮是否有文字,当有文字时,调用appendString方法,将其答案按钮的文字进行拼接,并保存到tempAnswerTitle数组中。

② 当答案按钮被填满字时,取出模型类的答案数据,与tempAnswerTitle进行比较。若两者相同,则将答案文字设置为蓝色,分数增加相应分值,并且跳到下一题。

- (void)chickAnswer{
    BOOL full = YES;
    NSMutableString *tempAnswerTitle = [NSMutableString string];
    for (UIButton *answerBtn in self.answerView.subviews) {
        if (answerBtn.currentTitle.length == 0) {  //没有文字
            full = NO;
        }
        // 拼接按钮文字
        if(answerBtn.currentTitle){
            [tempAnswerTitle appendString:answerBtn.currentTitle];
        }
    }
    if(full){
        KIMQuestion *question = self.questions[self.index];
        if ([tempAnswerTitle isEqualToString:question.answer]) { // 答案正确,将文字的颜色更改为蓝色
            for (UIButton *answerBtn in self.answerView.subviews){
                [answerBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
            }
            // 分数增加100
            [self addScore:100];
            // 0.5秒后跳到下一题
            // 必须加一个判断标志,如果没有判断,进行到最后一道题,再答对的话,程序会闪退
            if(self.index != self.questions.count - 1){
                [self performSelector:@selector(next) withObject:nil afterDelay:0.5];
            }
        }else{      // 答案错误,将文字的颜色更改为红色
            for (UIButton *answerBtn in self.answerView.subviews) {
                [answerBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
            }
        }
    }
}

(4)监听放大按钮事件

① alloc一个按钮对象,设置frame,背景颜色及透明度alpha = 0.0。

② 为阴影注册缩小图片的监听器。

③ 交换图片和阴影的层顺序

④ 用block动画更改阴影的透明度以图片的大小。

- (IBAction)bigImage {
    //1. 添加阴影
    UIButton *shadow = [[UIButton alloc]init];
    shadow.frame = self.view.bounds;
    shadow.backgroundColor = [UIColor blackColor];
    shadow.alpha = 0.0;
    [shadow addTarget:self action:@selector(smallImag) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:shadow];
    self.shadow = shadow;
    //2. 调整图片和阴影的先后顺序
    [self.view bringSubviewToFront:self.iconBtn];
    [UIView animateWithDuration:0.25 animations:^{
        shadow.alpha = 0.7;
        //3. 更改图片的frame
        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);
    }];
    
}
(5)监听点击提示按钮事件

① 先把用户点击的答案按钮的文字去掉,for循环为answerBtn注册answerClick监听器即可。相当于用户点击了答案按钮。

② 取出模型答案的第一个字,循环遍历待选项按钮的文字,若遍历到待选项按钮的文字与答案的第一个字相符时,停止遍历,并将该待选项按钮的文字添加到第一个答案按钮中,对应的待选项按钮隐藏,即相当于点击了待选项按钮事件。最后,分数减少对应的数值。

- (IBAction)tip {
    // 1.把所有答案按钮的文字去掉,并将隐藏的待选项按钮显示
    for (UIButton *answerBtn in self.answerView.subviews) {
        [self answerClick:answerBtn];
    }
    // 2.取出模型的答案
    KIMQuestion *question =self.questions[self.index];
    // 2.1取出答案的第一个字
    NSString *firstAnswer = [question.answer substringToIndex:1];
    for (UIButton *optionBtn in self.optionView.subviews) {
        if ([optionBtn.currentTitle isEqualToString:firstAnswer]) {
            [self optionClick:optionBtn];
            [self addScore:-200];
            break;
        }
    }
}

六、运行结果

由运行结果可知,当输入的答案不正确时,答案按钮的字体颜色就会变成红色。但输入的答案正确时,答案按钮的颜色就会变成蓝色,但由于是最后一道题,所以不会跳转到下一题此时,下一题按钮也变成了灰色,不可点击的状态。


七、总结

都实现了基本的功能,但还存在着不少问题。首先第一次在真机测试的时,到了最后一道题,在输入正确的答案后,程序闪退了。之后,在模拟器测试也是这样,分析了下,原来是数组越界了。因为到了最后的一道题,当再次调用next下一题方法时,就会导致数组越界的错误。解决方法时,只要加一个判断标志就可以了。其次,当用户输入了不正确的答案时,答案按钮上的字就会变成红色,但此时,当用户继续点击待选项按钮时,待选项按钮还是会消失,但答案按钮因为文字满了,所以不会继续显示。点击答案按钮时,之前点击的文字会重新显示,但后来点击的待选项按钮却不会再次显示出来,这是一个bug吧,想了好久,还是解决不了。尝试过,如果答案按钮文字满后,将待选项按钮设置为不可用,但是一旦设置成不可用后,就不能再设置回可点击状态了。最后,就是求助功能还没有实现,待以后学习到,再回来完善这个项目。


——爱分享,一起学,共成长。


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值