UIKit之猜图器Demo

news2025/3/15 17:38:45

需求

实现猜图器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。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python爬虫登录到海康相机管理页面

简述 1.最近接到个任务是在管理页面更改相机的某个参数&#xff0c;下载官方的sdk貌似没有提供这个接口&#xff0c;所以只能自己写爬虫登录发请求了。 1.主要步骤 1.1 发送get请求获取到salt&#xff0c;sessionID&#xff0c;challenge等信息 http://admin:123456192.168.…

将 MOV 转换为 MP4 的 10 个最佳工具

在当今的数字时代&#xff0c;内容创作和消费正处于巅峰&#xff0c;对多功能和兼容媒体格式的需求从未如此之高。在众多可用的视频格式中&#xff0c;MOV 和 MP4 因其在各种设备和平台中的广泛使用而脱颖而出。然而&#xff0c;将 MOV 文件转换为更通用兼容的 MP4 格式的需求已…

OZON的物流有哪些,OZON物流Unitrade

随着跨境电商的快速发展&#xff0c;OZON作为俄罗斯领先的电商平台&#xff0c;其物流服务的重要性不言而喻。对于卖家而言&#xff0c;选择合适的物流合作伙伴&#xff0c;不仅关乎商品的运输效率&#xff0c;更直接关系到店铺的口碑和消费者的购物体验。本文将带您深入了解OZ…

傲软抠图一款专为抠图打造的AI智能抠图应用,智能识别人物物体抠图软件,无广vip版 v1.8.1

软件介绍 傲软抠图&#xff0c;作为一款高度专业化的智能人工智能图片处理软件&#xff0c;被设计专门用于执行精确的图像提取功能。该程序利用其先进的算法能动地识别和分辨图像中的人物或物体轮廓&#xff0c;并能够从原始图片材料中分离出带有透明背景的目标图像。除了自动…

容器化:ES和Kibana

1 缘起 最近在学习使用ES&#xff0c; 为了找一个功能强大的可视化工具&#xff0c;之前使用了ES-Head&#xff0c;可以满足学习需求。 闲暇时间又折腾了另一个工具Kibana&#xff0c; 分享如下。 Kibana优点&#xff1a; 用户友好性&#xff1a;Kibana提供直观易用的用户界面…

IC卡水表抄表是什么?什么叫IC卡水表抄表?

一、什么叫IC卡水表抄表 IC卡水表抄表是一种现代化水资源管理方法&#xff0c;主要是通过集成智能IC卡科技的水表开展计量检定和传送数据。用户在预付模式中&#xff0c;根据IC卡在线充值后再用&#xff0c;用水量会自动保存在卡上&#xff0c;大大提高了抄表效率精确性。 二…

机器学习预测-CNN手写字识别

介绍 这段代码是使用PyTorch实现的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;用于在MNIST数据集上进行图像分类。让我一步步解释&#xff1a; 导入库&#xff1a;代码导入了必要的库&#xff0c;包括PyTorch&#xff08;torch&#xff09;、神经网络模块&#xff0…

STM32H743的FDCAN使用方法(1):STM32CubeMX初始化代码生成

0 工具准备 1.STM32CubeMX1 前言 本文介绍基于STM32CubeMX&#xff0c;使用stm32h743xi的对FDCAN2进行配置的方法。 2 初始化代码生成 2.1 选择FDCAN引脚 本例选择PB5、PB6作为FDCAN2的RX、TX引脚。 2.2 选择FDCAN时钟源 本例选择PLL2Q作为FDCAN时钟源&#xff0c;频率…

Redis(1)-Jedis连接配置

问题 阿里云安装并启用Redis后&#xff0c;尝试在本地用Jedis调用&#xff0c;发现报错 public class Jedis01 {Testpublic void connect(){Jedis jedis new Jedis("101.37.31.211", 6379); // 公网ipjedis.auth("123"); // 密码String ping jedis.pin…

可转债日内自动T+0交易,行情推送+策略触发+交易接口

说明 目前这个项目已编译打包,下载即可测试,直接生成多平台可执行文件&#xff0c;详见运行方法。行情部分与策略弱相关&#xff0c;拆分解耦单独作为一个项目。行情项目请移步GitHub - freevolunteer/hangqing: A股行情订阅工具&#xff0c;支持股票/可转债level2/level2数据&…

Golang实现递归复制文件夹

代码 package zdpgo_fileimport ("errors""os""path/filepath""strings" )// CopyDir 复制文件夹 // param srcPath 源文件夹 // param desPath 目标文件夹 // return error 错误信息 func CopyDir(srcPath, desPath string) error {…

机器学习第十次课

前言 因为考了一次试,所以没讲太多新东西,唯一的问题是有的知识刚讲完就考了,导致我爆了...... 正文 主要讲的就是一个贝叶斯分类模型,这是属于生成式的分类器了 Bayesian decision theory 我的理解是贝叶斯公式则是利用条件概率和全概率公式计算后验概率,就这么简单 但是…

智慧农业可视化大屏,当个农民是不是小伙伴的梦想。

智慧农业可视化大屏是指通过数据可视化技术&#xff0c;将农业生产过程中的各种数据、指标和信息以图表、图像等形式展示在大屏上&#xff0c;以便农业从业者能够直观地了解农田、作物、气象、设备等方面的情况&#xff0c;从而进行农业生产的监控、管理和决策。以下是智慧农业…

怎么快速批量导出文本二维码?文件批量生码的方法和步骤

随着互联网的快速发展&#xff0c;二维码的应用也越来越广泛&#xff0c;现在很多二维码会用来展示物品信息&#xff0c;将编辑好的文字内容生成二维码之后&#xff0c;让其他人通过扫码的方式来获取相关内容。那么当有多条信息时&#xff0c;有什么方法能够一次批量生成二维码…

PHP质量工具系列之php_CodeSniffer

PHP_CodeSniffer 是一组两个 PHP 脚本&#xff1a;主脚本 phpcs 对 PHP、JavaScript 和 CSS 文件进行标记&#xff0c;以检测是否违反定义的编码标准&#xff1b;第二个脚本 phpcbf 自动纠正违反编码标准的行为。PHP_CodeSniffer 是一个重要的开发工具&#xff0c;可以确保你的…

04Django项目基本运行逻辑及模板资源套用

对应视频链接点击直达 Django项目用户管理及模板资源 对应视频链接点击直达1.基本运行逻辑Django的基本运行路线&#xff1a;视图views.py中的 纯操作、数据返回、页面渲染 2.模版套用1.寻找一个好的模版2.模板部署--修改适配联动 OVER&#xff0c;不会有人不会吧不会的加Q1394…

AI大模型到底能帮我干什么?

这周百度文心一言大模型正式发布了&#xff0c;不少网民拿着各种段子搞笑和玩梗。我在的其中某个微信群里&#xff0c;一位老兄针对当下的大模型&#xff0c;发出来如下的问题&#xff1a; 大家这么玩梗真没意思 我一直没弄明白这些大模型怎么帮助我工作 这个问题有一定的代表性…

关于sklearn决策树手动指定节点进行剪枝调整的实现

一、决策树剪枝 决策树的剪枝方式有两种&#xff0c;预剪枝和后剪枝&#xff0c;后剪枝在python的sklearn方法中提供了CCP代价复杂度剪枝法&#xff08;Cost Complexity Pruning&#xff09;具体实现代码如下&#xff1a; # -*- coding: utf-8 -*- from sklearn.datasets imp…

Java入门基础学习笔记44——String

为什么要学习String的处理呢&#xff1f; 开发中&#xff0c;对字符串的处理是非常常见的。 String是什么&#xff1f;可以做什么&#xff1f; java.lang.String 代表字符串。可以用来创建对象封装字符串数据&#xff0c;并对其进行处理。 1、创建对象 2、封装字符串数据 3…

超过GPT4.0?Claude3官网及国内镜像站,国内使用克劳德3的方法

近期又有一个大模型横空出世&#xff0c;这就是由Anthropic公司推出的Claude 3&#xff08;克劳德3&#xff09;&#xff0c;在多项基准测试中得分超越了GPT-4&#xff0c;那么他到底是什么情况呐&#xff1f;其实大家在国内也是可以使用上的&#xff01; 克劳德Claude3 关于…