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. 界面构成:
    自定义视图类:
    界面上半部分组件多直接交互,故写直接创建为成员变量,而中部和下部,按钮单一,一般是多个按钮产生有响应动作:如删除、创建等,故写入仅需两个视图成员: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. 布局实现以及功能初始化:
    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. 懒加载数据:
    使用模型来记录变量可以避免使用字典时的键错误。 我读取时出错了,后来发现是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
#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

懒加载过程:读取文件到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. 核心功能实现:
    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. 图片按钮不显示图片:

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

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

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

[answerbtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside];

[self.viewbottom addSubview:answerbtn];
  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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/658806.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

记录一个截图导出pdf的方法

以下是导出的方法&#xff1a; // 通过截图、分页、处理文字截断后从dom生成pdf并导出 import { nextTick } from vue import { BxmMessage } from bxm-ui3 import html2Canvas from html2canvas import JsPDF from jspdf/*** * param {*} dom 导出的模块* param {*} fileNam…

Hive复杂数据类型之 Struct结构体

想写这篇文章蛮久了&#xff0c;但这个数据类型&#xff0c;确实很少用&#xff0c;翻遍了代码库的所有代码&#xff0c;也没有找到。 但&#xff0c;之前分享过的 Hive复杂数据类型之 array 数组&#xff0c; Hive复杂数据类型之array数组_hive 建表设置array类型-CSDN博客 …

Linux命令 jps(Java Process Status)解释

文章目录 1、第一种解释2、第二种解释3、第三种解释 1、第一种解释 jps 命令本身并不是一个标准的 Unix/Linux 命令&#xff0c;但您可能是想提到 jps 的一个变种或误写了 jps 为 jps&#xff0c;而实际上可能是想提及 jps&#xff08;Java Virtual Machine Process Status To…

linux下常用的终端命令

文章目录 1. MV移动文件、重命名文件1.1 移动文件&#xff1a;mv [选项] 源文件或目录 目标文件或目录1.2 文件重命名 2. 查找&#xff1a;文件&#xff0c;内容&#xff0c;统计文件2.1 find查找文件2.2 Linux查找文件内容 3. 查看当前用户4. linux修改文件所属用户和组5. 复制…

红酒配餐中的酒杯选择与使用技巧

在红酒配餐中&#xff0c;酒杯的选择与使用技巧是影响品鉴体验的重要因素。合适的酒杯不仅能展现出红酒的优雅和风味&#xff0c;还能提升用餐的仪式感和愉悦感。云仓酒庄雷盛红酒以其卓着的品质和丰富的口感&#xff0c;成为了红酒爱好者们的首要选择品牌。下面将介绍在红酒配…

菜鸟的JavaSE学习之旅7

这是一个目录 数组工具类Arrays数学工具类Math继承重写&#xff08;Override&#xff09;覆盖、覆写注意 构造方法super关键字用法this关键字super和this 抽象抽象方法和抽象类格式抽象方法和抽象类使用抽象方法和抽象类注意事项 数组工具类Arrays java.util.Arrays是一个与数…

飞书API(10):通过阿里云MaxCompute数仓入库 - 转为阿里云 DataFrame 再入库

一、引入 上一小节介绍了怎么入库到阿里云的 MaxCompute 数仓&#xff0c;其中涉及到 2 种入库方式&#xff0c;一种是转为阿里云的 DataFrame&#xff0c;然后类似 pandas 的 DataFrame 直接写入 MySQL 的方法&#xff0c;将数据写入表中&#xff1b;另外一种是转为列表&…

linux开发之设备树四、设备树中断节点

中断节点 这里是由原厂的BSP工程师写的一部分 在CPU的外部有一个GIC控制器&#xff0c;外设会连接在GIC控制器上 设备树是对硬件进行描述的&#xff0c;所以设备树会对CPU进行描述&#xff0c;也要对GIC 控制器进行描述&#xff0c;这部分的代码由原厂的BSP工程师进行编写&…

微软Build开发者大会速览,OpenAI CEO站台剧透新模型

5月22日凌晨&#xff0c;微软Build 2024开发者大会在美国西雅图召开。微软CEO萨蒂亚纳德拉在会上发表主题演讲&#xff0c;宣布了超过50项产品更新&#xff0c;涵盖AI基础设施、模型产品以及生产力工具等多个领域。纳德拉强调&#xff0c;微软一直致力于让人工智能理解人类并帮…

Python的解析网页

课前案例 通过requests模块爬取指定网站中的图片并保存到本地目录中。 上述案例采用的是同步方式下载图片&#xff0c;效率太低。异步方式如下&#xff08;线程&#xff09;&#xff1a; # target为目标函数&#xff1b;args中传入的是download函数的参数url threading.Threa…

TypeScript系列之-- 数组和元组类型

数组的定义&#xff1a; 第一种&#xff0c;可以在元素类型后面接上[] let list: number[] [1, 2, 3]; 第二种方式是使用数组泛型&#xff0c;Array<元素类型> let list: Array<number> [1, 2, 3]; 如果数组想每一项放入不同数据怎么办&#xff1f;用元组类型…

C# yolov8 TensorRT +ByteTrack Demo

C# yolov8 TensorRT ByteTrack Demo 目录 效果 说明 项目 代码 Form2.cs YoloV8.cs ByteTracker.cs 下载 参考 效果 说明 环境 NVIDIA GeForce RTX 4060 Laptop GPU cuda12.1cudnn 8.8.1TensorRT-8.6.1.6 版本和我不一致的需要重新编译TensorRtExtern.dll&…

深入分析 Android Activity (十)

文章目录 深入分析 Android Activity (十)1. Activity 的资源管理1.1 使用资源 ID 访问资源1.2 Drawable 资源1.3 使用 TypedArray 管理资源1.4 使用资源配置 2. Activity 的数据存储2.1 SharedPreferences2.2 文件存储2.3 SQLite 数据库2.4 ContentProvider 3. Activity 的性能…

倪老师是教我们如何去读书

之前一篇我们了解了倪老师&#xff0c;告诉我们如何去学习一些东西&#xff0c;今天这一篇&#xff0c;我把倪老师视频里面总结的几点&#xff0c;倪老师教我们如何去读书&#xff0c;我把一些小细节做了一个简单的整理&#xff0c;我们共同地去看&#xff0c;倪老师是教我们如…

JVS物联网、逻辑引擎、智能BI(重构优化)5.21功能新增说明

项目介绍 JVS是企业级数字化服务构建的基础脚手架&#xff0c;主要解决企业信息化项目交付难、实施效率低、开发成本高的问题&#xff0c;采用微服务配置化的方式&#xff0c;提供了 低代码数据分析物联网的核心能力产品&#xff0c;并构建了协同办公、企业常用的管理工具等&am…

SqliSniper:针对HTTP Header的基于时间SQL盲注模糊测试工具

关于SqliSniper SqliSniper是一款基于Python开发的强大工具&#xff0c;该工具旨在检测HTTP请求Header中潜在的基于时间的SQL盲注问题。 该工具支持通过多线程形式快速扫描和识别目标应用程序中的潜在漏洞&#xff0c;可以大幅增强安全评估过程&#xff0c;同时确保了速度和效…

使用 Django 连接 MySQL 数据库

文章目录 步骤一&#xff1a;安装必要的库和驱动步骤二&#xff1a;配置数据库连接步骤三&#xff1a;执行数据库迁移步骤四&#xff1a;开始使用 MySQL 数据库创建一个模型迁移模型到数据库使用模型进行数据操作创建新记录&#xff1a;查询记录&#xff1a;更新记录&#xff1…

Innodb Buffer Pool缓存机制(一)一条sql的执行过程

思维导图 石墨文档&#xff1a;https://shimo.im/mindmaps/NJkbnZV0ePINXzkR 一、SQL的执行 执行过程&#xff1a; 加载缓存数据&#xff0c;加载id为1的记录所在的整页数据&#xff08;相当于索引树的一个结点&#xff0c;16KB&#xff09;&#xff1b;写入更新数据的旧值到…

重生奇迹mu卡智力的方法

1、准备3个号A打手,B智力MM,C随意。 2、使用C匹配组队,但是不能选择自动进入队伍。 3、用A申请C的队伍,但是C不做通过处理。 4、用A组B,用快捷键D的方式。 5、所谓的卡智力就是智力MM可以给打手加属性加血&#xff0c;但是并不在一个队伍里享受经验&#xff0c;适用于MM不是…

如何提升网站运营效率

企业网站作为品牌展示、客户获取和商业目标实现的关键平台&#xff0c;其运营效率的提升对增强用户体验、搜索引擎排名和转化率至关重要。以下是一些有效技术和策略的介绍&#xff0c;旨在助力您提高网站运营的效率。 一、网站速度的优化 1.1 利用内容分发网络&#xff08;CD…