• UIKit之猜图器Demo


    需求

    实现猜图器Demo
    请添加图片描述

    1. 功能分解:
      1>下一题切换功能
      2>点击图片后能放大并背景变暗(本质是透明度的变化)。再次点击则缩小,删除暗色背景。
      在这里插入图片描述
      3> 答案区按钮点击则文字消失,选择区对应文字恢复。
      4> 选择区文字按钮点击则添加该文字到答案区。
      5> 点击提示使得答案对应的第一个字符的按钮添加入答案区。

    分析:

    界面主要由如下三部分组成:top、middle、bottom。
    在这里插入图片描述
    由于上半部分的组件多是直接交互,所以写为该视图类的成员变量,而中部和下部,按钮单一,且一般都是多个按钮一起有响应动作发生:如删除、创建等,所以写入仅需两个视图成员:viewmiddle、viewbottom。
    综上,涉及组件有:

    UIButton、UILabel、UIView
    1 右上角积分不可点击,但是有图片,又有文字,所以用UIButton,取消交互属性
    2 中间图片可点击,用UIButton而不是UIIMageView
    3 点击中间图片生成阴影,而点击阴影后回退到之前界面,说明阴影本质是带背景色的图片。

    代码实现:

    1. VC处调用代码:
    {
    	[self testCaiTuDemo];
    }
    - (void) testCaiTuDemo{
        // 2. 猜图器上半视图
        CaiTuViewTop * viewtop = [[CaiTuViewTop alloc] initWithFrame:CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height)];
        [self.view addSubview:viewtop];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 界面构成:
      自定义视图类:
      界面上半部分组件多直接交互,故写直接创建为成员变量,而中部和下部,按钮单一,一般是多个按钮产生有响应动作:如删除、创建等,故写入仅需两个视图成员:viewmiddle、viewbottom。
    #import <UIKit/UIKit.h>
    #import "CZQuestion.h"
    
    NS_ASSUME_NONNULL_BEGIN
    @interface CaiTuViewTop : UIView
    @property(strong, nonatomic) UIButton *imgbtn;
    @property(strong, nonatomic) UIButton *l1btn;
    @property(strong, nonatomic) UIButton *l2btn;
    @property(strong, nonatomic) UIButton *r1btn;
    @property(strong, nonatomic) UIButton *r2btn;
    // 积分按钮:
    @property(strong, nonatomic) UIButton *topRightbtn;
    // 题号展示label
    @property(strong, nonatomic) UILabel *labtop1;
    // title
    @property(strong, nonatomic) UILabel *labtop2;
    // 当前题号
    @property (nonatomic, assign) int index;
    // ==== 猜图器plist信息 ====
    @property (nonatomic, strong) NSArray * questions;
    // 在放大缩小Frame时,存个原始frame来方便缩消回去 复原方便
    @property (nonatomic, assign) CGRect iconFrame;
    
    // 在某个个自定义方法中,获取其它自定义方法中创建的属性,是获取不到的
    // 为了删除放大后增加的btn背景视图,用来引用阴影按钮,方便找到并删除
    @property(nonatomic, weak) UIButton *coverView;
    @property(nonatomic, strong) UIView *viewmiddle;
    @property(nonatomic, strong) UIView *viewbottom;
    
    - (void)btnNxtClick;
    
    -(void)NxtQuestion;
    
    -(void)shrinkbgclick;
    
    -(void) selectBtnClick:(UIButton *)btn;
    
    @end
    NS_ASSUME_NONNULL_END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    1. 布局实现以及功能初始化:
      1> APP拥有酒红色背景图,通过创建UIImage类并添加到新建的UIImageView类对象中去,随后通过insertSubview添加到当前View。
      2> 创建App顶部各组件,注意右上角显示积分的UIButton需要设置取消交互,并注意图标在左而文字在右(设置Button的Image再设置Title即可,能左右分布的只能是IMage和Title)。
      3> 可点击图片的内边距设置:设置图片的backgroundImage后,再设置image,通过设置按钮的imageEdgeInsets
      4> 初始化题目信息。通过懒加载数据变量,设置界面显示第一题信息。
    -(instancetype) initWithFrame:(CGRect)frame{
        self = [super initWithFrame:frame];
        if(self){
            // 背景图
    #pragma mark - backGroundImage
            // 1. 设置背景图片,原理是加UIImageView视图,用UIIMage初始化该视图,并添加到self view
            UIImage *backgroundImage = [UIImage imageNamed:@"bj.png"]; // 从项目中加载图片
            UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
            backgroundImageView.frame = self.bounds; // 设置与 self.view 相同的 frame
            backgroundImageView.contentMode = UIViewContentModeScaleAspectFill; // 设置填充模式
            [self insertSubview:backgroundImageView atIndex:0]; // 将 imageView 添加到视图的最底层
            
    #pragma mark - ViewTop
            // 按钮:
            _imgbtn = [[UIButton alloc] initWithFrame:CGRectMake(108, 120, 200, 200)];
            _l1btn = [[UIButton alloc] initWithFrame:CGRectMake(20, 210, 65, 35)];
            _l2btn = [[UIButton alloc] initWithFrame:CGRectMake(20, 274, 65, 35)];
            _r1btn = [[UIButton alloc] initWithFrame:CGRectMake(315, 210, 70, 35)];
            _r2btn = [[UIButton alloc] initWithFrame:CGRectMake(315, 274, 70, 35)];
            _topRightbtn = [[UIButton alloc] initWithFrame:CGRectMake(311, 73, 42, 20)];
            // 根据外面的初始化情况:设置width为屏宽,再设置左边距为0,直接设置text居中即可
            _labtop1 = [[UILabel alloc] initWithFrame:CGRectMake(0, 50, self.frame.size.width, 21)];
            // self.frame.size.width:因为
            _labtop2 = [[UILabel alloc] initWithFrame:CGRectMake(0, 75, self.frame.size.width, 21)];
            _topRightbtn = [[UIButton alloc] initWithFrame:CGRectMake(300, 30, 100, 20)];
            
            [_topRightbtn setTitle:@"1000" forState:UIControlStateNormal];
            
            _labtop1.textColor = [UIColor whiteColor];
            _labtop2.textColor = [UIColor whiteColor];
            _topRightbtn.titleLabel.textColor = [UIColor whiteColor];
            
            _topRightbtn.font = [UIFont systemFontOfSize:12];
            [_topRightbtn setImage:[UIImage imageNamed:@"coin.png"] forState:UIControlStateNormal];
            _topRightbtn.titleLabel.textAlignment = NSTextAlignmentCenter;
            // 按钮禁止点击
            _topRightbtn.userInteractionEnabled = NO;
            
            // 页号:这些不用设置,交给VC调用处
            //        _labtop1.text = @"1/10";
            //        // 图片描述
            //        _labtop2.text = @"第一张图片";
            //        // UILabel文字居中
            //        _labtop1.textAlignment = NSTextAlignmentCenter;
            //        _labtop2.textAlignment = NSTextAlignmentCenter;
            //        // UILabel大小设置
            //        _labtop1.font = [UIFont systemFontOfSize:12];
            //        _labtop2.font = [UIFont systemFontOfSize:12];
            //
            
            
            // 带白色边框的背景图:用白色给按钮的背景图打底,再设置图片:
            // center_img
            [_imgbtn setBackgroundImage:[UIImage imageNamed:@"center_img.png"] forState:UIControlStateNormal];
            
            // 2.1 初始index为-1,初始label信息为index0的内容
            // 读取数据也通过 viewTop来获取
            // 初始为-1,++后使得索引为0,从0处开始获取信息
    #pragma mark - 初始化题目信息
            _index = -1;
            [self NxtQuestion];
            
            
            
            // 不显示的调试:网上也看到这种说不显示的例子了
            // center_img
            // people-wg:先往后做吧,然后在看着怎么设置
            // 图片像素太大,不显示
            //        [_imgbtn setImage:[UIImage imageNamed:@"people-cls.png"] forState:UIControlStateNormal];
            _imgbtn.contentMode = UIViewContentModeScaleAspectFit; // 或者使用其他contentMode
            
            // UIImage 的 scaling methods
            _imgbtn.imageEdgeInsets = UIEdgeInsetsMake(5, 5, 5, 5);
            // 点击不变灰色:取消高亮的接口:,showsHeighted已经不能用了
            _imgbtn.adjustsImageWhenHighlighted = NO;
            
            // 四周按钮
            [_l1btn setTitle:@"提示" forState:UIControlStateNormal];
            
            _l1btn.font = [UIFont systemFontOfSize:12];
            [_l1btn setImage:[UIImage imageNamed:@"icon_tip.png"] forState:UIControlStateNormal];
            [_l1btn setBackgroundImage:[UIImage imageNamed:@"btn_left"] forState:UIControlStateNormal];
            
            [_l2btn setTitle:@"帮助" forState:UIControlStateNormal];
            [_l2btn setImage:[UIImage imageNamed:@"icon_help.png"] forState:UIControlStateNormal];
            
            
            _l2btn.font = [UIFont systemFontOfSize:12];
            [_l2btn setBackgroundImage:[UIImage imageNamed:@"btn_left"] forState:UIControlStateNormal];
            
            [_r1btn setImage:[UIImage imageNamed:@"icon_img.png"] forState:UIControlStateNormal];
            [_r1btn setTitle:@"大图" forState:UIControlStateNormal];
            _r1btn.font = [UIFont systemFontOfSize:12];
            
            [_r1btn setBackgroundImage:[UIImage imageNamed:@"btn_right"] forState:UIControlStateNormal];
            
            [_r2btn setTitle:@"下一题" forState:UIControlStateNormal];
            
            
            _r2btn.font = [UIFont systemFontOfSize:12];
            [_r2btn setBackgroundImage:[UIImage imageNamed:@"btn_right"] forState:UIControlStateNormal];
            
            
    #pragma mark - btnAddTarget
            
            // 绑定帮助按钮的响应事件
            [_l1btn addTarget:self action:@selector(btnHelpClick) forControlEvents:UIControlEventTouchUpInside];
            
            // 绑定下一题按钮的响应事件
            [_r2btn addTarget:self action:@selector(btnNxtClick) forControlEvents:UIControlEventTouchUpInside];
            
            
            // 绑定响应事件
            [_r1btn addTarget:self action:@selector(EnlargeClick) forControlEvents:UIControlEventTouchUpInside];
            
            // 给头像绑定放大功能
            [_imgbtn addTarget:self action:@selector(imgBtnClick) forControlEvents:UIControlEventTouchUpInside];
            
            [self addSubview:_imgbtn];
            [self addSubview:_l1btn];
            [self addSubview:_l2btn];
            [self addSubview:_r1btn];
            [self addSubview:_r2btn];
            [self addSubview:_labtop1];
            [self addSubview:_labtop2];
            [self addSubview:_topRightbtn];
            
    #pragma mark - ViewMiddle
            // 宽度同当前
            _viewmiddle = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height/2.5, self.frame.size.width, 50)];
            //_viewmiddle.backgroundColor = [UIColor greenColor];
            
            
            // 没有添加进去,
            _viewbottom = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height/2, self.frame.size.width, 150)];
            // _viewbottom.backgroundColor = [UIColor greenColor];
            
    #pragma mark - 初始化答案区btn、带选取btn
            [self CreateAnswerBtn];
            [self CreateSelectBtn];
            
    #pragma mark - ViewBottom
            // 动态添加按钮功能:点击下一题的时候动态创建按钮
            [self addSubview:_viewmiddle];
            [self addSubview:_viewbottom];
        }
        return self;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    1. 懒加载数据:
      使用模型来记录变量可以避免使用字典时的键错误。 我读取时出错了,后来发现是plist中的option字段是数组类型,所以得使用数组的接口。
      我曾经声明错了,options属性该是NSArray
      通过字典封装模型,初始化函数类型是instancetype,防止继承体系下出问题。
    @interface CZQuestion : NSObject
    // 希望外部修改不会影响当前属性,就使用cpy
    @property(nonatomic, copy) NSString *answer;
    @property(nonatomic, copy) NSString *icon;
    @property(nonatomic, copy) NSString *title;
    // 强引用
    @property(nonatomic, strong) NSArray *options;
    -(instancetype) initWithDict:(NSDictionary *)dict;
    +(instancetype) questionWithDict:(NSDictionary *)dict;
    @end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    #import "CZQuestion.h"
    
    @implementation CZQuestion
    -(instancetype) initWithDict:(NSDictionary *)dict
    {
        if(self = [super init])
        {
            self.answer = dict[@"answer"];
            self.title = dict[@"title"];
            self.icon = dict[@"icon"];
            self.options = dict[@"options"];
        }
        return self;
    }
    
    // 这种命名方式是约定
    +(instancetype) questionWithDict:(NSDictionary *)dict
    {
        return [[self alloc]initWithDict:dict];
    }
    
    @end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    懒加载过程:读取文件到NSString,再转Array。由于文件本身是装着字典的,所以转的Array是个字典数组。

    // 一般模型中属性全是String:记录
    - (NSArray *)questions{
        if(_questions == nil){
            // 从安装路径读取plist
            NSString *path = [[NSBundle mainBundle] pathForResource:@"questions.plist" ofType:nil];
            // 把字符串字典,转为数组,此时数组中装着多个字典,下面要把字典转为类模型
            NSArray *arrayDicts = [NSArray arrayWithContentsOfFile:path];
            // 创建存模型的数组
            NSMutableArray *arrayModel = [NSMutableArray array];
            // 遍历
            for(NSDictionary *dict in arrayDicts){
                CZQuestion *model = [CZQuestion questionWithDict:dict];
                // 给模型数组中添加模型
                [arrayModel addObject:model];
            }
            // 最后把模型数组赋值给该懒加载变量,它是个数组,里面装着模型
            _questions = arrayModel;
        }
        return _questions;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    1. 核心功能实现:
      1> 下一题切换:
      更新index、更新题目信息、创建答案区和待选区按钮。
      2> 最后一题后弹出信息框:
      创建视图变量添加,绑定响应事件,点击后关闭当前视图,同时调用remove移除。
      3> 答案区按钮和待选区按钮的点击和消失:
      设置点击按钮后消失即可,但此前,在点击待选区按钮添加到答案区时,设置答案区按钮tag和待选区按钮tag相同。
      同时注意答案区满了后,禁止待选区视图的交互属性。
      4> 判断答案是否正确:
      读取数据模型的answer属性,和答案区对照,相同则设置蓝色字体。
      5> 积分的加法减法:
      在每一题填满且正确时,增加积分。
      点击提示后减少积分。
      6> 点击图片按钮放大图片:
      重新设置frame这一行添加到动画中执行。
      背景变化:把透明度变化添加到动画中执行。
      7> 加分
      回答完毕,正确则加分。
      注意不能通过title.text直接设置,必须通过setTitle()方法。
      8> 扣分
      回答完毕,错误则扣分

    实现功能:

    #import "CaiTuViewTop.h"
    
    @implementation CaiTuViewTop
    
    #pragma mark - 实现函数
    
    #pragma mark - btn:HelpClick
    -(void) btnHelpClick{
        int score = self.topRightbtn.titleLabel.text.intValue;
        if(score >= 100){
            // 1. 减分
            [self deductScore];
            // 2.清空
            for(UIButton *btn in _viewmiddle.subviews){
                [self answerBtnClick:btn];
            }
            // 3. 获取答案
            CZQuestion *que = _questions[_index];
            
            NSString *answerFirst = [que.answer substringToIndex:1];
            // 4. 只提示第一个
            for(UIButton *btn in self.viewbottom.subviews){
                // Expected ']'
                if([btn.currentTitle isEqual:answerFirst]){
                    [self selectBtnClick:btn];
                }
            }
        }
        else{
            NSLog(@"没积分了,不能提示");
        }
    }
    
    
    -(void) delinfoBtn:(UIButton *)btn{
        //btn.hidden = YES;
        [btn removeFromSuperview];
    }
    
    #pragma mark - btn:CreateAnswerBtn
    -(void)CreateAnswerBtn{
        // 创建之前先清除已添加的答案按钮:
        // 如果存在元素,则删除
    //    while(_viewmiddle.subviews.firstObject){
    //        [_viewmiddle.subviews.firstObject removeFromSuperview];
    //    }
        // 也可以让数组中每个元素都执行删除操作
        [_viewmiddle.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        //
        CZQuestion *que = self.questions[_index];
        int len = que.answer.length;
        CGFloat btnW = 35;
        CGFloat btnH = 35;
        CGFloat btnX = 35;
        CGFloat btnY = 2;
        CGFloat marginX = 10;   // 每个答案格X间距10,Y间距0
        // 每个间隔距离最左边
        CGFloat marginLeft = (_viewmiddle.frame.size.width - btnW * len - marginX*(len-1))/2;   // 每个答案格X间距10,Y间距0
        for(int i = 0; i < len; i++)
        {
            UIButton *answerbtn = [[UIButton alloc] initWithFrame:CGRectMake(marginLeft+i*btnX + marginX*i, btnY, btnW, btnH)];
            // 设置背景图片
            [answerbtn setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState:UIControlStateNormal];
            [answerbtn setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState:UIControlStateHighlighted];
            [answerbtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            [answerbtn addTarget:self action:@selector(answerBtnClick:) forControlEvents:UIControlEventTouchUpInside];
            [self.viewmiddle addSubview:answerbtn];
        }
    }
    
    
    #pragma mark - btn:answerbtnClick
    // 如果有内容,则隐藏,没有则不做
    -(void) answerBtnClick:(UIButton *)btn{
        if(btn.currentTitle != nil){
            // 设置中间字体为黑色:如果当前点击删除某答案区字,答案区不满,应该再设为黑色
            [self setViewmiddleFontColor:[UIColor blackColor]];
            
            NSString *tmp = btn.currentTitle;
            [btn setTitle:nil forState:UIControlStateNormal];
            self.viewbottom.userInteractionEnabled = YES;
            // 根据tag寻找待选区对应的btn:这样也行,但是不能用self直接来找,因为self会找到两个:
            // 因为设置了middleView和bottomView中的btn的tag相等,所以通过self找到的tag不唯一
            // 此外,通过self的subview不能调用这个函数,只能通过直接的视图来获得,因为self的subview是个集合,非某个单一view
             UIButton *selectbtn = (UIButton *)[_viewbottom viewWithTag:btn.tag];
            [self appearSelectBtn:selectbtn :tmp];
    
            // 正确方法2:
    //        for(UIButton *optbtn in self.viewbottom.subviews){
    //            if(optbtn.tag == btn.tag){
    //                optbtn.hidden = NO;
    //                break;
    //            }
    //        }
        }
    }
    #pragma mark - btn:CareteSelectBtn
    -(void)CreateSelectBtn{
        // 让区域可交互:因为当输入正确使得界面切换到下一题时,上次因为满了而设定的不可选择仍然生效,所以要解除
        self.viewbottom.userInteractionEnabled = YES;
        
        // 先删除已有
        [_viewbottom.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        // 增加新的
        CZQuestion *que = self.questions[_index];
        int len = que.options.count;
        //长度调用
        int colcounts = 7;
        CGFloat btnW = 35;
        CGFloat btnH = 35;
        CGFloat btnX = 35;
        CGFloat btnY = 5;
        CGFloat marginX = 10;   // 每个答案格X间距10,Y间距0
        CGFloat marginY = 10;   // 每个答案格X间距10,Y间距0
          // 每个答案格X间距10,Y间距0
        // 每个间隔距离最左边:必然大于1列,所以直接按一列的减
        CGFloat marginLeft = (self.frame.size.width - btnW * colcounts - marginX*(colcounts-1))/2;
        // NSLog(@"第%d 批", _index);
        // 查坐标:0批有错误点
        for(int i = 0; i < len; i++)
        {
            int row = i / colcounts;
            int col = i % colcounts;
            UIButton *answerbtn = [[UIButton alloc] initWithFrame:CGRectMake(marginLeft+col*btnX + marginX*col, marginY*row + btnH *row, btnW, btnH)];
            answerbtn.tag = i;
            // 设置背景图片
            [answerbtn setBackgroundImage:[UIImage imageNamed:@"btn_option"] forState:UIControlStateNormal];
            [answerbtn setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
            [answerbtn setTitle:que.options[i] forState:UIControlStateNormal];
            [answerbtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            [answerbtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside];
            [self.viewbottom addSubview:answerbtn];
        }
    }
    
    #pragma mark - selectBtnClick
    // 待选按钮的单击事件
    -(void) selectBtnClick:(UIButton *)btn{
        // 1. 隐藏
        btn.hidden = YES;
        // 2. 获取当前按钮上的文字
        NSString *text = btn.currentTitle;
        // 3. 文字显示到答案按钮上
        for(UIButton *answerbtn in self.viewmiddle.subviews){
            // 挨个放:如果当前内容空,则放
            if(answerbtn.currentTitle == nil){
                [answerbtn setTitle:text forState:UIControlStateNormal];
                // 同步tag
                answerbtn.tag = btn.tag;
                break;
            }
        }
      
        // 每次点击完后判断是否已满,已满则禁止所有控件交互,所以也不会再触发该方法,能保证效率:
        BOOL isAnswerBtnFull = YES;
        for(UIButton *btnAnswer in self.viewmiddle.subviews){
            if(btnAnswer.currentTitle == nil){
                isAnswerBtnFull = FALSE;
                break;
            }
        }
        // 满了,则设置当前底部区域全不可交互,并且检查是否正确
        if(isAnswerBtnFull)
        {
            self.viewbottom.userInteractionEnabled = NO;
            CZQuestion *model = self.questions[self.index];
            NSString *correctStr = model.answer;
            // 初始化
            NSMutableString *current = [NSMutableString string];
            for(UIButton *btnAnswer in self.viewmiddle.subviews){
                [current appendString:btnAnswer.currentTitle];
            }
            // 答案一致则设置全部为蓝色,且执行动画跳转去下一题
            if([correctStr isEqualToString:current]){
                [self setViewmiddleFontColor:[UIColor blueColor]];
                
                [self getScore];
                // 延迟后执行该方法:
                [self performSelector:@selector(btnNxtClick) withObject:nil afterDelay:0.5];
            }
            else{
                [self setViewmiddleFontColor:[UIColor redColor]];
            }
        }
    }
    
    #pragma mark -加分
    -(void) getScore{
        NSString * score = self.topRightbtn.titleLabel.text;
        int num = score.intValue;
        if(num >= 100)
            num += 100;
        NSString *newsc = [NSString stringWithFormat:@"%d", num];
        [_topRightbtn setTitle:newsc forState:UIControlStateNormal];
        //self.topRightbtn.titleLabel.text = newsc;
    }
    
    #pragma mark -减分
    -(void) deductScore{
        NSString * score = self.topRightbtn.titleLabel.text;
        int num = [score integerValue];
        if(num >= 100)
            num -= 100;
        NSString *newsc = [NSString stringWithFormat:@"%d", num];
        [_topRightbtn setTitle:newsc forState:UIControlStateNormal];
    }
    
    #pragma mark -setFontcolor
    
    -(void) setViewmiddleFontColor:(UIColor *)color{
        for(UIButton *btn in self.viewmiddle.subviews){
            [btn setTitleColor:color forState:UIControlStateNormal];
        }
    }
    
    // 待选区按钮出现:
    -(void) appearSelectBtn:(UIButton *)btn :(NSString *) str{
        // 根据字符串赋值
        //[btn setTitle:str forState:UIControlStateNormal];
        //btn.hidden = YES;
        btn.hidden = NO;
    }
    
    // 跳转下一题的上半信息全部更新
    // index++,设置label内容
    -(void)NxtQuestion{
        // 更新索引、信息框所展示的内容
        _index++;
        // 懒加载变量的访问必须通过self才能触发getter方法,直接_方式不能
        CZQuestion *model = self.questions[_index];
        // 页号
        _labtop1.text = [NSString stringWithFormat:@"%d/%ld", self.index+1, self.questions.count];
        // 图片描述
        _labtop2.text = model.title;
        // UILabel文字居中
        _labtop1.textAlignment = NSTextAlignmentCenter;
        _labtop2.textAlignment = NSTextAlignmentCenter;
        // 设置文字颜色,否则看不见
        // UILabel大小设置
        _labtop1.font = [UIFont systemFontOfSize:12];
        _labtop2.font = [UIFont systemFontOfSize:12];
        // 设置图片:把图片放小 试试
        [_imgbtn setImage:[UIImage imageNamed:model.icon] forState:UIControlStateNormal];
        
        // 最后一题禁用nxt按钮:OC的if可以省略{}
        if (_index == _questions.count-1)
            _r2btn.enabled = NO;
    }
    
    -(void) imgBtnClick{
        if(_coverView == nil){
            [self EnlargeClick];
        }
        else{
            [self shrinkbgclick];
        }
    }
                #pragma mark - 放大按钮功能
    
    // 放大按钮的响应事件
    -(void) EnlargeClick{
        // 按钮阴影背景
        UIButton *btnview = [[UIButton alloc] init];
        [btnview setBackgroundColor:[UIColor blackColor]];
        // self本身是view
        btnview.frame = self.bounds;
        btnview.alpha = 0.0;
        
        // 记录刚创建的btnview
        _coverView = btnview;
        // 存原始frame
        _iconFrame = _imgbtn.frame;
        // 通过动画增加渐变暗:
        // 把之前的图片显示到最上层:不是新设置图片
        // 设置新的frame属性:
        // 高和宽设成一样的
        CGFloat iconW = self.frame.size.width;
        CGFloat iconH = iconW;
        // 相当于贴着屏幕中间的正方形,所以 用 ( 屏幕长度 - 正方形边长) / 2
        CGFloat iconY = (self.frame.size.height-iconH)/2;
        
        // 增加图片变大的动画
        // 增加背景变暗的动画
        /// 摈弃原本的写法:_imgbtn.frame = CGRectMake(0, iconY, iconW, iconH);
        // [btnview addTarget: action: forControlEvents:];
        [UIView animateWithDuration:1 animations:^{
            // 1. 缩小
            _imgbtn.frame = CGRectMake(0, iconY, iconW, iconH);
            // 2. 背景变暗消失:不用移除的方式,而是通过设置透明度
            _coverView.alpha = 0.6;
            // 3.
        }];
        
        // 添加事件后没找到函数:在.h文件中声明,这里点击一般进不去
        [btnview addTarget:self action:@selector(shrinkbgclick) forControlEvents:UIControlEventTouchUpInside];
        
        // 把背景贴上去
        [self addSubview: btnview];
        // 把底层图片放到顶层,因为刚刚添加了btnView
        [self bringSubviewToFront: _imgbtn];
    }
    
    // 增加动画
    -(void) shrinkbgclick{
        // 无动画的视线方式:
            // 删除背景视图
    //    [_coverView removeFromSuperview];
    //        // frame恢复原来
    //    _imgbtn.frame = _iconFrame;
    //    
        // 0.7秒执行frame变化:
        [UIView animateWithDuration:0.7 animations:^{
            // 1. 缩小
            _imgbtn.frame = _iconFrame;
            // 2. 背景变暗消失:不用移除的方式,而是通过设置透明度
            _coverView.alpha = 0.0;
            // 3.
        }completion:^(BOOL finished) {
            if(finished){
                [self bringSubviewToFront: _coverView];
                // 当缩完,可通过判断_cvoerView是否有值来判断当前的缩放状态
                _coverView = nil;
            }
        }];
    }
    @end
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327

    注意事项:

    1. 图片按钮不显示图片:

    不是名字和函数错了,而是像素在当前视图中绘制不出来,我缩小后可以绘制出来了。

    1. 在VC中重写方法可以改变状态栏颜色。
      隐藏状态栏也是通过重写方法。

    2. 添加动画的对象可以是父视图,也可以是爷视图,我开发过程中犯了错,因为那时还没把当前元素添加到父视图中。

    [answerbtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.viewbottom addSubview:answerbtn];
    
    • 1
    • 2
    • 3
    1. 在设置imgbtn的backgroundImage之前设置Image,结果没有显示,在设置backgroundImage之后设置Image就显示了,为什么?。

    因为绘制顺序、内边距等设置的顺序导致,切换设置顺序即可。

    1. 懒加载变量的触发问题:

    懒加载变量需要通过getter()方法触发,通过_不会触发懒加载,通过self调用才行。

    1. 要删掉已经添加进来的按钮:
    1. while()或:
    2. self …数组中全部元素执行同一个删除代码。
    1. Array需要是强引用,@properyt中用(copy)即可,其它字符串用copy类型声明即可。

    2. 组件不显示问题:

    一定是subview,查查坐标位置问题。数值可能成了负数或者太大。我自己是因为 底部视图还没创建,结果计算出了负值,所以要注意调用某个方法给视图添加组件时,要确保该视图已经创建并初始化。

    1. 获取组件上是否有已经存在text内容的API:

    currentTitle,基于此可以获取点击的待选区按钮上的文字,也可以设置为答案区按钮上的文字。

    1. 注意关键字NO和FALSE的区别:NO确实是YES,而不是FALSE

    2. 按钮的title的清除:

    不能通过设置@“”,而要设置nil。否则按钮的title仍不为空。

    1. 关于代理:什么时候需要代理、代理的好处:
      需要监控用户的操作,要用代理。视图需要实现代理协议。
      是一种设计模式,解除耦合,做某件事找代理去做。一些API中经常看见delegate,就是需要传入代理。代理就是需要执行的某个方法。比如这里警告框要实现的代理函数,可以监听到点击的按钮序号,进而获得按钮中的内容。
      · 规范:在当前类中声明代理并实现该函数。
      · 以警告框为例的代理逻辑:
      在这里插入图片描述

    2. AppIcon和LaunchImage

    图片名称为:@2x、@3x的含义
    为什么同样一张图片要做很多张?
    1> 因为不同屏幕大小型号不一样,像素要求不同、分辨率不同,所以要求启动图和图标有多个版本。分辨率和像素点的关系:分辨率xy必须是像素点xy的倍数。程序代码中是点,运行后会自动把点转换为不同的像素去找图片。但是你的原始图片要准备好多份。分辨率高,则一个点表示多个像素。
    2> 不同地方可以都要显示同一张图片,不同地方需要的图片尺寸是不一样的。
    @2x:视网膜屏幕,在原来点坐标的大小上长乘以2
    @3x:在代码写的时候统一使用btn_left,iOS根据屏幕会自动寻找约定好的后缀名@nx。

  • 相关阅读:
    微信公众号开发:网页授权
    GEE——利用Sentinel-5p 二氧化硫SO2数据如何进行单位转化(mol/m2 、 µg/m3)
    如何写出匹配Java方法注释的正则表达式
    maven本地仓库配置
    IAB视频广告标准《数字视频和有线电视广告格式指南》之 简介、目录及视频配套广告 - 我为什么要翻译介绍美国人工智能科技公司IAB系列(2)
    Leetcode 617. Merge Two Binary Trees
    PowerBI_一分钟了解POWERBI计算组_基础运用篇(环同比分析)
    springboot心理咨询管理系统
    设计模式----工厂模式
    初见物理引擎库Cannon.js:CannonDebugRenderer的基本使用
  • 原文地址:https://blog.csdn.net/myscratch/article/details/139010959