iOS零星知识点 - 04

查看提示

01 UIView 的触摸事件处理
02 手势识别器----UIGestureRecognizer 的具体手势
03 屏幕适配相关的东东
04 CALayer的一些属性
05 UIView 和 CALayer 的选择
06 修改 UITableViewCell 距离 UITableView 上下左右边距
07 自定义控件--纯代码
08 自定义控件--xib
09 各种手势操作的示范
10 NSArray 快速求总和 最大值 最小值 和 平均值
11 单例模式的宏定义
12 调节屏幕亮度
13 导航控制器原理详解
14 按钮的图片设置问题
15.监听导航栏左侧的返回按钮(局限只能做简单地逻辑判断处理)

pragma mark - 01 UIView 的触摸事件处理
一根或者多根手指开始触摸 view,系统会自动调用 view 的下面方法:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法):
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

一根或者多根手指离开 view,系统会自动调用 view 的下面方法:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用 view 的下面方法:
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

【备注】UIImageView 的 userInteractionEnabled 默认就是 NO,
因此 UIImageView 以及它的子控件默认是不能接收触摸事件的。
pragma mark - 02 手势识别器----UIGestureRecognizer 的具体手势
(1)UITapGestureRecognizer(敲击)
(2)UIPinchGestureRecognizer(捏合,用于缩放)
(3)UIPanGestureRecognizer(拖拽)
(4)UISwipeGestureRecognizer(轻扫)
(5)UIRotationGestureRecognizer(旋转)
(6)UILongPressGestureRecognizer(长按)
pragma mark - 03 屏幕适配相关的东东
设置一个按钮在父控件的屏幕适配:
UIViewAutoresizingFlexibleLeftMargin 距离父控件左边的间距是伸缩的
UIViewAutoresizingFlexibleWidth 自己的宽度跟随着父控件的宽度进行伸缩
UIViewAutoresizingFlexibleRightMargin 距离父控件右边的间距是伸缩的
UIViewAutoresizingFlexibleTopMargin 距离父控件顶部的间距是伸缩的
UIViewAutoresizingFlexibleHeight 自己的高度跟随着父控件的高度进行伸缩
UIViewAutoresizingFlexibleBottomMargin 距离父控件底部的间距是伸缩的
举例
UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
btn.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
pragma mark - 04 CALayer的一些属性
宽度和高度:
@property CGRect bounds;
位置(默认指中点,具体由 anchorPoint 决定):
@property CGPoint position;
锚点(x,y 的范围都是 0-1),决定了 position 的含义:
@property CGPoint anchorPoint;
背景颜色(CGColorRef 类型):
@property CGColorRef backgroundColor;
形变属性:
@property CATransform3D transform;
边框颜色(CGColorRef 类型):
@property CGColorRef borderColor;
边框宽度:
@property CGFloat borderWidth;
圆角半径:
@property CGColorRef borderColor;
内容(比如设置为图片 CGImageRef):
@property(retain) id contents;
例如:
//边框宽度
self.iconView.layer.borderWidth = 10;
// 边框颜色
self.iconView.layer.borderColor = [UIColor greenColor].CGColor;
// 圆角
self.iconView.layer.cornerRadius = 10;
// 超出主层边框范围的内容都剪掉
self.iconView.layer.masksToBounds = YES;
// 阴影颜色
self.iconView.layer.shadowColor = [UIColor blueColor].CGColor;
// 阴影偏差
self.iconView.layer.shadowOffset = CGSizeMake(20, 20);
// 阴影不透明度
self.iconView.layer.shadowOpacity = 0.5;
pragma mark - 05 UIView 和 CALayer 的选择
  • 通过 CALayer,就能做出跟 UIView 一样的界面效果,既然 CALayer 和 UIView 都能实现相同的显示效果,那究竟该选择谁好呢?
  • 其实,对比 CALayer,UIView 多了一个事件处理的功能。也就是说,CALayer 不能处理用户的触摸事件,而 UIView可以。
  • 所以,如果显示出来的东西需要跟用户进行交互的话,用 UIView;如果不需要跟用户进行交互,用 UIView 或者 CALayer 都可以。
  • 当然,CALayer 的性能会高一些,因为它少了事件处理的功能,更加轻量级。
pragma mark - 06 修改 UITableViewCell 距离 UITableView 上下左右边距
UITableViewCell 默认是和 UITableView 上下左右边距没有距离的,要想其上下左右都有一段距离,如下:
方法为重写 UITableViewCell 的 setFrame 方法:
- (void)setFrame:(CGRect)frame{
frame.origin.y += 10;
frame.origin.x = 10
;frame.size.width -= 2 * 10;
frame.size.height -= 10;
[super setFrame:frame];
}
pragma mark - 07 自定义控件--纯代码
  • 一般来说我们的自定义类继承自 UIView,首先在 initWithFrame:方法中将需要的子控件加入 view 中。
  1. 注意,这里只是加入到 view 中,不要设置各个子控件的尺寸。为什么要在 initWithFrame:方法而不是在 init 方法?因为使用纯代码的方式创建自定义类,在以后使用的时候可能使用 init 方法创建,也有可能使用 initWithFrame:方法创建,但是无论哪种方式,最后都会调用到 initWithFrame:方法。

  2. 在这个方法中创建子控件,可以保证无论哪种方式都可以成功创建。为什么要在 initWithFrame:方法里面只是将子控件加到 view 而不设置尺寸?前面已经说过,两种方式最后都会调用到 initWithFrame:方法。如果使用 init 方法创建,那么这个 view 的 frame有可能是不确定的:
    CYLView *view = [[CYLView alloc] init];view.frame = CGRectMake(0, 0, 100, 100);...

3.如果是这种情况,那么在 init 方法中,frame 是不确定的,此时如果在 initWithFrame:方法中设置尺寸,那么各个子控件的尺寸都会是 0,因为这个 view 的 frame 还没有设置。(可以看到是在发送完 init 消息才设置的)所以我们应该保证 view 的 frame 设置完才会设置它的子控件的尺寸。

4.在 layoutSubviews 方法中就可以达到这个目的。第一次 view 将要显示的时候会调用 layoutSubviews 方法,之后当 view 的尺寸(不是位置)改变时,也会调用这个方法。所以正常的做法应该是在 initWithFrame:方法中创建子控件,注意此时子控件有可能只是一个局部变量,所以想要在 layoutSubviews 访问到的话,一般需要创建这个子控件的对应属性来指向它。
@property (nonatomic, weak) UIButton *button; // 注意这里使用 weak 就可以,因为 button 已经被加入到self.view.subviews 这个数组里。...
举例:

- (instancetype)initWithFrame: (CGRect)frame{
if (self = [super initWithFrame: frame]) 
{
// 创建一个 button
UIButton *button = ... 
// 设置 button 的属性
[button setTitle: ...] 
// 将 button 加到 view 中,并不设置尺寸
[self.view addSubview: button]; 
//将 self.button 指向这个 button 保证在 layoutSubviews 中可以访问
self.button = button; 
// 其他的子控件同理
UILabel *label = ... 
}
}这样我们就可以在 layoutSubviews 中访问子控件,设置子控件的尺寸,因为此时 view 的 frame 已经确定。
- (void)layoutSubviews{
// 注意,一定不要忘记调用父类的 layoutSubviews 方法!
[super layoutSubviews]; 
// 设置 button 的 frame
self.button.frame = ... 
// 设置 label 的 frame
self.label.frame = ... 
}
经过以上的步骤,就可以实现自定义控件。
pragma mark - 08 自定义控件--xib
  • 使用 xib 的方式可以省去 initWithFrame:和 layoutSubviews 中添加子控件和设置子控件尺寸的步骤,还有在 viewcontroller 里面设置 view 的 frame,因为添加子控件和设置子控件的尺寸以及整个 view 的尺寸在 xib 中就已经完成。
  • (注意整个 view 的位置还没有设置,需要在控制器里面设置。)我们只需对外提供数据接口,重写 setter 方法就可以显示数据。注意要将 xib 中的类设置为我们的自定义类,这样创建出来的才是自定义类,而不是默认的父类。当然,用 xib 这种方式是需要加载 xib 文件的。
// 第一种方法(较为常用)
CYLView *view = [[[NSBundle mainBundle] loadNibNamed:@"CYLView" owner:nil options:nil] firstObject]; 
//CYLView 代表 CYLView.xib,代表 CYLView 这个类对应的 xib 文件。这个方法返回的是一个 NSArray,我们取第一个 Object 或最后一个(因为这个数组只有一个 CYLView 没有其他对象)就是需要加载的 CYLView。
// 第二种方法
UINib *nib = [UINib nibWithNibName:@"CYLView" bundle:nil];
NSArray *objectArray = [nib instantiateWithOwner:nil options:nil];
CYLView *view = [objectArray firstObject];

#建议在 awakeFromNib 方法中进行初始化外的额外操作。因为 awakeFromNib 是在初始化完成后调用

比如在 CYLView.h 中提供一个类工厂方法:
+ (instancetype)viewWithBook: (Book *)book;
然后在 CYLView.m 中实现这个方法:
+ (instancetype)viewWithBook: (Book *)book
{
CYLView *view = [[[NSBundle mainBundle] loadNibNamed: NSStringFromClass(self) owner: nil opetions: nil]firstObject];
view.book = book;
return view;
}
这样外界只需用 viewWithBook:方法传入一个 book,就可以创建一个 CYLView 的对象,而具体是怎么创建的,只有 CYLView 才知道。
pragma mark - 09 各种手势操作的示范

轻击手势(TapGestureRecognizer)

//新建tap手势 
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)]; 
//设置点击次数和点击手指数 
tapGesture.numberOfTapsRequired = 1; //点击次数 
tapGesture.numberOfTouchesRequired = 1; //点击手指数 
[self.view addGestureRecognizer:tapGesture]; 

//轻击手势触发方法 
-(void)tapGesture: (id)sender 
{ //轻击后要做的事情
}

长按手势(LongPressGestureRecognizer)

//添加长摁手势 
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGesture:)]; 
//设置长按时间 
longPressGesture.minimumPressDuration = 0.5; //(2秒) 
[self.view addGestureRecognizer:longPressGesture]; 
在对应的回调方法中添加相应的方法(当手势开始时执行):
 
//常摁手势触发方法 
-(void)longPressGesture:(id)sender 
{ 
UILongPressGestureRecognizer *longPress = sender; 
if (longPress.state == UIGestureRecognizerStateBegan) 
{ 
 
UIAlertView *alter = [[UIAlertView alloc] initWithTitle:@“提示” message:@“长按触发” delegate:nil cancelButtonTitle:@“取消” otherButtonTitles: nil]; 
[alter show]; 
} 
}
手势的常用状态如下
开始:UIGestureRecognizerStateBegan
改变:UIGestureRecognizerStateChanged
结束:UIGestureRecognizerStateEnded
取消:UIGestureRecognizerStateCancelled
失败:UIGestureRecognizerStateFailed

轻扫手势(SwipeGestureRecognizer)

//添加轻扫手势 
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)]; 
//设置轻扫的方向 
swipeGesture.direction = UISwipeGestureRecognizerDirectionRight; //默认向右 
 [self.view addGestureRecognizer:swipeGesture]; 
 
 
 //添加轻扫手势 
 UISwipeGestureRecognizer *swipeGestureLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)]; 
 //设置轻扫的方向 
 swipeGestureLeft.direction = UISwipeGestureRecognizerDirectionLeft; //默认向右 
 [self.view addGestureRecognizer:swipeGestureLeft];

//轻扫手势触发方法 
-(void)swipeGesture:(id)sender 
{ 
UISwipeGestureRecognizer *swipe = sender; 
if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) 
{ 
//向左轻扫做的事情 
} 
if (swipe.direction == UISwipeGestureRecognizerDirectionRight) 
{ 
 //向右轻扫做的事情 
} 
} 

捏合手势(PinchGestureRecognizer)

//添加捏合手势 
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGesture:)]; 
[self.view addGestureRecognizer:pinchGesture]; 
捏合手势要触发的方法(放大或者缩小图片):
 
 ////捏合手势触发方法 
-(void) pinchGesture:(id)sender 
{ 
UIPinchGestureRecognizer *gesture = sender; 
 //手势改变时 
if (gesture.state == UIGestureRecognizerStateChanged) 
{ 
//捏合手势中scale属性记录的缩放比例 
_imageView.transform = CGAffineTransformMakeScale(gesture.scale, gesture.scale); 
} 
 //结束后恢复 
if(gesture.state==UIGestureRecognizerStateEnded) 
{ 
[UIView animateWithDuration:0.5 animations:{ 
_imageView.transform = CGAffineTransformIdentity;//取消一切形变 
}]; 
} 
} 

拖动手势(PanGestureRecognizer)

//添加拖动手势 
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)]; 
[self.view addGestureRecognizer:panGesture]; 

//拖动手势 
-(void) panGesture:(id)sender 
{ 
UIPanGestureRecognizer *panGesture = sender; 
 CGPoint movePoint = [panGesture translationInView:self.view]; 
 //做你想做的事儿 
} 

旋转手势(RotationGestureRecognizer)

//添加旋转手势 
 UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGesture:)]; 
 [self.view addGestureRecognizer:rotationGesture]; 
 //旋转手势 
-(void)rotationGesture:(id)sender 
 { 
 UIRotationGestureRecognizer *gesture = sender; 
 if (gesture.state==UIGestureRecognizerStateChanged) 
{ 
_imageView.transform=CGAffineTransformMakeRotation(gesture.rotation); 
} 
 if(gesture.state==UIGestureRecognizerStateEnded) 
{ 
[UIView animateWithDuration:1 animations:{ 
_imageView.transform=CGAffineTransformIdentity;//取消形变 
}]; 
} 
}
pragma mark - 10 NSArray 快速求总和 最大值 最小值 和 平均值
NSArray *array = [NSArray arrayWithObjects:@"5.0", @"2.3", @"8.0", @"3.0", @"10", nil];
CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue];
CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue];
CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue];
NSLog(@"%f\n%f\n%f\n%f",sum,avg,max,min);

pragma mark -- 11 单例模式的宏定义

singleton.h文件

//##:连接字符串和参数
//拖进工程就可以用了,传入自己的单例名就好
#define singleton_h(name) + (instancetype)shared##name;

#define singleton_m(name) \
static id _instance; \
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
        _instance = [super allocWithZone:zone]; \
    }); \
    return _instance; \
} \
 \
+ (instancetype)shared##name \
{ \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
        _instance = [[self alloc] init]; \
    }); \
    return _instance; \
} \
 \
+ (id)copyWithZone:(struct _NSZone *)zone \
{ \
    return _instance; \
}

pragma mark — 12 调节屏幕亮度

方法:
[[UIScreen mainScreen] setBrightness: value];
value:value就是屏幕的亮度值  这个值介于0和1之间

另外 这个方法  会即时刷新  无需手动刷新  但这个方法是调整整个手机界面的亮度的  并不仅仅是某个app的亮度  也就是说这个亮度就是在你完全退出这个app后还是会保持的 所以当我们不需要这个亮度继续保持的时候 我们需要在app的代理方法里做些处理 :
//这个方法会在app失去激活状态的时候调用  比如说程序进入后台
- (void)applicationWillResignActive:(UIApplication *)application {
 [[UIScreen mainScreen] setBrightness: 0.5];//0.5是自己设定认为比较合适的亮度值
}
//获取当前屏幕的亮度:
CGFloat *currentLight = [[UIScreen mainScreen] brightness];
另外,屏幕的亮度调节只能在真机上看到效果 在模拟器上看不到效果

pragma mark — 13 导航控制器原理详解

 程序一进入时,就要让窗口的根控制器是一个导航控制器.
    1.新建窗口
    2.创建导航控制器.并设置导航控制器的根控制器
    3.把导航控制器设为窗口的根控制器.
    4.显示窗口.

 说明:1.当设置导航控制器的根控制器时,也就是initWithRootViewController,
            它底层其实是调用了导航控制器的push方法.把该控制器添加为导航控制器的子控制器.
            并且它会把该控制器的View添加到导航控制器专门存放子控制器的View上面.

         2.把导航控制器设为窗口的根控制器时,它就会把导航控制器的View添加到窗口的View上面.
            所以程序一运行时, 我们看到的就是一个导航控制器的View.
            导航控制器的View内部默认有两个子view.一个是导航条, 一个是转专存放子控制器的View.
            现在专门存放子控制器的View里面存放的就是导航控制器根控制器的View.

            导航控制器的子控制器都是存放到一个栈中.也就是一个数组当中.

    当调用导航控制器的push方法时, 就会把一个控制器压入到导航控制器的栈中.
    那么刚压入栈中的这个导航控制器就在栈的最顶部.
    它就会把原来导航控制器View当中存放的子控制器View的内容移除,
    然后把导航控制器栈顶控制器的View添加到导航控制器专门存放子控制器View当中.
    注意:只是把控制器的View从导航控制器存放子控制器的View当中移除,并没有把控制器从栈中移除.所以上一个控制器还在.

    当调用pop当方法时, 就会把导航控制器存放子控制器View当中控制器的View移除,并且会把该控制器从栈里面移除.
    此时该控制器就会被销毁.接着它就会把上一个控制器的View添加到导航控制器专门存放子控制器的View当中.

pragma mark — 14 按钮的图片设置问题

#1.有时我们给按钮设置了不可交互,然后按钮上又有图片,这时图片会变为灰色
解决方法— btn.adjustsImageWhenDisabled = NO;

#2.btn.contentEdgeInsets  = UIEdgeInsetsMake(0,0,0,0);
这个属性是设置btn内部内容到边界的距离的。 如果按钮的宽高为100,100. 我设置了UIEdgeInsetsMake(10,10,10,10);,那么实际按钮内部可显示控件区域为(80,80)

pragma mark — 15.监听导航栏左侧的返回按钮(局限只能做简单地逻辑判断处理)

- (void)viewWillDisappear:(BOOL)animated
{
    if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
    {
        NSLog(@"clicked navigationbar back button");
    }
}


你可能感兴趣的:(iOS零星知识点 - 04)