前言
视图不能交互的几种情况
1./**视图不能交互的几种情况:
1.视图的属性
1》 [[UIButton alloc] init].alpha <= 0.01
2》[[UIButton alloc] init].hidden= YES
3》[[UIButton alloc] init].userInteractionEnabled =NO; UIImageView /UILabel 的userInteractionEnabled 属性默认为NO
2. 若父视图不允许交互,则子视图也是一样不能交互
3.位于父视图的不可见范围的子视图部分 是不能交互的(可以使用clip subviews 属性进行验证);即只有在父视图可见范围才可以交互
*/
- (IBAction)click {
/**
1.Oc风格BOOL 具有 YES 和 NO。实用8位存储空间。从最低位算起。 YES定义为1,NO定义为0。
2.控制台输出布尔值
NSLog(@"ifReadOnly value: %@" ,ifReadOnly?@"YES":@"NO");
*/
NSLog(@"%d",([[UIImageView alloc]init].userInteractionEnabled ? YES: NO));//@property (nonatomic, getter=isUserInteractionEnabled) BOOL userInteractionEnabled; // default is NO
NSLog(@"%d",([[UIButton alloc] init].userInteractionEnabled? YES: NO));//1
}
2.// UIView.userInteractionEnabled属性
@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled; // default is YES. if set to NO, user events (touch, keys) are ignored and removed from the event queue.,但 UIImageView /UILabel 的userInteractionEnabled 属性默认为NO
掌握:
一、按钮的多功能使用
图层(蒙板、或者说遮罩)的操作--蒙板通常是UIButton对象
二、@2x的含义
1、Retina 屏幕
1》对点和像素的理解
提交App Store的时候记得上传这类图标1024x1024 App list in iTunes on devices with retina display
四、数组乱序的实现
//
// ViewController.m
// 02-for
//
// Created by devzkn on 3/12/16.
// Copyright © 2016 hisun. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//使用块代码实现数组排序和乱序
// 数组不能存储nil,因为OC是采用nil 来判断数组是否结束--Collection element of type 'void *' is not an Objective-C object
NSArray *array = @[@(1),@(4),@(5),@(2)];//快速包装NSNumber类型数组
for (NSNumber *number in array) {
NSLog(@"%@",number);
}
array = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber *number1, NSNumber *number2) {
//乱序-->一会升序,一会乱序
//随机
int seed = arc4random_uniform(2);//0-1 之间的随机数
if (seed) {//1 YES 被定义为1
return [number2 compare:number1];
}
return [number1 compare:number2];
}];
NSLog(@"%@",array);
}
/**
sortedArrayUsingComparator 块代码数组排序
*/
- (NSArray *) sortedArrayUsingComparator: (NSArray *)array{
//0 . 数组排序Returns an array that lists the receiving array’s elements in ascending order, as determined by the comparison method specified by a given NSComparator Block.
//1> 返回参数typedef NS_ENUM(NSInteger, NSComparisonResult) {NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending};
array = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber *number1, NSNumber *number2) {
//比较方法(规则)
/**
2016-03-12 11:46:04.539 02-for[1880:51443] nimber1= 1 ;number2= 4
2016-03-12 11:46:04.539 02-for[1880:51443] nimber1= 5 ;number2= 2
2016-03-12 11:46:04.540 02-for[1880:51443] nimber1= 4 ;number2= 5
2016-03-12 11:46:04.540 02-for[1880:51443] nimber1= 4 ;number2= 2
2016-03-12 11:46:04.540 02-for[1880:51443] nimber1= 1 ;number2= 2
1 4 5 2->4 1 5 2 ->4 1 5 2 ->5 4 1 2 -> 5 4 1 2 -> 5 4 2 1
*/
NSLog(@"nimber1= %@ ;number2= %@",number1,number2);
return [number2 compare:number1];//NSOrderedAscending if the value of aNumber is greater than the number object’s, NSOrderedSame if they’re equal, and NSOrderedDescending if the value of aNumber is less than the number object’s. 返回数组元素的比较结果
}];
NSLog(@"%@",array);
return array;
}
/**
块代码遍历数组
*/
- (void)arrayWith: (NSArray *)array {
//1》 数组的遍历Executes a given block using each object in the array, starting with the first object and continuing through the array to the last object.
//2>obj The element in the array.对象 idx The index of the element in the array. 索引 stop A reference to a Boolean value. The block can set the value to YES to stop further processing of the array. The stop argument is an out-only argument. You should only ever set this Boolean to YES within the Block.是否中断
//3 > 块数组的遍历方法效率比 for in 方式来的高
[array enumerateObjectsUsingBlock:^(NSNumber *obj, NSUInteger idx, BOOL *stop) {
NSLog(@"%@ idx= %lu",obj,idx);
if (1 == idx) {
*stop = YES;//退出循环
}
}];
}
@end
五、主要方法,尽量保留简洁代码,体现思路和流程即可
ps:p s:0>xcode 的快捷键:option+command+left(代码折叠)、
1> 模拟器的快捷键 :切换屏幕 shift+command+h(显示主界面)、shift+command+h+h(结束程序)
六、等待一段时间,再让线程调用方法的例子
1》 延迟进入下一题-》目的是给玩家展示绿色答案文字
//等待0.5秒,直接进入下一题Invokes a method of the receiver on the current thread using the default mode after a delay.
[self updateAnswerButtonTitleColor:[UIColor greenColor]];//动画显示答案字体为绿色
[self performSelector:@selector(nextQuestion) withObject:nil afterDelay:1.0];
//2》 动画结束要清空UIImageView 对象的属性AnimationImages,即设置其为nil
//清除内存的代码简化--可以避免定义cleanUpAnimationsArray方法,直接调用setAnimationImages方法进行arrayImage的清除
[self.imageList performSelector:@selector(setAnimationImages:) withObject:nil afterDelay:self.imageList.animationDuration];
//- (void)cleanUpAnimationsArray{
// NSLog(@"%s ",__func__);
// //动画结束之后清除帧动画数组
// [self.imageList setAnimationImages:nil];
//
//}
七、 实现方法的时候,考虑执行该方法的条件
//1.再定义方法时,首先考虑的一个问题是:先判断是否达到执行该方法的资格(条件),否则直接return
//1》答案区的点击事件
#pragma mark - 答题按钮的监听方法,若答案按钮标题的空的,没必要执行本方法
/**
处理答题按钮点击事件
*/
- (void) answerButtonClick:(UIButton *) answerButton{
//1.如果当前答案按钮没有标题,直接return
if (nil == answerButton.currentTitle) {
return;
}
//2》 候选区的点击事件,若答案区都是满的,就没必要执行该方法
#pragma mark - 候选按钮点击方法;
- (void)optionButtonClick:(UIButton *)button{
//1.找到答案区的第一个没有标题的按钮
UIButton *nilTitleButton = [self firstNilTitleAnswerButton];
if (nil == nilTitleButton) {//找不到空标题按钮,return
return;
}
八、字符串对象是否为空的判断
//1.对象比较的效率 比数值型比较效率低
//1>效率好些的空字符串对象判断:
if (0 == answerButton.currentTitle.length) {
return;
}
//2>效率低:
if (nil == nilTitleButton) {//找不到空标题按钮,return
return;
}
正文
疯狂猜图案例的需求分析
Click here to expand…疯狂猜图案例的需求分析
1.搭建界面
1》上半部分空间位置固定的,使用storyBoard进行布局连线
2》下半部分的控件,是根据题目的变化而变化-》采用代码方式进行界面搭建
2.编写代码(按照流程进行实现,即用户的操作习惯流程)
1》大图小图的切换
2》下一题的实现
3》备选按钮点击事件处理(让文字进入答案区)
4》判断胜负:胜利,界面切换到下一题;失败,提示用户重新选择答案
5》答题按钮点击事件的处理:把答案区的文字恢复到备选区域
3.收尾工作
图标和启动页面
总结
OC 解决NSArray直接打印中文出现乱码的问题?
解决方法:就是需要通过为NSArray添加分类,重写 - (NSString *)descriptionWithLocale:(id)locale方法即可
附
控制器的代码实现
//
// ViewController.m
// 01-超级猜图
//
// Created by devzkn on 3/9/16.
// Copyright © 2016 devzkn. All rights reserved.
//
#import "ViewController.h"
#import "HSQuestion.h"
#define KButtonWidth 35
#define KButtonSpacingWidth 10 // 按钮的行间距
#define KButtonSpacingHeight 5 //按钮的列间距
#define KButtonHeight 35
//九宫格算法 x 决定的是其所在的列,y 决定其所在的行
#define KButtonColumn 7 //列数
#define KButtonRow 3//行数
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *iconButton;//图像按钮
@property (nonatomic,weak) UIButton *cover;//蒙板
@property (nonatomic,strong) NSArray *questions;//问题数组
@property (nonatomic,assign) int index;//当前题目index
@property (weak, nonatomic) IBOutlet UILabel *noLabel;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *nextButton;
@property (weak, nonatomic) IBOutlet UIView *answerView;
@property (weak, nonatomic) IBOutlet UIView *optionsView;
@property (weak, nonatomic) IBOutlet UIButton *coinButton;//金币按钮
@end
@implementation ViewController
/**
懒加载questions
*/
- (NSArray *) questions{
if (nil == _questions) {
_questions = [HSQuestion questionList];
}
return _questions;
}
/**
懒加载蒙板按钮控件
*/
- (UIButton *)cover{
if (nil == _cover){
//创建蒙板
UIButton *tmpCover = [[UIButton alloc]initWithFrame:self.view.bounds];
[tmpCover setBackgroundColor: [UIColor colorWithWhite:0.0 alpha:0.5]];
[tmpCover setAlpha:0.0];
//添加conver图层的监听事件
[tmpCover addTarget:self action:@selector(smallerIconButton) forControlEvents:UIControlEventTouchUpInside];
_cover=tmpCover;
[self.view addSubview:_cover];//cover强引用+1
}
return _cover;
}
- (void)viewDidLoad {
[super viewDidLoad];
//上半部分的界面控件基本是静态的,采用storyBoard进行实现
//搭建下半部分的界面,采用代码实现
//初始化界面
[self nextQuestion];
}
/**
he preferred status bar style for the view controller.调整状态栏颜色
*/
- (UIStatusBarStyle)preferredStatusBarStyle NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED{// Defaults to UIStatusBarStyleDefault
return UIStatusBarStyleLightContent;
}
/**
pecifies whether the view controller prefers the status bar to be hidden or shown. 重写方法
*/
- (BOOL)prefersStatusBarHidden NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED{
return NO;//A Boolean value of YES specifies the status bar should be hidden. Default value is NO.
}
/**
大图小图切换
*/
#pragma mark - 大图小图切换--pragma 是预处理命令
- (IBAction)biggerSmallerIconButton {
//判断当前的图像按钮是否处于放大状态,如果是就进行缩小,否则进行放大;
//判断依据为蒙板cover的Alpha属性值
if (1.0 == self.cover.alpha) {// Alpha: 1.0 放大状态,0.0 缩小状态
[self smallerIconButton];
return ;
}
[self biggerImage];
}
#pragma mark - 下一题的实现
/**
下一题
1.在主要方法中,尽量保留简短代码,体现思路和流程即可
*/
- (IBAction)nextQuestion{
//如果题号大于等于总题数 ,直接return,即只有题号self.index为“0-题目总数” 的时候才执行本方法
if (self.questions.count <= self.index || 0 >self.index) {
return;
}
//下一题,在数据模型中是数据递增的关系
//1> 当前答题的index递增
self.index = (self.index <self.questions.count) ? self.index+1 :self.index;
//禁用next Button 的判断,(在题目序号递增之后判断)
// [self.nextButton setEnabled: (self.index >=self.questions.count || self.index < 0 ) ? NO : YES];//当前题目序号大于或者等于题目总数,以及小于0 就禁用,否则就启用
[self.nextButton setEnabled:(self.index>0 && self.index < self.questions.count)];//当题号》0且题号小于总题数,就启用nextbutton按钮,否则禁用button
//2> 根据题目index从数据模型数组取出question对象(题目数据)
HSQuestion *question = self.questions [self.index-1];//当前题目的数据模型在数组中的index=当前题目的index-1
// 3> 通过建立连线获得基本信息控件;修改题目的基本信息(iconImage、title 以及题目的index控件)
[self setupBasicInfo:question];
//4>答案区按钮设置,根据答案的文字个数进行布局
[self createAnswerButtons:question];
//5>创建备选按钮
[self createOptionButtons:question];
}
/**
设置基本信息
*/
- (void)setupBasicInfo:(HSQuestion *)question{
//设置iconImage
[self.iconButton setImage:question.iconImage forState:UIControlStateNormal];
//设置title控件
[self.titleLabel setText:[NSString stringWithFormat: @"%@",question.title]];
//设置题目的index
[self.noLabel setText:[NSString stringWithFormat:@"%d/%lu",self.index,self.questions.count]];
}
/**
创建答案区按钮
*/
- (void)createAnswerButtons: (HSQuestion *)question{
//清空上一题的答案按钮
for (UIView *button in [self.answerView subviews]) {//使用的UIbutton 都继承于UIView
[button removeFromSuperview];//多态的应用
}
//布局答案区,类似九宫格
//根据答案文字个数往视图添加按钮
// 获取问题答案的个数
long answerNo = question.answer.length;
//第一个button的x值
CGFloat answerX =(CGRectGetWidth(self.answerView.frame)- answerNo*KButtonWidth-(answerNo-1)*KButtonSpacingWidth)*0.5 ;
for (int i= 0; i<answerNo; i++) {
CGFloat x = answerX + i*(KButtonWidth+KButtonSpacingWidth);
UIButton *answerButton = [[UIButton alloc]initWithFrame:CGRectMake(x, 0, KButtonWidth, KButtonHeight)];
[answerButton setBackgroundColor:[UIColor whiteColor]];
[answerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
//设置背景图片
[answerButton setBackgroundImage:[UIImage imageNamed:@"btn_answer"] forState:UIControlStateNormal];
[answerButton setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState:UIControlStateHighlighted];
//设置按钮的监听方法
[answerButton addTarget:self action:@selector(answerButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.answerView addSubview:answerButton];
}
}
/**
创建候选区按钮,
*/
- (void)createOptionButtons:(HSQuestion *)question{
//1》如果已经存在候选按钮,就直接修改按钮标题,不用在创建候选按钮
NSArray *subviewsArray = [self.optionsView subviews];
if (subviewsArray.count >=
question.options.count) {
//获取按钮文字
for (int i=0 ;i<subviewsArray.count;i++) {
[subviewsArray[i] setTitle:question.options[i] forState:UIControlStateNormal];
//设置按钮为可见
[subviewsArray[i] setHidden:NO];
}
return;//设置完标题直接结束方法
}
//2》创建候选按钮
// 设置候选区按钮显示内容(用模型数据装配),根据候选文字总数 进行布局,并使用乱序算法进行装配按钮控件
// // 清空上一题候选按钮(清除optionsView的所有子视图)
for (UIView *view in [self.optionsView subviews]) {
[view removeFromSuperview];
}
//根据列数、行数 的个数 进行候选区的的布局(九宫格)
//定义行第一列的buttonX值
CGFloat optionMarginX = (CGRectGetWidth(self.optionsView.frame)-KButtonColumn*KButtonWidth -(KButtonColumn-1)*KButtonSpacingWidth)*0.5;
CGFloat optionMarginY = (CGRectGetHeight(self.optionsView.frame)- KButtonRow*KButtonHeight-(KButtonRow-1)*KButtonSpacingHeight)*0.5;
//对候选答案进行乱序可在数据模型HSQuestion questionList方法中实现
//布局候选按钮,并装配数据
for (int i =0 ; i<question.options.count; i++) {
//创建候选按钮
int columnNo = i%KButtonColumn ;//button 所在的列
int rowNo = i/KButtonColumn;//button 所在的行数
//计算button 的x,y
CGFloat x = optionMarginX +columnNo*(KButtonWidth+KButtonSpacingWidth);//x 值与列数相关
CGFloat y = optionMarginY+rowNo*(KButtonHeight+KButtonSpacingHeight);//y值与行数关联
UIButton *optionButton = [[UIButton alloc] initWithFrame:CGRectMake(x, y, KButtonWidth, KButtonHeight)];
[optionButton setBackgroundColor:[UIColor whiteColor]];
//设置候选答案文字
[optionButton setTitle:question.options[i] forState:UIControlStateNormal];
//设置按钮文字font
[optionButton.titleLabel setFont:[UIFont systemFontOfSize:12]];
//设置文字颜色
[optionButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
//设置按钮的背景图片
[optionButton setBackgroundImage:[UIImage imageNamed:@"btn_option"] forState:UIControlStateNormal];
[optionButton setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
//设置候选按钮的监听方法
[optionButton addTarget:self action:@selector(optionButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.optionsView addSubview:optionButton];
}
}
#pragma mark - 候选按钮点击方法
- (void)optionButtonClick:(UIButton *)button{
//1.找到答案区的第一个没有标题的按钮
UIButton *nilTitleButton = [self firstNilTitleAnswerButton];
if (nil == nilTitleButton) {//找不到空标题按钮,return
return;
}
//找到了空标题按钮的操作:
//2.将按钮标题设置到答题区视图的第一个空标题按钮中
[nilTitleButton setTitle:button.titleLabel.text forState:UIControlStateNormal];
[button setHidden:YES]; //将按钮设置为不可见
//3.判断胜负(如果答案区的按钮均非空,即可进行答案判断)
[self judge];
}
/**
判断结果,并提示玩家
*/
-(void)judge{
//1> 判断用户是否填写完问题,填完整了,才需要判断结果,否则return
NSArray *array = [self.answerView subviews];
//用户填写答案
NSMutableString *userAnswer = [[NSMutableString alloc]init];
for (UIButton *btn in array) {
if (btn.currentTitle.length == 0) {//如果有一个空为空,直接return
return ;
}
[userAnswer appendString:btn.currentTitle];
}
//2> 获取问题答案,进行比对,如果错误,就在答案区提示玩家,否则直接进入下一题
//获取正确答案
HSQuestion *question = self.questions[self.index-1];//当前题号-1 即使其所在数组对应的下标
if ([question.answer isEqualToString:userAnswer]) {
[self updateAnswerButtonTitleColor:[UIColor greenColor]];//动画显示答案字体为绿色
//分数奖励
[self changeScore:500];
//等待0.5秒,直接进入下一题Invokes a method of the receiver on the current thread using the default mode after a delay.
[self performSelector:@selector(nextQuestion) withObject:nil afterDelay:1.0];
return;
}
//3>提示玩家重新选择,将答题按钮文字颜色改为红色
[self updateAnswerButtonTitleColor:[UIColor redColor]];
}
/**
修改答题区按钮的颜色
*/
- (void) updateAnswerButtonTitleColor:(UIColor *)color{
[UIView animateWithDuration:10.0f animations:^{
for (UIButton *answerButton in [self.answerView subviews]) {
[answerButton setTitleColor:color forState:UIControlStateNormal];
}
}];
}
#pragma mark - 答题按钮的监听方法
/**
处理答题按钮点击事件
*/
- (void) answerButtonClick:(UIButton *) answerButton{
//1.如果当前答案按钮没有标题,直接return
if (0 == answerButton.currentTitle.length) {
return;
}
//2.执行此方法,意味着用户去除掉了一个字(即答题区的内容不完整),此时应将答案区的文字颜色恢复成黑色
[self updateAnswerButtonTitleColor:[UIColor blackColor]];
//3.设置与“当前按钮的”相同标题的候选区按钮为可见(执行到这里按理都会有存在这样的候选按钮)
[[self optionButtonWithTitle:answerButton.currentTitle isHidden:YES] setHidden:NO ];
//移除当前按钮的标题
[answerButton setTitle:nil forState:UIControlStateNormal];
}
/**
根据title查找候选区按钮,特殊要求(规则,目标按钮的Hidden属性为YES 或者为NO)
*/
- (UIButton *) optionButtonWithTitle:(NSString *)title isHidden:(BOOL)isHidden{
//考虑候选区有重复标题按钮的问题,增加Hidden属性的判断,只有为YES才是“答案按钮点击功能”要找的目标按钮;只有为NO的按钮才是“提示功能”要找的目标
for (UIButton *optionButton in [self.optionsView subviews]) {
if ([title isEqualToString:optionButton.currentTitle] && (optionButton.hidden == isHidden)) {
return optionButton;
}
}
return nil;
}
/**
查找文字为空的按钮
*/
- (UIButton *)firstNilTitleAnswerButton{
NSArray *answerButtonArray =[self.answerView subviews];
for (UIButton *button in answerButtonArray) {
//找出没有标题的按钮
if (0 == button.currentTitle.length ) {//这个判断方法比使用nil 进行判断的效率更高
return button;
}
}
return nil;
}
/**
放大图片
*/
- (void)biggerImage {
//0>biggerSmallerIconButton 保证将图像按钮bringSubviewToFront之前,cover的已经创建完成
//1》将图像按钮添加至最顶层 Moves the specified subview so that it appears on top of its siblings.
[self.view bringSubviewToFront:self.iconButton];
//2》用块动画放大图像按钮
CGFloat width = CGRectGetWidth(self.view.frame);
CGFloat height = width;
CGFloat x=0;
CGFloat y= (CGRectGetHeight(self.view.frame)- height)*0.5;
//块动画
[UIView animateWithDuration:1.0f animations:^{
//动画内容:修改图像按钮大小、位置以及cover的透明度
[self.iconButton setFrame:CGRectMake(x, y, width, height)];
[self.cover setAlpha:1.0];
}];
}
/**
将图像按钮恢复原来大小
*/
- (void) smallerIconButton{
//使用块动画恢复icon Button的大小和位置,块动画是预先准备好的代码,一旦定义,将立即执行
[UIView animateWithDuration:1.0f animations:^{
[self.iconButton setFrame:CGRectMake(85, 85, 150, 150)];
[self.cover setAlpha:0.0];//将cover按钮控件设为不可见
}];
//设置图像按钮的放大、缩小状态
[self.iconButton setTag:0];
}
#pragma mark - 提示功能
/**
1.提示功能的实现(用代码代替用户的按钮点击行为)
2. 提示功能,是要进行扣分,即执行该功能你必须达到消费的积分额度
*/
- (IBAction) tip{
if (self.coinButton.currentTitle.intValue <500) {//金币数小于本次消费的金币额度,直接结束
return;
}
//1.清空答案区的title并恢复候选按钮
[self cleanAnswerButtons];
// 2.取出正确答案的第一个字,并设置到都一个答案按钮,并隐藏候选区对应的按钮
//获取当前题目模型对象
HSQuestion *question =self.questions[self.index-1];
//获取与“正确答案第一个字母”相同标题候选按钮
UIButton *optionButton = [self optionButtonWithTitle:[question.answer substringToIndex:1] isHidden:NO];
//设置标题到答案区,并隐藏候选区按钮
[self optionButtonClick:optionButton];
//进行分数的扣减
[self changeScore:-500];
}
/**
清空答案区按钮,并恢复候选按钮
*/
- (void) cleanAnswerButtons{
for (UIButton *btn in [self.answerView subviews]) {
//直接调用答案按钮的监听方法
[self answerButtonClick:btn];//
}
}
#pragma mark - 分数处理
/**
分数处理
*/
- (void) changeScore:(int) score{
score += self.coinButton.currentTitle.intValue ;
[self.coinButton setTitle: [NSString stringWithFormat:@"%d",score] forState:UIControlStateNormal];
}
@end
作者:u011018979 发表于2017/6/27 10:55:23 原文链接
阅读:26 评论:0 查看评论