iOS自定义控件

这里做一个类似于下面界面的小案例

1.创建一个空的布局文件 .xib

1 new File -->User Interface -->选择View
2 创建一个空的view ,会自动生成一个 .xib的文件

2.设置我们自己需要经常复用的界面

   注意:记得设置"Custom Class"中的 Class属性 与我们的代码文件 .h .m (Cocoa Touch Class文件 )相关联

3.创建我们的Cocoa文件(Cocoa Touch Class文件)

  继承 <UIKit/UIKit.h> 包种的 UIView类

.h文件

复制代码
 1 #import <UIKit/UIKit.h>
 2 @class CZApp;
 3 
 4 
 5 @interface CZAppView : UIView
 6 
 7 @property (nonatomic,strong) CZApp *model;
 8 
 9 //为自定义view封装一个类方法,这个类方法的作用就是创建一个view对象
10 +(instancetype) appView;
11 
12 @end
复制代码

.m文件

复制代码
 1 #import "CZAppView.h"
 2 #import "CZApp.h"
 3 @interface CZAppView()
 4 @property (weak, nonatomic) IBOutlet UIImageView *imgViewIcon;
 5 @property (weak, nonatomic) IBOutlet UILabel *lblName;
 6 @property (weak, nonatomic) IBOutlet UIButton *btnDownload;
 7 - (IBAction)btnDownloadClick:(UIButton *)sender;
 8 
 9 @end
10 @implementation CZAppView
11 +(instancetype) appView{
12     //1.通过xib创建每一个应用(UIView)
13     //通过动态加载xib文件创建里面的view
14     //1.1>找到应用的根目录
15     NSBundle *rootBundle =[NSBundle mainBundle];//NSLog(@"%@",[mainBundle bundlePath]);
16     //1.2>在应用程序根目录下取搜索对应的Xib(nib)文件
17     return [[rootBundle loadNibNamed:@"CZAppView" owner:nil options:nil]lastObject];
18 }
19 //重写model属性的set方法
20 -(void)setModel:(CZApp *)model{
21     //先赋值
22     _model = model;
23     
24     //解析模型数据,把模型数据赋值给UIView中的各个子控件
25     self.imgViewIcon.image = [UIImage imageNamed:model.icon];
26     self.lblName.text=model.name;
27 }
28 //下载按钮的单击事件
29 - (IBAction)btnDownloadClick:(UIButton *)sender {
30     //1.禁用当前被点击的按钮
31     sender.enabled = NO;
32     
33     //2.弹出一个消息提醒框(这个消息提醒框其实就是一个UILable)
34     UILabel *lblMsg = [[UILabel alloc]init];
35     //2.1 设置lblMsg的显示文字
36     lblMsg.text=@"正在下载....";
37     //2.2 设置lblMsg的背景色
38     lblMsg.backgroundColor = [UIColor blackColor];
39     //2.3设置lblMsg的frame
40     CGFloat viewW = self.superview.frame.size.width;
41     CGFloat viewH = self.superview.frame.size.height;
42     CGFloat msgW = 200;
43     CGFloat msgH = 30;
44     CGFloat msgX= (viewW -msgW)/2;
45     CGFloat msgY = (viewH - msgH)*0.5;
46     lblMsg.frame=CGRectMake(msgX, msgY, msgW, msgH);
47     //2.4设置label的文字颜色
48     lblMsg.textColor = [UIColor redColor];
49     //2.5设置label居中显示
50     lblMsg.textAlignment = NSTextAlignmentCenter;
51     //2.6设置文字粗体
52     lblMsg.font = [UIFont boldSystemFontOfSize:17];
53     //2.7设置label的透明度
54     lblMsg.alpha = 0.0;//一开始把透明度设置为0 ,然后通过动画的方式慢慢的改变透明度
55     //2.8 设置Label为"圆角"
56     //设置四个角的"半径"
57     lblMsg.layer.cornerRadius =10;
58     //把多余的部分裁剪掉
59     lblMsg.layer.masksToBounds =YES;
60     //2.9通过动画的方式来显示Label
61 //    [UIView animateWithDuration:2.0 animations:^{
62 //        lblMsg.alpha =0.6;
63 //    }];
64     
65     //开启一个动画,这个动画要执行1.5秒
66     [UIView animateWithDuration:1.5 animations:^{
67         //动画代码:将透明度变为0.6
68         lblMsg.alpha = 0.6;
69     } completion:^(BOOL finished) {
70         if(finished)
71         {
72             //这个代码的含义是,隔一段时间后再启动另外一个动画
73             //这个动画的执行时间是1.5秒,但是这个动画会在1.0秒之后再开始执行
74             //UIViewAnimationOptionCurveLinear表示是均速执行动画
75             [UIView animateWithDuration:1.5 delay:1.0 options:UIViewAnimationOptionCurveLinear animations:^{
76                 //这个动画的代码
77                 lblMsg.alpha = 0;
78             } completion:^(BOOL finished) {
79                 if(finished){
80                     //当Label的透明度变为0以后,再把这个Label从view中移除
81                     [lblMsg removeFromSuperview];
82                 }
83             }];
84         }
85     }];
86     //3.把lblMsg加到控制器所管理的那个view上
87     [self.superview addSubview:lblMsg];
88     
89 }
90 @end
复制代码

这样我们的自定义控件就算完成了,接下来要做得就是引用我们自己所做的界面

4.由于我们加载的图片和名称都是来源 .plist文件

   所以我们设置一个"模型" 来导入.plist文件

.h文件

复制代码
1 #import <Foundation/Foundation.h>
2 
3 @interface CZApp : NSObject
4 @property(nonatomic,copy) NSString *name;
5 @property(nonatomic,copy) NSString *icon;
6 
7 -(instancetype)initWithDict:(NSDictionary *)dict;
8 +(instancetype)appWithDict:(NSDictionary *)dict;
9 @end
复制代码

.m文件

复制代码
 1 #import "CZApp.h"
 2 
 3 @implementation CZApp
 4 -(instancetype)initWithDict:(NSDictionary *)dict{
 5     if(self=[super init]){
 6         self.name=dict[@"name"];
 7         self.icon=dict[@"icon"];
 8     }
 9     return self;
10 }
11 +(instancetype)appWithDict:(NSDictionary *)dict{
12     return [[self alloc]initWithDict:dict];
13 }
14 @end
复制代码

5.接下来我们就在控制器ViewController中开始使用我们自定义的控件

复制代码
 1 #import "ViewController.h"
 2 #import "CZApp.h"
 3 #import "CZAppView.h"
 4 
 5 @interface ViewController ()
 6 
 7 //用来保存所有应用的数据
 8 @property(nonatomic,strong)NSArray *apps;
 9 
10 @end
11 
12 @implementation ViewController
13 
14 //重写apps属性的get方法,进行懒加载数据
15 -(NSArray *)apps{
16     if(_apps == nil){
17         //加载数据
18         //1.获取app.plist文件在手机上的路径
19         NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil];
20         
21         //2.根据路径加载数据
22         NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
23         
24         //3.创建一个可变数据用来保存一个一个的模型对象
25         NSMutableArray *arrayModels = [NSMutableArray array]; //一个空的可变数组
26         
27         //4.循环字典数组,把每个字典对象转换成一个模型对象
28         for(NSDictionary *dict in arrayDict){
29             //创建一个模型
30             CZApp *model = [CZApp appWithDict:dict];
31             
32             //把模型加到arrayModels中
33             [arrayModels addObject:model];
34         }
35         _apps = arrayModels;
36     }
37     return _apps;
38 }
39 
40 - (void)viewDidLoad {
41     [super viewDidLoad];
42     
43     //假设每行的应用的个数
44     int columns = 3;
45     
46     //获取控制器所管理的view的宽度
47     CGFloat viewWidth = self.view.frame.size.width;
48     
49     //每个应用的宽和高
50     CGFloat appW = 75;
51     CGFloat appH = 90;
52     CGFloat marginTop =30;//第一行距离顶部的距离
53     CGFloat marginX = (viewWidth - columns *appW)/(columns+1);
54     CGFloat marginY = marginX;//假设每行之间的间距与marginX相等
55     
56     for(int i=0;i<self.apps.count;i++){
57         //获取当前这个应用的数据字典
58         CZApp *appModel = self.apps[i];
59         
60         //创建view
61         CZAppView *appView = [CZAppView appView];
62         
63         //2.2 设置appView 的fram属性
64         //计算每个单元格所在的列的索引
65         int colIdx = i%columns;
66         //计算每个单元格的行索引
67         int rowIdx = i/columns;
68         
69         CGFloat appX = marginX + colIdx *(appW +marginX);
70         CGFloat appY = marginTop + rowIdx *(appH + marginY);
71         appView.frame = CGRectMake(appX, appY, appW, appH);
72         
73         //3.将appView加到self.view(控制器所管理的那个view)
74         [self.view addSubview:appView];
75         
76         //设置数据
77         //把模型数据设置给"自定义view"的model属性
78         //然后重写model属性的set方法,在set方法中解析模型对象中的属性,并把属性值设置给自定义view的各个子控件
79         appView.model = appModel;
80         
81         
82     }
83     
84     
85 }
86 
87 - (void)didReceiveMemoryWarning {
88     [super didReceiveMemoryWarning];
89     // Dispose of any resources that can be recreated.
90 }
91 
92 @end
复制代码

再制作一个自动猜图的小案例

这里主要的是动态生成按钮,以及修改launchScreen的启动界面

效果图:

1.修改启动的launchscreen 以及应用小图标icon

简单来说只需要把我们制作的界面放入Images.xcassets中覆盖原来系统的LaunchImage和AppIcon就可以

主要注意的是关于尺寸的选择:

然后修改项目General中的APP Icons and Launch Image

1.先创建模型用于导入 .plist数据

.h

复制代码
 1 #import <Foundation/Foundation.h>
 2 
 3 @interface CZQuestion : NSObject
 4 
 5 @property (nonatomic, copy) NSString *answer;
 6 @property (nonatomic, copy) NSString *icon;
 7 @property (nonatomic, copy) NSString *title;
 8 @property (nonatomic, strong) NSArray *options;
 9 
10 
11 - (instancetype)initWithDict:(NSDictionary *)dict;
12 + (instancetype)questionWithDict:(NSDictionary *)dict;
13 
14 
15 @end
复制代码

.m

复制代码
 1 #import "CZQuestion.h"
 2 
 3 @implementation CZQuestion
 4 
 5 - (instancetype)initWithDict:(NSDictionary *)dict
 6 {
 7     if (self = [super init]) {
 8         self.answer = dict[@"answer"];
 9         self.title = dict[@"title"];
10         self.icon = dict[@"icon"];
11         self.options = dict[@"options"];
12     }
13     return self;
14 }
15 
16 + (instancetype)questionWithDict:(NSDictionary *)dict
17 {
18     return  [[self alloc]initWithDict:dict];
19 }
20 @end
复制代码

2.控制器ViewController.m

复制代码
  1 #import "ViewController.h"
  2 #import "CZQuestion.h"
  3 
  4 
  5 @interface ViewController () <UIAlertViewDelegate>
  6 
  7 // 所有问题的数据都在这个数组中
  8 @property (nonatomic, strong) NSArray *questions;
  9 
 10 // 控制题目索引, 类型的int类型属性, 默认没有赋值一开始就是0
 11 @property (nonatomic, assign) int index;
 12 
 13 // 记录头像按钮原始的frame
 14 @property (nonatomic, assign) CGRect iconFrame;
 15 
 16 
 17 @property (weak, nonatomic) IBOutlet UILabel *lblIndex;
 18 @property (weak, nonatomic) IBOutlet UIButton *btnScore;
 19 @property (weak, nonatomic) IBOutlet UILabel *lblTitle;
 20 @property (weak, nonatomic) IBOutlet UIButton *btnIcon;
 21 @property (weak, nonatomic) IBOutlet UIButton *btnNext;
 22 @property (weak, nonatomic) IBOutlet UIView *answerView;
 23 @property (weak, nonatomic) IBOutlet UIView *optionsView;
 24 
 25 
 26 
 27 // 用来引用那个“阴影”按钮的属性
 28 @property (weak, nonatomic) UIButton *cover;
 29 
 30 - (IBAction)btnNextClick;
 31 
 32 - (IBAction)bigImage:(id)sender;
 33 
 34 // 头像按钮的单击事件
 35 - (IBAction)btnIconClick:(id)sender;
 36 
 37 // 提示
 38 - (IBAction)btnTipClick;
 39 
 40 
 41 @end
 42 
 43 @implementation ViewController
 44 
 45 
 46 // 懒加载数据
 47 - (NSArray *)questions
 48 {
 49     if (_questions == nil) {
 50         // 加载数据
 51         NSString *path = [[NSBundle mainBundle] pathForResource:@"questions.plist" ofType:nil];
 52         NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
 53         NSMutableArray *arrayModel = [NSMutableArray array];
 54         
 55         // 遍历把字典转模型
 56         for (NSDictionary *dict in arrayDict) {
 57             CZQuestion *model = [CZQuestion questionWithDict:dict];
 58             [arrayModel addObject:model];
 59         }
 60         _questions = arrayModel;
 61     }
 62     return _questions;
 63 }
 64 
 65 
 66 // 改变状态栏的文字颜色为白色
 67 - (UIStatusBarStyle)preferredStatusBarStyle
 68 {
 69     return UIStatusBarStyleLightContent;
 70 }
 71 
 72 // 隐藏状态栏
 73 - (BOOL)prefersStatusBarHidden
 74 {
 75     return YES;
 76 }
 77 
 78 
 79 - (void)viewDidLoad {
 80     [super viewDidLoad];
 81     
 82     
 83     // 初始化显示第一题
 84     self.index = -1;
 85     [self nextQuestion];
 86     
 87 }
 88 
 89 - (void)didReceiveMemoryWarning {
 90     [super didReceiveMemoryWarning];
 91     // Dispose of any resources that can be recreated.
 92 }
 93 
 94 // 点击下一题
 95 - (IBAction)btnNextClick {
 96    
 97     // 移动到下一题
 98     [self nextQuestion];
 99 }
100 
101 // 显示大图
102 - (IBAction)bigImage:(id)sender {
103     
104     // 记录一下头像按钮的原始frame
105     self.iconFrame = self.btnIcon.frame;
106     
107     // 1.创建大小与self.view一样的按钮, 把这个按钮作为一个"阴影"
108     UIButton *btnCover = [[UIButton alloc] init];
109     // 设置按钮大小
110     btnCover.frame = self.view.bounds;
111     // 设置按钮背景色
112     btnCover.backgroundColor = [UIColor blackColor];
113     // 设置按钮透明度
114     btnCover.alpha = 0.0;
115     
116     // 把按钮加到self.view中
117     [self.view addSubview:btnCover];
118     
119     // 为阴影按钮注册一个单击事件
120     [btnCover addTarget:self action:@selector(samllImage) forControlEvents:UIControlEventTouchUpInside];
121     
122     
123     // 2. 把图片设置到阴影的上面
124     // 把self.view中的所有子控件中, 只把self.btnIcon显示到最上层
125     [self.view bringSubviewToFront:self.btnIcon];
126     
127     // 通过self.cover来引用btnCover
128     self.cover = btnCover;
129     
130     
131     // 3. 通过动画的方式把图片变大
132     CGFloat iconW = self.view.frame.size.width;
133     CGFloat iconH = iconW;
134     CGFloat iconX = 0;
135     CGFloat iconY = (self.view.frame.size.height - iconH) * 0.5;
136     
137     [UIView animateWithDuration:0.7 animations:^{
138         // 设置按钮透明度
139         btnCover.alpha = 0.6;
140 
141         // 设置图片的新的frame
142         self.btnIcon.frame = CGRectMake(iconX, iconY, iconW, iconH);
143     }];
144 }
145 
146 // 头像按钮的单击事件
147 - (IBAction)btnIconClick:(id)sender {
148     if (self.cover == nil) {
149         // 显示大图
150         [self bigImage:nil];
151     } else {
152         [self samllImage];
153     }
154 }
155 
156 // 点击"提示"按钮
157 - (IBAction)btnTipClick {
158     // 1. 分数-1000
159     [self addScore:-1000];
160     
161     
162     // 2. 把所有的答案按钮"清空"(其实这里的"清空"最好是调用每个答案按钮的单击事件)
163     for (UIButton *btnAnswer in self.answerView.subviews) {
164         // 让每个答案按钮点击一下
165         [self btnAnswerClick:btnAnswer];
166     }
167     
168     // 3. 根据当前的索引, 从数据数组中(self.questions)中找到对应的数据模型
169     // 从数据模型中获取正确答案的第一个字符, 把待选按钮中和这个字符相等的那个按钮点击一下
170     CZQuestion *model = self.questions[self.index];
171     //截取正确答案中的第一个字符"字符串"
172     NSString *firstChar = [model.answer substringToIndex:1];
173     
174     // 根据firstChar在option按钮中找到对应的option 按钮, 让这个按钮点击一下
175     for (UIButton *btnOpt in self.optionsView.subviews) {
176         if ([btnOpt.currentTitle isEqualToString:firstChar]) {
177             [self optionButtonClick:btnOpt]; // 设置某个option 按钮点击一下
178             break;
179         }
180     }
181 }
182 
183 
184 // "阴影"的单击事件
185 - (void)samllImage
186 {
187     [UIView animateWithDuration:0.7 animations:^{
188         // 1. 设置btnIcon(头像)按钮的frame还原
189         self.btnIcon.frame = self.iconFrame;
190         // 2. 让"阴影"按钮的透明度变成0
191         self.cover.alpha = 0.0;
192     } completion:^(BOOL finished) {
193         if (finished) {
194             // 移出"阴影"按钮
195             [self.cover removeFromSuperview];
196             // 当头像图片变成小图以后, 再把self.cover设置成nil
197             self.cover = nil;
198         }
199     }];
200 }
201 
202 
203 // 实现UIAlertView的代理方法
204 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
205 {
206    // NSLog(@"%ld", buttonIndex);
207     if (buttonIndex == 0) {
208         // 让程序在回到第0个问题
209         self.index = -1;
210         [self nextQuestion];
211     }
212 }
213 
214 
215 
216 // 下一题
217 - (void)nextQuestion
218 {
219     // 1. 让索引++
220     self.index++;
221     
222     // 判断当前索引是否越界, 入股索引越界, 则提示用户
223     if (self.index == self.questions.count) {
224         //NSLog(@"答题完毕!!!!");
225         
226         // 弹出一个对话框
227         UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"操作提示" message:@"恭喜通关!" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
228         
229         // 显示对话框
230         [alertView show];
231         return;
232     }
233     
234     
235     // 2. 根据索引获取当前的模型数据
236     CZQuestion *model = self.questions[self.index];
237     
238     
239     
240     // 3. 根据模型设置数据
241     [self settingData:model];
242     
243     
244     // 4. 动态创建"答案按钮"
245     [self makeAnswerButtons:model];
246     
247     
248     // 5. 动态创建"待选按钮"
249     [self makeOptionsButton:model];
250     
251     
252 }
253 
254 
255 // 创建待选按钮
256 - (void)makeOptionsButton:(CZQuestion *)model
257 {
258     // 0. 设置option view 可以与用户交互
259     self.optionsView.userInteractionEnabled = YES;
260     
261     
262     // 1. 清除待选按钮的view中的所有子控件
263     [self.optionsView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
264     
265     // 2. 获取当前题目的待选文字的数组
266     NSArray *words = model.options;
267     
268     // 3. 根据待选文字循环来创建按钮
269     
270     // 指定每个待选按钮的大小
271     CGFloat optionW = 35;
272     CGFloat optionH = 35;
273     // 指定每个按钮之间的间距
274     CGFloat margin = 10;
275     // 指定每行有多少个按钮
276     int columns = 7;
277     // 计算出每行第一个按钮距离左边的距离
278     CGFloat marginLeft = (self.optionsView.frame.size.width - columns * optionW - (columns - 1) * margin) / 2;
279     
280     
281     for (int i = 0; i < words.count; i++) {
282         // 创建一个按钮
283         UIButton *btnOpt = [[UIButton alloc] init];
284         
285         // 给每个option 按钮一个唯一的tag值
286         btnOpt.tag = i;
287         
288         // 设置按钮背景
289         [btnOpt setBackgroundImage:[UIImage imageNamed:@"btn_option"] forState:UIControlStateNormal];
290         [btnOpt setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
291         
292         // 设置按钮文字
293         [btnOpt setTitle:words[i] forState:UIControlStateNormal];
294         
295         // 设置文字颜色为黑色
296         [btnOpt setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
297         
298         
299         // 计算当前按钮的列的索引和行的索引
300         int colIdx = i % columns;
301         int rowIdx = i / columns;
302         
303         CGFloat optionX = marginLeft + colIdx * (optionW + margin);
304         CGFloat optionY = 0 + rowIdx * (optionH + margin);
305         
306         // 设置按钮frame
307         btnOpt.frame = CGRectMake(optionX, optionY, optionW, optionH);
308         
309         // 把按钮添加到optionsView中
310         [self.optionsView addSubview:btnOpt];
311         
312         // 为待选按钮注册单击事件
313         [btnOpt addTarget:self action:@selector(optionButtonClick:) forControlEvents:UIControlEventTouchUpInside];
314     }
315     
316     
317 }
318 
319 // 待选按钮的单击事件
320 - (void)optionButtonClick:(UIButton *)sender
321 {
322     // 1. 隐藏当前被点击的按钮
323     sender.hidden = YES;
324     
325     // 2. 把当前被点击的按钮的文字显示到第一个为空的"答案按钮"上
326     //NSString *text = [sender titleForState:UIControlStateNormal]; // 获取按钮指定状态下的文字
327     NSString *text = sender.currentTitle; // 获取按钮当前状态下的文字
328     
329     
330     // 2.1 把文字显示到答案按钮上
331     
332     // 遍历每一个答案按钮
333     for (UIButton *answerBtn in self.answerView.subviews) {
334         // 判断每个"答案按钮"上的文字是否为nil
335         if (answerBtn.currentTitle == nil) {
336             
337             // 把当前点击的待选按钮的文字设置给对应的答案按钮
338             [answerBtn setTitle:text forState:UIControlStateNormal];
339             // 把当前点击的待选按钮的tag值也设置给对应的答案按钮
340             answerBtn.tag = sender.tag;
341             
342             break;
343         }
344     }
345     
346     
347     
348     
349     
350     
351     // 3. 判断答案按钮是否已经填满了
352     // 一开始假设答案按钮是填满的
353     BOOL isFull = YES;
354     // 声明一个用来保存用户输入的答案的字符串
355     NSMutableString *userInput = [NSMutableString string];
356     
357     for (UIButton *btnAnswer in self.answerView.subviews) {
358         if (btnAnswer.currentTitle == nil) {
359             isFull = NO;
360             break;
361         } else {
362             // 如果当前答案按钮上面有文字, 那么就把这个文字拼接起来
363             [userInput appendString:btnAnswer.currentTitle];
364         }
365     }
366     
367     // 如果已经填满, 则禁止option view 控件与用户的交互
368     if (isFull) {
369         // 禁止"待选按钮"被点击
370         self.optionsView.userInteractionEnabled = NO;
371         
372         // 获取当前题目的正确答案
373         CZQuestion *model = self.questions[self.index];
374         
375         
376         // 4. 如果答案按钮被填满了, 那么就判断用户点击输入的答案是否与标准答案一致,
377         if ([model.answer isEqualToString:userInput]) {
378              // 如果一致, 则设置答案按钮的文字颜色为蓝色, 同时在0.5秒之后跳转下一题
379             // 0. 如果正确+100分
380             [self addScore:100];
381             //1. 设置所有的答案按钮的文字颜色为 蓝色
382             [self setAnswerButtonsTitleColor:[UIColor blueColor]];
383             
384             // 延迟0.5秒后, 跳转到下一题
385             [self performSelector:@selector(nextQuestion) withObject:nil afterDelay:0.5];
386             
387         } else {
388             // 如果答案不一致(答案错误), 设置答案按钮的文字颜色为红色
389             // 设置所有的答案按钮的文字颜色为 红色
390             [self setAnswerButtonsTitleColor:[UIColor redColor]];
391         }
392     }
393 }
394 
395 // 根据指定的分数, 来对界面上的按钮进行加分和减分
396 - (void)addScore:(int)score
397 {
398     // 1. 获取按钮上现在分值
399     NSString *str = self.btnScore.currentTitle;
400     
401     // 2. 把这个分值转换成数字类型
402     int currentScore = str.intValue;
403     
404     // 3. 对这个分数进行操作
405     currentScore = currentScore + score;
406     
407     // 4. 把新的分数设置给按钮
408     [self.btnScore setTitle:[NSString stringWithFormat:@"%d", currentScore] forState:UIControlStateNormal];
409 }
410 
411 
412 // 统一设置答案按钮的文字颜色
413 - (void)setAnswerButtonsTitleColor:(UIColor *)color
414 {
415     // 遍历每一个答案按钮, 设置文字颜色
416     for (UIButton *btnAnswer in self.answerView.subviews) {
417         [btnAnswer setTitleColor:color forState:UIControlStateNormal];
418     }
419 }
420 
421 
422 
423 // 加载数据, 把模型数据设置到界面的控件上
424 - (void)settingData:(CZQuestion *)model
425 {
426     // 3. 把模型数据设置到界面对应的控件上
427     self.lblIndex.text = [NSString stringWithFormat:@"%d / %ld", (self.index + 1), self.questions.count];
428     self.lblTitle.text = model.title;
429     [self.btnIcon setImage:[UIImage imageNamed:model.icon] forState:UIControlStateNormal];
430     
431     // 4. 设置到达最后一题以后, 禁用"下一题按"钮
432     self.btnNext.enabled = (self.index != self.questions.count - 1);
433 }
434 
435 
436 // 创建答案按钮
437 - (void)makeAnswerButtons:(CZQuestion *)model
438 {
439     // 这句话的意思:让subviews这个数组中的每个对象, 分别调用一次removeFromSuperview方法, 内部执行了循环,无需我们自己来些循环
440     [self.answerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
441     
442     // 5.1 获取当前答案的文字的个数
443     NSInteger len = model.answer.length;
444     // 设置按钮的frame
445     CGFloat margin = 10; // 假设每个按钮之间的间距都是10
446     CGFloat answerW = 35;
447     CGFloat answerH = 35;
448     CGFloat answerY = 0;
449     CGFloat marginLeft = (self.answerView.frame.size.width - (len * answerW) - (len - 1) * margin) / 2;
450     
451     // 5.2 循环创建答案按钮, 有几个文字就创建几个按钮
452     for (int i = 0; i < len; i++) {
453         // 创建按钮
454         UIButton *btnAnswer = [[UIButton alloc] init];
455         // 设置按钮的背景图
456         [btnAnswer setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState:UIControlStateNormal];
457         [btnAnswer setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState:UIControlStateHighlighted];
458         
459         // 计算按钮的x值
460         CGFloat answerX = marginLeft + i * (answerW + margin);
461         btnAnswer.frame = CGRectMake(answerX, answerY, answerW, answerH);
462         
463         // 设置答案按钮的文字颜色
464         [btnAnswer setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
465         
466         // 把按钮加到answerView中
467         [self.answerView addSubview:btnAnswer];
468         
469         
470         // 为答案按钮注册单击事件
471         [btnAnswer addTarget:self action:@selector(btnAnswerClick:) forControlEvents:UIControlEventTouchUpInside];
472         
473     }
474 }
475 
476 // 参数sender, 就表示当前点击的答案按钮
477 - (void)btnAnswerClick:(UIButton *)sender
478 {
479     // 0. 启用option view与用户的交互
480     self.optionsView.userInteractionEnabled = YES;
481     
482     // 1. 设置所有的答案按钮的文字颜色为黑色
483     [self setAnswerButtonsTitleColor:[UIColor blackColor]];
484     
485     
486     // 2. 在"待选按钮"中找到与当前被点击的答案按钮文字相同待选按钮,设置该按钮显示出来。
487     for (UIButton *optBtn in self.optionsView.subviews) {
488         // 比较判断待选按钮的文字是否与当前被点击的答案按钮的文字一致
489 //        if ([sender.currentTitle isEqualToString:optBtn.currentTitle]) {
490 //            optBtn.hidden = NO;
491 //            break;
492 //        }
493         
494         if (sender.tag == optBtn.tag) {
495             optBtn.hidden = NO;
496             break;
497         }
498     }
499     
500     // 1. 清空当前被点击的答案按钮的文字
501    [sender setTitle:nil forState:UIControlStateNormal];
502     
503     
504 }
505 @end
原文地址:https://www.cnblogs.com/harderAndLuckier/p/5365339.html