一、之前我们实现了“下一题”功能,和“大图”功能,接下里,我们把前面的总结一下: 之前实现的“下一题”功能,和“大图”功能的步骤: 1.新建项目 2.拷贝素材 3.懒加载模型数据. 4.通过storyboard设计"超级猜图"的上半部分界面。 1> 一个UIImageView做背景 2> 分析界面上的控件应该使用什么控件 **注意按钮点击没有高亮效果取消: highlighted adjust image属性 5.实现状态栏白色文字效果。 6.实现点击"下一题"功能。 * 使用一个index属性来记录当前显示的题目的索引。 * 点击"下一题"的时候,从数组中获取对应的题目,并显示到对应的界面控件上。 * 解决最后一题之后再次点击"下一题"索引越界问题。sender. enabled = (self.index != self.questions.count - 1); ** 注意:设置按钮图片的时候,通过调用setImage: forState: UIControlStateNormal]方法来设置。 7.在viewDidLoad中,初始化第一个问题 (显示第一个问题到界面上) 。 * 设置self. index = -1 * 手动调用"下一题"按钮的点击事件 8.实现"查看大图"功能。 ** 点击右侧"大图"按钮,显示大图 * 实现思路(步骤) : 1> 添加一个“阴影”按钮,因为该“阴影”要实现点击,所以用“按钮” 2> 然后再把“头像按钮"显示在”阴影“上面。 3> 通过动画的方式改变"头像按钮"的frame(位置和尺寸),变成大图效果。 ** 注意:如果图片没有变大,检查是否没有取消"自动布局(Auto Layout)" ** 点击"遮罩阴影”,回到小图 1> 通过动画慢慢将"遮罩阴影”的透明度变为0 2> 通过动画慢慢将"头像图片的frame修改为原来的位置 3> 在动画执行完毕后,移除"遮罩阴影” ** 点击图片本身显示大图,再次点击图片本身显示小图 9.动态生成"答案按钮"。 *思路: 0> 在点击"下一题"按钮中实现该功能 1> 创建一个UIView来存放所有的"答案按钮" 2> 根据每个问题的答案的文字个数来创建按钮 3> 每次创建按钮之前,先把旧的按钮都删除 4> 指定每个"答案按钮”的尺寸和中间的margin,然后计算第一个按钮的x值(marginLeft) 。 5> 在循环中,计算每个按钮的x值(y值都是0)。 二、把这个“下一题”功能,和“大图”功能,实现以后,接下来,我们就要开始实现动态生成“答案按钮”了,接下来,就实现动态生成“答案按钮”, 1.好,接下来,我们就给大家做这个“答案按钮”,生成“答案按钮”, 那么,我们还是先思考一下,这个动态生成“答案按钮”,该怎么实现,好,首先,实现的思路就是这样的,来,我们先看这个示例程序吧,我们这样,嗯,我们把这些,这些就是放答案的按钮吧, 中间这三个,就是“答案按钮”吧, 下面这些,是放这个待选项的按钮,下面是放待选项的按钮,我们把这个红色的这个把它作为一个View,这是一个View, 首先,创建一个View,放在这儿,下面给它创建一个View,放在这儿,然后呢,创建若干个按钮,动态创建若干个按钮,放到这个View里面,注意,这是创建几个按钮,取决于什么,取决于当前答案的文字的个数吧,所以说,我们这里要根据当前这个题目的答案的文字个数,是什么,来动态创建这些按钮,然后设置按钮的背景图是一个什么颜色,白色吧,然后默认状态下什么颜色,点击状态下什么颜色,然后把它坐标排好,这样的话,我们这儿是不是实现了, 实现这个以后,然后我们再根据当前这个题目的待选文字的个数,是不是实现下面这几个按钮,是不是这样的,好,我问大家,现在生成这个答案按钮,这个代码应该写在哪里, 生成这几个答案按钮,这几个按钮,这个代码应该写在哪里,生成这几个答案按钮的代码,应该写在哪里,肯定是控制器里面,这个我知道,在控制器里面,在哪里,是不是点击“下一题”的时候啊,当你点击“下一题”的时候,要把“下一题”的数据填上,同时要根据当前这个题目的答案的个数,文字个数,是不是要显示这几个“答案按钮”啊,同时,再根据当前这个题目的待选答案的文字个数,动态生成待选答案的按钮, 所以说,当你点击“下一题”的时候,是不是要做这一系列操作,明白了吗,好,所以我们先把这两个View拽过来, 然后,再设置它的坐标,宽和高,宽给个多少,375吧,是不是和屏幕一样宽,距离左边的距离,左边是x,x给个0吧,y就是255吧,高给个35吧, 然后,它的背景色,为了我们等会能看到,因为按钮也是白色,背景色是白色,看不出来了,把这个背景色改一下,大家喜欢什么颜色,黄色,好,Background属性给个黄色, 然后接下来,选中左边控件列表里的“View”,command + C,command + V,复制一个,Y坐标,来个317吧,它距离上边的距离,来个317吧,然后呢,它的高度呢,注意它的Y值是多少,317吧,整个屏幕的高度是667,拿667-317等于多少,350吧,这样它的高度,就是多少,350吧,这样子,它的高度,是不是它刚好是填满整个屏幕的下边啊, 然后呢,我们给它的背景色,给它来一个,蓝色吧,Background属性,给它来个蓝色, 这样的话,我们是不是这两个View都有了,这两个View就都有了, 2.好,这两个View好了以后,那么接下来,当点击“下一题”的时候,需要向这两个View里面动态创建子控件, 既然要向这两个View里面,动态创建子控件,所以说,我们是不是要通过一个什么,要通过两个属性,是不是来引用这两个View, 这样的话,等会儿是不是就可以向这两个View里面创建子控件了,通过两个属性来引用,所以说,既然要通过属性来引用,所以说,就想到了什么,拖线吧, 先在控件列表中,修改一下这两个View的名称,放置“答案按钮”的这个View,给它来个什么名称呢,answerView吧,下面这个是“待选项”,名字给它来个optionsView, 然后,拖线,按住control键,把这个answerView拖到ViewController.m文件的延展里,设置5个参数: Connection:Outlet, Object:View Controller, Name:answerView, Type:UIView, Storage:Weak, 点击Connect按钮, 自动生成了下面这个属性: @property(nonatomic,weak) IBOutlet UIView *answerView; 然后,是这个optionsView,拖线,设置5个参数: Connection:Outlet, Object:View Controller, Name:optionisView, Type:UIView, Storage:Weak, 点击Connect按钮, 自动生成了下面这个属性: 这个是不是用来放答案的View啊,用来放待选答案的View: @property(nonatomic,weak)IBOutlet UIView *optionsView; 当这两个View没有问题以后,接下来,我们就要在单击“下一题”,这个“下一题”,这个事件当中,我们是不是就要,根据当前这个题目的答案的文字个数,动态创建按钮了,好,找到“下一题”, 如果ViewController.m文件里面的方法太多,找不到的话,可以从方法的下拉列表里找: 好,是不是这个- nextQuestion,啊 这是我们点击“下一题”吧, //下一题 - (void)nextQuestion{ //1.让索引++ self.index++; //2.根据索引获取当前的模型数据 TestQuestion *model = self.questions[self.index]; //3.把模型数据设置到界面对应的控件上 self.lblIndex.text = [NSString stringWithFormat:@“%d/%ld”,(self.index+1),self.questions.count]; self.lblTitle.text = model.title; [self.btnIcon setImage:[UIImage imageNamed:model.icon] forState:UIControlStateNormal]; //4.设置到达最后一题以后,禁用“下一题”按钮 self.btnNext.enabled = (self.index != self.questions.count - 1); } 这是我们点击“下一题”,在这里面, 1)第一步,让索引++, 2)第二步,获取模型数据, 3)第三步,根据模型数据,填充我们的控件的数据, 4)第四步,设置这个按钮是否禁用, 5)第五步,动态创建“答案按钮” 在这个里面,我们要做这么几步事情, 1)第一步,先获取当前这个题目的答案这个文字吧,然后呢,再根据这个答案文字的个数,是不是循环,创建按钮,怎么写, //5.动态创建“答案按钮” //5.1 获取当前答案的文字的个数 //所以就是,当前这个模型,这个模型,是不是当前这个问题,这个模型啊,当前这个模型里面,有一个叫做什么的东西,answer吧,这个东西,这个东西就是当前这个问题的答案,这个答案的具体内容吧,然后呢,有几个答案,就是里面有几个文字,就是循环几次吧,就是循环几次啊,就是循环几次,所以说,我们就这么做,我们能把这个答案的文字内容直接显示上来吗,答案不能显示吧,是不是不要那个答案的文字内容啊,只要它的文字个数,我们就可以,这里可以拿一个NSInteger, NSInteger len = model.answer.length; //这个model.answer.length,是不是获取答案里面的文字的个数啊, //5.2 循环创建答案按钮,有几个文字就创建几个按钮 //怎么写,这里就可以使用for循环了吧, for(int i = 0 ; i < len ; i++){ //然后呢,每次是不是有一个答案文字,就创建一个按钮, //1.创建按钮 UIButton *btnAnswer = [[UIButton alloc] init]; //2.把按钮加到answerView里面去, [self.answerView addSubview:btnAnswer]; //这个answerView,是不是指的就是我们这里这个黄色的View, //运行一下,但是这里为什么什么都没看见呢,因为我们是不是压根儿就没有设置按钮的大小、frame、背景色,是不是什么都没有设置啊, //3.先就设置按钮的背景色图,然后再设置按钮的什么,再设置按钮的frame,把这两个设置好以后,是不是就能看到这个按钮了,好,我们看一下这个示例程序,这个示例程序里面,这个“答案按钮”的默认背景色是不是白色啊,当按下的时候,背景色变成灰色了,所以它有两张背景图,默认是一张背景图,按下的时候,是一张背景图,ok,这个按钮有两张背景图, //3.1 设置按钮的背景图 //3.2 设置按钮的frame //然后,它的大小呢,它的这个大小也是35,高和宽都是35,我们看一下,这个图片素材里面,就看图片素材里面,Images.csassets文件夹里面,有一个Btn文件夹,按钮,哪个是按钮的背景图呢注意看看,这个,这就是默认状态下,按钮的背景图,是不是白色背景啊, //btn_answer,这个是默认状态下的背景图, //btn_answer_highlighted,当你点击的时候,这个是高亮状态下的背景图,是不是灰色的背景啊,我们这里来设置背景图, //3.1 设置按钮的背景图 //怎么设置背景图,setBackgroundImage, [btnAnswer setBackgroundImage:[UIImage imageNamed:@“btn_answer”] forState:UIControlStateNormal]; //好,高亮状态下,怎么设置, [btnAnswer setBackgroundImage:[UIImage imageNamed:@“btn_answer_highlighted” forSate:UIControlStateHighlighted]; //好,这是设置背景图,背景图设置好以后,接下来,我们就要设置它的frame吧,所以首先,固定好它的大小, //3.2 设置按钮的frame CGFloat answerW = 35; CGFloat answerH = 35; CGFloat answerY = 我们这个Y值,是多少,来,看一下, //我们将来这个“答案按钮”,是不是一个一个加到这个View里面了,所以这个按钮,是不是紧贴着上边缘,所以Y值,是多少,0吧, CGFloat answerY = 0; //X轴,是不是要动态算一下 ,X值要动态算一下,好,这个X值,怎么算 //来,看一下我们这个X值,怎么算,这个和我们之前的九宫格,是不是稍微有一点点不一样啊,注意看,我们现在最外层这个View,这个黄色的框框,是不是就是我们最外层这个View啊, //如果现在我们有3个按钮,它们左边和右边的距离,这两个黄色的箭头,是不是距离是相等的,如果现在有四个,左边和右边的距离,是不是也是相等的,可能中间会宽一些,但是它这四个,距离左边和右边的距离,是不是还是相等的 //所以说,首先,我们第一,给定一个按钮的高和宽,第二,再给定一个按钮中间的间距, //然后我们动态去计算它两边的距离,是不是动态计算两边的距离,那么这个时候,我们来, //这个动态计算两边的距离,这该怎么算呢, //我们现在先用总的宽度,减去中间有几个按钮,就减去几个按钮的宽度,再减去中间按钮个数 - 1 的按钮中间的间距,比如说,现在有3个按钮,就是减掉2个间距,减完之后,是不是就把中间这一坨,都减掉了,然后再除以2,是不是就是两边这个距离了, //所以说,我们首先就是要用这个View的宽度,减去有几个按钮,就是几个按钮的宽度,再减去有几个按钮,就是按钮的个数减1,然后呢,是不是再乘以这间距的个数, //这样除以2,最终计算出来的,就是两边这个间距了吧, //好,那么这两边的间距,我们就先给它来一个, //假设每个按钮之间的间距都是10 //3.2 设置按钮的frame CGFloat margin = 10;//假设每个按钮之间的间距都是10 CGFloat answerW = 35; CGFloat answerH = 35; CGFloat answerY = 0; //然后呢,我们当前,当前你这个循环,你这个循环,是不是有几次循环,就创建几个按钮啊, //所以说,我们这些,每个按钮的大小都一样,每个按钮的间距都是10,每个按钮的Y坐标都是0,就是这些可以怎么样,这些可以提取到外面,在循环里面,是不是只要算一下它那个X坐标,就可以了吧, //计算按钮的X值 CGFloat answerX = //那么,计算按钮的X值之前,我们是不是还要算一下两边这两个间距啊, //所以,我们循环之前,还要再来一个,CGFloat marginLeft,这两边这两个间距,就等于什么呢,就等于当前self.answerView.frame.size.width,等于这个总View的宽度,减去谁, 减去是不是有几个按钮,就是减去几个按钮的宽度吧,减去几个按钮的宽度,然后再减去谁,减去按钮的个数 - 1 ,也就是len - 1,这么多的margin,吧,是不是总共的宽度,减去它,然后什么的,再减去它,把它们这一堆都减完了以后,最后怎么样,最后乘以0.5,或者除以2,是不是都可以,最后除以2,这样的话,拿到这个值,这个值是不是就是算出了我们距离左边这个距离,其实也就是距离右边的距离吧, CGFloat marginLeft = (self.answerView.frame.size.width - (len * answerW) - (len - 1) * margin ) * 0.5; //然后拿到这个距离以后,第一个按钮的X坐标,就等于这个距离左边的距离吧,就等于这个marginLeft,也就是marginLeft 加上 , 0倍的这个宽度和margin的和吧, //也就是marginLeft + 0 * (answerW + margin) //第二个按钮,等于marginLeft + 1 * (answerW + margin) //第二个按钮,等于marginLeft,加上一倍的这个宽度和margin的和吧, //第三个按钮,等于marginLeft,加上两倍的这个宽度和margin的和吧, //第i个按钮,等于marginLeft,加上当前索引是几,就是几倍的这个宽度和margin的和吧, //第i个按钮,等于marginLeft + i * (answerW + margin) //这样,X的值,就算出来了, //计算按钮的X值 CGFloat answerX = marginLeft +i * (answerW + margin); btnAnswer.frame = CGRectMake(answerX + answerY + answerW + answerH); //这样的话,我们再运行一下,是不是这5个按钮都有了 //再点“下一题”,一片白,因为每次点击这个按钮,都会创建好几个“答案按钮”啊,你点的次数越多,是不是里面的按钮越来越多,就变满屏了,所以说,每一次点之前,要干什么,是不是要清除所有的“答案按钮”吧, //5.0 清除所有的“答案按钮” //怎么来清除所有的“答案按钮”呢,就是如何把一个按钮从我们的控件中移除呢, //就是调用按钮自己的removeFromSuperview,是不是就ok了, //所以说,我这里就这么写: while(self.answerView.subviews.firstObject){ //code; } //while循环,让这个self.answerView.subviews.firstObject,只要它有这么一个对象,有这么一个对象,就怎么办,调什么,让它第一个对象,self.answerView.subviews.firstObject,让它第一个对象,removeFromSuperview, while(self.answerView.subviews.firstObject){ [self.answerView.subviews.firstObject removeFromSuperview]; } //只要你有这个对象,我就让它从父控件中移除,也就是说,每次当你点击“下一题”按钮的时候,我先从这个answerView里面把所有子控件清掉,然后,是不是再创建新控件吧, //运行一下,ok了吧, //好,这样的话,删除每一个子控件,可以这么来删,但是这样写,是不是还得自己去写循环,还得自己去写循环,那么大家还记得数组里面有一个方法是,让数组里面每一个对象执行某个特定的方法,还记得这个吗,就这么写吧,我们可以直接这么写,注意看: //self.answerView.subviews,注意,这个subviews属性,是一个什么类型,是不是一个数组类型啊,NSArray * subviews, //数组里面,每一个对象,是不是就是我们那个按钮类型,我们可以直接让数组调一个makeObjectsPerformSelector:@selector(selector),让数组里面的每一个成员,执行它的哪个方法啊,removeFromSuperview,这样的话,一句话搞定,这句话的意思是,让这个数组里面的每一个成员,每一个对象,分别调一下这个方法, //这句话的意思:让subviews这个数组中的每个对象,分别调一次removeFromSuperview方法,内部执行了循环,无需我们自己来写循环 [self.answerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; //不需要我们自己去写循环了,直接这么写就OK了, //好,我们再运行一下试试看,这样的话,这个答案就生成好了,那么这个答案按钮就生成好了,那么接下来,我们这个黄色背景是不是就可以把它干掉了吧, //怎么给它干掉呢,打开main.storyboard,选中这个控件列表中的answerView,右边的属性,Background,不要选这个Default,选择Clear Color,其实是透明的,没有颜色就是透明的,ok, 好,这是我们这个动态生成“答案”按钮