UINavigationController的使用步骤
// UINavigationController以栈的形式保存子控制器
@property(nonatomic,copy) NSArray *viewControllers;
@property(nonatomic,readonly) NSArray *childViewControllers;
// 使用push方法能将某个控制器压入栈
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 使用pop方法可以移除控制器
// 将栈顶的控制器移除
- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
// 回到指定的子控制器
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
// 回到根控制器(栈底控制器)
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;
// 导航栏的内容由栈顶控制器的navigationItem属性决定
// UINavigationItem有以下属性影响着导航栏的内容
// 左上角的返回按钮
@property(nonatomic,retain) UIBarButtonItem *backBarButtonItem;
// 中间的标题视图
@property(nonatomic,retain) UIView *titleView;
// 中间的标题文字
@property(nonatomic,copy) NSString *title;
// 左上角的视图
@property(nonatomic,retain) UIBarButtonItem *leftBarButtonItem;
// 右上角的视图
@property(nonatomic,retain) UIBarButtonItem *rightBarButtonItem;
与之相关的三个方法:
UITabBarController的使用步骤
UITabBarController添加控制器的方式有2种
1. 沙盒根目录
NSString *home = NSHomeDirectory();
2. 获取Documents文件夹
// *********方式1.利用沙盒根目录拼接”Documents”字符串*************
// 不建议采用,因为新版本的操作系统可能会修改目录名
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];
// **********方式2. 利用NSSearchPathForDirectoriesInDomains函数**********
// NSUserDomainMask 代表从用户文件夹下找
// YES 代表展开路径中的波浪字符“~”
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO);
// 在iOS中,只有一个目录跟传入的参数匹配,所以这个集合里面只有一个元素
NSString *documents = [array objectAtIndex:0];
3. tmp
NSString *tmp = NSTemporaryDirectory();
4. Library/Caches (跟Documents类似的2种方法) 利用沙盒根目录拼接”Caches”字符串 利用NSSearchPathForDirectoriesInDomains函数(将函数的第2个参数改为:NSCachesDirectory即可)
5. Library/Preference 通过NSUserDefaults类存取该目录下的设置信息
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中
1. 保存数据
// 将数据封装成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"母鸡" forKey:@"name"];
[dict setObject:@"15013141314" forKey:@"phone"];
[dict setObject:@"27" forKey:@"age"];
// 将字典持久化到Documents/stu.plist文件中
[dict writeToFile:path atomically:YES];
2. 读取数据
// 读取Documents/stu.plist的内容,实例化NSDictionary
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
// 打印信息
NSLog(@"name:%@", [dict objectForKey:@"name"]);
NSLog(@"phone:%@", [dict objectForKey:@"phone"]);
NSLog(@"age:%@", [dict objectForKey:@"age"]);
使用NSKeyedArchiver可以持久化一个对象(包括自定义的对象)
注意:要持久化的对象必须实现NSCoding协议,并实现该协议中的encodeWithCoder:(NSCoder *)encoder和initWithCoder:(NSCoder *)decoder方法
e.g.
/*******************Person.h******************/
#import <Foundation/Foundation.h>
// 如果想将一个自定义对象保存到文件中必须实现NSCoding协议
@interface Person : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) double height;
@end
/*******************Person.m******************/
#import "Person.h"
@implementation Person
// 当将一个自定义对象保存到文件的时候就会调用该方法
// 在该方法中说明如何存储自定义对象的属性
// 也就说在该方法中说清楚存储自定义对象的哪些属性
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeInteger:self.age forKey:@"age"];
[encoder encodeFloat:self.height forKey:@"heigth"];
}
// 当从文件中读取一个对象的时候就会调用该方法
// 在该方法中说明如何读取保存在文件中的对象
// 也就是说在该方法中说清楚怎么读取文件中的对象
- (id)initWithCoder:(NSCoder *)decoder
{
if (self = [super init]) {
self.name = [decoder decodeObjectForKey:@"name"];
self.age = [decoder decodeIntegerForKey:@"age"];
self.height = [decoder decodeFloatForKey:@"heigth"];
}
return self;
}
@end
/*******************在控制器中使用时******************/
/**************************************************/
/**************************************************/
// 将一个Penson对象持久化至本地,path为要保存至的文件路径
[NSKeyedArchiver archiveRootObject:person toFile:path];
// 将文件中持久化的数据实例化至Person对象p中
Person *p = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能。每个应用都有个NSUserDefaults实例,通过它来存取偏好设置。
1. 保存偏好设置
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"itcast" forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];
2. 读取偏好设置
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:@"username"];
float textSize = [defaults floatForKey:@"text_size"];
BOOL autoLogin = [defaults boolForKey:@"auto_login"];
注意:UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入
[defaults synchornize];
// 1.获得图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2. 拼接路径(下面代码是一条线段)
CGContextMoveToPoint(ctx, 10, 10);
CGContextAddLineToPoint(ctx, 100, 100);
// 3. 绘制路径
CGContextStrokePath(ctx); // 绘制路径
// CGContextFillPath(ctx); // 绘制封闭的填充图形
Bitmap Graphics Context
UIGraphicsBeginImageContext(CGSize size)
UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) opaque : YES:不透明 NO:透明
PDF Graphics Context
Window Graphics Context
Layer Graphics Context
可在UIView的drawRect:方法里面通过UIGraphicsGetCurrentContext()方法获得
Printer Graphics Context
e.g. 画图并保存至本地文件(bitmap的创建以及使用)
// 0. 创建bitmap上下文
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0);
// 1.获取bitmap上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.绘图
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
// 3.渲染
CGContextStrokePath(ctx);
// 4.获取生成的图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 5.显示生成的图片到imageview
self.iv.image = image;
// 6.保存绘制好的图片到文件中
// 先将图片转换为二进制数据, 然后再将图片写到文件中
NSData *data = UIImagePNGRepresentation(image);
[data writeToFile:@"/Users/apple/Desktop/abc.png" atomically:YES];
添加一个矩形
void CGContextAddRect(CGContextRef c, CGRect rect)
CGContextStrokeRect(CGContextRef c, CGRect rect) 直接绘制一个空心矩形(所有图形都有这个方法)
CGContextFillRect(CGContextRef c, CGRect rect) 直接绘制一个实心矩形(所有图形都有这个方法)
添加一个椭圆(rect为椭圆的外接圆)
void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)
添加一个圆弧
void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
其中:
x/y 圆心
radius 半径
startAngle 开始的弧度 eg: M_PI
endAngle 结束的弧度
clockwise 画圆弧的方向 (0 顺时针, 1 逆时针)
关闭路径
void CGContextClosePath ( CGContextRef c )
获得上下文
CGContextRef UIGraphicsGetCurrentContext()
设置颜色
[[UIColor purpleColor] setFill]; 设置实心颜色
[[UIColor blueColor] setStroke]; 设置空心颜色
[[UIColor greenColor] set]; 同时设置空心/实心颜色
[[UIColor colorWithRed:1.0 green:0 blue:0 alpha:1.0] set]; 同时设置空心/实心颜色
画曲线(一条直线通过几个控制点的扭曲实现)
void CGContextAddCurveToPoint(CGContextRef c, CGFloat cp1x, CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y )
CGContextAddQuadCurveToPoint(CGContextRef c, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y)
其中:
cpx/cpy 是指控制点的坐标
x/y 终点的坐标
Path的一些方法
CGPathCreateMutable 类似于 CGContextBeginPath
CGPathMoveToPoint 类似于 CGContextMoveToPoint
CGPathAddLineToPoint 类似于 CGContextAddLineToPoint
CGPathAddCurveToPoint 类似于 CGContextAddCurveToPoint
CGPathAddEllipseInRect 类似于 CGContextAddEllipseInRect
CGPathAddArc 类似于 CGContextAddArc
CGPathAddRect 类似于 CGContextAddRect
CGPathCloseSubpath 类似于 CGContextClosePath
CGPathRef
CGMutablePathRef
注意:但凡通过quarzt2d中的带有create/ copy / retain 方法创建出来的值都必须手动的释放
在此创建路径时,记得释放创建的路径,释放路径的两种方法
CGPathRelease(path)
CFRelease(path)
将Path添加至上下文
void CGContextAddPath(CGContextRef context, CGPathRef path);
绘制图形
CGContextStrokePath(ctx); // 绘制路径
CGContextFillPath(ctx); // 绘制封闭的填充图形
设置渲染时的参数
void CGContextSetLineWidth(CGContextRef c, CGFloat width); 设置线条的宽度
void CGContextSetLineJoin(CGContextRef c, CGLineJoin join) 设置线条转角样式
void CGContextSetMiterLimit(CGContextRef c, CGFloat limit) 当转角样式为Miter时,limit参数对其有影响
void CGContextSetLineDash(CGContextRef c, CGFloat phase, const CGFloat lengths[], size_t count) 虚线相关
保存/恢复图形上下文
CGContextSaveGState(ctx) 保存上下文至堆栈
CGContextRestoreGState(ctx) 恢复已保存的上下文至ctx
清空上下文内容
CGContextClearRect(CGContextRef c, CGRect rect)
对layer进行矩阵操作
CGContextRotateCTM(CGContextRef c, CGFloat angle)
CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
指定可以显示的范围(可用来剪切图片)
CGContextClip(ctx);
通知UIView刷新视图
- (void)setNeedsDisplay;
- (void)setNeedsDisplayInRect:(CGRect)rect;
NSTimer & CADisplayLink刷帧变成动画
具体用法见系列第十四点:NSTimer & CADisplayLink
获取上下文中的图片
UIImage* UIGraphicsGetImageFromCurrentImageContext(void)
将图片转为NSData类型,使其可以保存至文件中
NSData *UIImageJPEGRepresentation(UIImage *image, CGFloat compressionQuality);
NSData *UIImagePNGRepresentation(UIImage *image); png图片效果更好
基本思想:创建一个bitmap,首先绘制原图,然后在原图的某个位置绘制水印,最后保存。
// 1.调用分类方法生成水印图片
UIImage *newImage = [UIImage imageWithBackgroundImageName:@"psb" log:@"logo1"];
// 2.将图片写到文件中
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"aaa.png"];
NSData *data = UIImagePNGRepresentation(newImage);
[data writeToFile:path atomically:YES];
生成水印的方法
+ (instancetype)imageWithBackgroundImageName:(NSString *)bgName log:(NSString *)logNmae
{
// 0. 加载背景图片
UIImage *image = [UIImage imageNamed:bgName];
// 1.创建bitmap上下文
// 执行完这一行在内存中就相遇创建了一个UIImage
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
// 2.绘图图片
// 绘制背景图片
[image drawAtPoint:CGPointMake(0, 0)];
// 绘制水印
UIImage *logImage = [UIImage imageNamed:logNmae];
CGFloat margin = 10;
CGFloat logY = margin;
CGFloat logX = image.size.width - margin - logImage.size.width;
[logImage drawAtPoint:CGPointMake(logX, logY)];
// NSString *str = @"如果仅有文字,可以这样";
// [str drawAtPoint:CGPointMake(150, 50) withAttributes:nil];
// 3.获得图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
return newImage;
}
// 1.生成一张以后用于平铺的小图片
CGSize size = CGSizeMake(self.view.frame.size.width, 44);
UIGraphicsBeginImageContextWithOptions(size , NO, 0);
// 2.画矩形
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat height = 44;
CGContextAddRect(ctx, CGRectMake(0, 0, self.view.frame.size.width, height));
[[UIColor redColor] set];
CGContextFillPath(ctx);
// 3.画线条
CGFloat lineWidth = 2;
CGFloat lineY = height - lineWidth;
CGFloat lineX = 0;
CGContextMoveToPoint(ctx, lineX, lineY);
CGContextAddLineToPoint(ctx, 320, lineY);
[[UIColor blackColor] set];
CGContextStrokePath(ctx);
// Key Point : 调用UIColor里面的colorWithPatternImage函数获取条纹背景,
// 然后设置为背景颜色即可
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIColor *myColor = [UIColor colorWithPatternImage:image];
self.contentView.backgroundColor = myColor;
CATransition的其他用法详见39.4.5:CATransition
CATransition *ca = [[CATransition alloc] init];
ca.type = @"pageCurl";
[self.contentView.layer addAnimation:ca forKey:nil];
// 1.创建一个bitmap的上下文
UIGraphicsBeginImageContext(self.view.frame.size);
// 2.将屏幕绘制到上下文中
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 3.保存图片到相册
UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
注意:访问相册时iOS会提示是否允许app访问相册。如果用户禁止访问相册,然后又保存了图片,则最好在image:didFinishSavingWithError:contextInfo:函数里面提示用户允许app访问
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error) {
NSLog(@"保存失败,app应提示用户在Settings -> Privacy -> Camera 中将对应app的UISwitch置为On");
}else
{
NSLog(@"提示保存成功");
}
}
// 1. 创建路径
UIBezierPath *path = [UIBezierPath bezierPath];
// 2.设置路径的相关属性 (options)
[path setLineJoinStyle:kCGLineJoinRound];
[path setLineCapStyle:kCGLineCapRound];
[path setLineWidth:10];
// 3. 设置当前路径的起点
[path moveToPoint:startPoint];
// 4. 设置当前路径的终点
[path addLineToPoint:movePoint];
// 5. 绘制path
[path stroke];
iOS中的事件可分为三类:
1. 触摸事件
2. 加速计事件
3. 远程控制事件
在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”。UIApplication、UIViewController、UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件。
UIResponder内部提供了以下方法来处理事件
触摸事件
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
touches里面存放的都是UITouch对象
加速计事件
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
-(void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
远程控制事件
-(void)remoteControlReceivedWithEvent:(UIEvent *)event;
当用户用一根触摸屏幕时,会创建一个与手指相关联的UITouch对象
一根手指对应一个UITouch对象
UITouch保存着跟手指相关的信息,比如触摸的位置、时间、阶段
当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置
当手指离开屏幕时,系统会销毁相应的UITouch对象
提示:iPhone开发中,要避免使用双击事件!!!
触摸产生时所处的窗口
@property(nonatomic,readonly,retain) UIWindow *window;
触摸产生时所处的视图
@property(nonatomic,readonly,retain) UIView *view;
短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
@property(nonatomic,readonly) NSUInteger tapCount;
记录了触摸事件产生或变化时的时间,单位是秒
@property(nonatomic,readonly) NSTimeInterval timestamp;
当前触摸事件所处的状态
@property(nonatomic,readonly) UITouchPhase phase;
-(CGPoint)locationInView:(UIView *)view;
返回值表示触摸在view上的位置
这里返回的位置是针对view的坐标系的(以view的左上角为原点(0, 0))
调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
-(CGPoint)previousLocationInView:(UIView *)view;
该方法记录了前一个触摸点的位置
每产生一个事件,就会产生一个UIEvent对象
UIEvent:称为事件对象,记录事件产生的时刻和类型
事件类型
@property(nonatomic,readonly) UIEventType type;
@property(nonatomic,readonly) UIEventSubtype subtype;
事件产生的时间
@property(nonatomic,readonly) NSTimeInterval timestamp;
一次完整的触摸过程,会经历3个状态:
触摸开始:- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event
触摸移动:- (void)touchesMoved:(NSSet )touches withEvent:(UIEvent )event
触摸结束:- (void)touchesEnded:(NSSet )touches withEvent:(UIEvent )event
触摸取消(可能会经历):- (void)touchesCancelled:(NSSet )touches withEvent:(UIEvent )event
4个触摸事件处理方法中,都有NSSet *touches和UIEvent *event两个参数
一次完整的触摸过程中,只会产生一个事件对象,4个触摸方法都是同一个event参数
如果两根手指同时触摸一个view,那么view只会调用一次touchesBegan:withEvent:方法,touches参数中装着2个UITouch对象
如果这两根手指一前一后分开触摸同一个view,那么view会分别调用2次touchesBegan:withEvent:方法,并且每次调用时的touches参数中只包含一个UITouch对象
根据touches中UITouch的个数可以判断出是单点触摸还是多点触摸
响应者链条的事件传递过程:
1. 如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图
2. 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
3. 如果window对象也不处理,则其将事件或消息传递给UIApplication对象
4. 如果UIApplication也不能处理该事件或消息,则将其丢弃
为了完成手势识别,必须借助于手势识别器—-UIGestureRecognizer
利用UIGestureRecognizer,能轻松识别用户在某个view上面做的一些常见手势
UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能处理具体的手势
// 1. 创建手势识别器对象
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
// 2. 设置手势识别器对象的具体属性
// 连续敲击2次
tap.numberOfTapsRequired = 2;
// 需要2根手指一起敲击
tap.numberOfTouchesRequired = 2;
// 3. 添加手势识别器到对应的view上
[self.iconView addGestureRecognizer:tap];
// 4. 监听手势的触发
[tap addTarget:self action:@selector(tapIconView:)];
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
UIGestureRecognizerStatePossible, // 没有触摸事件发生,所有手势识别的默认状态
UIGestureRecognizerStateBegan, // 一个手势已经开始但尚未改变或者完成时
UIGestureRecognizerStateChanged, // 手势状态改变
UIGestureRecognizerStateEnded, // 手势完成
UIGestureRecognizerStateCancelled, // 手势取消,恢复至Possible状态
UIGestureRecognizerStateFailed, // 手势失败,恢复至Possible状态
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // 识别到手势识别
};
UITapGestureRecognizer
numberOfTapsRequired 点击的次数
numberOfTouchesRequired 需要的手指数
UIPinchGestureRecognizer
scale 相对于屏幕触摸点的比例
velocity 速度
UIPanGestureRecognizer
minimumNumberOfTouches
maximumNumberOfTouches
UISwipeGestureRecognizer
numberOfTouchesRequired
direction 方向
UIRotationGestureRecognizer
rotation 旋转角度
velocity
UILongPressGestureRecognizer
numberOfTapsRequired
numberOfTouchesRequired
minimumPressDuration 按下的最小持续时间
allowableMovement 手指按下后事件响应之前允许手指移动的偏移位
宽度和高度
@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;
CALayer有2个非常重要的属性:position和anchorPoint,他们共同决定View显示在什么位置
position
用来设置CALayer在父层中的位置
以父层的左上角为原点(0, 0)
anchorPoint
称为“定位点”、“锚点”
决定着CALayer身上的哪个点会在position属性所指的位置
以自己的左上角为原点(0, 0)
它的x、y取值范围都是0~1,默认值为(0.5, 0.5)
每一个UIView内部都默认关联着一个CALayer,我们可用称这个Layer为Root Layer(根层)
所有的非Root Layer,也就是手动创建的CALayer对象,都存在着隐式动画
什么是隐式动画?
当对非Root Layer的部分属性进行修改时,默认会自动产生一些动画效果
而这些属性称为Animatable Properties(可动画属性)
列举几个常见的Animatable Properties:
bounds:用于设置CALayer的宽度和高度。修改这个属性会产生缩放动画
backgroundColor:用于设置CALayer的背景色。修改这个属性会产生背景色的渐变动画
position:用于设置CALayer的位置。修改这个属性会产生平移动画
可以通过动画事务(CATransaction)关闭默认的隐式动画效果
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.myview.layer.position = CGPointMake(10, 10);
[CATransaction commit];
Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。另外Core Animation是直接作用在CALayer上的,并非UIView。
<QuartzCore/QuartzCore.h/>
(iOS7及以后不需要)CAAnimation is an abstract animation class. It provides the basic support for the CAMediaTiming and CAAction protocols. To animate Core Animation layers or Scene Kit objects, create instances of the concrete subclasses CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, or CATransition.
CAAnimation是一个抽象的动画类。它为CAMediaTiming和CAAtion协议提供了基础支持。为了使用核心动画,需要创建具体的子类:CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup 或 CATransition.
是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation
属性解析:
CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行
CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。iOS比Mac OS X的转场动画效果少一点
过渡效果
NSURL *url = [NSURL URLWithString:@"tel://10010"];
[[UIApplication sharedApplication] openURL:url];
缺点:电话打完后,不会自动回到原应用,直接停留在通话记录界面
NSURL *url = [NSURL URLWithString:@"telprompt://10010"];
[[UIApplication sharedApplication] openURL:url];
缺点:因为是私有API,所以可能不会被审核通过
if (_webView == nil) {
_webView = [[UIWebView alloc] initWithFrame:CGRectZero]; } [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"tel://10010"]]];
注意:这个webView千万不要添加到界面上来,不然会挡住其他界面
NSURL *url = [NSURL URLWithString:@"sms://10010"];
[[UIApplication sharedApplication] openURL:url];
#import <MessageUI/MessageUI.h>
// 显示发短信的控制器
MFMessageComposeViewController *vc = [[MFMessageComposeViewController alloc] init];
// 设置短信内容
vc.body = @"吃饭了没?";
// 设置收件人列表
vc.recipients = @[@"10010", @"02010010"];
// 设置代理
vc.messageComposeDelegate = self;
// 显示控制器
[self presentViewController:vc animated:YES completion:nil];
// 代理方法,当短信界面关闭的时候调用,发完后会自动回到原应用
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
// 关闭短信界面
[controller dismissViewControllerAnimated:YES completion:nil];
if (result == MessageComposeResultCancelled) {
NSLog(@"取消发送");
} else if (result == MessageComposeResultSent) {
NSLog(@"已经发出");
} else {
NSLog(@"发送失败");
}
}
NSURL *url = [NSURL URLWithString:@"mailto://[email protected]"];
[[UIApplication sharedApplication] openURL:url];
// 不能发邮件
if (![MFMailComposeViewController canSendMail]) return;
MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
// 设置邮件主题
[vc setSubject:@"会议"];
// 设置邮件内容
[vc setMessageBody:@"今天下午开会吧" isHTML:NO];
// 设置收件人列表
[vc setToRecipients:@[@"[email protected]"]];
// 设置抄送人列表
[vc setCcRecipients:@[@"[email protected]"]];
// 设置密送人列表
[vc setBccRecipients:@[@"[email protected]"]];
// 添加附件(一张图片)
UIImage *image = [UIImage imageNamed:@"lufy.jpeg"];
NSData *data = UIImageJPEGRepresentation(image, 0.5);
[vc addAttachmentData:data mimeType:@"image/jepg" fileName:@"lufy.jpeg"];
// 设置代理
vc.mailComposeDelegate = self;
// 显示控制器
[self presentViewController:vc animated:YES completion:nil];
// 邮件发送后的代理方法回调,发完后会自动回到原应用
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
// 关闭邮件界面
[controller dismissViewControllerAnimated:YES completion:nil];
if (result == MFMailComposeResultCancelled) {
NSLog(@"取消发送");
} else if (result == MFMailComposeResultSent) {
NSLog(@"已经发出");
} else {
NSLog(@"发送失败");
}
}
NSURL *url = [NSURL URLWithString:@”http://www.baidu.com"];
[[UIApplication sharedApplication] openURL:url];
有时候,需要在本应用中打开其他应用,比如从A应用中跳转到B应用
NSURL *url = [NSURL URLWithString:applicationURL];
[[UIApplication sharedApplication] openURL:url];
NSString *appid = @"444934666";
NSString *str = [NSString stringWithFormat:@"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%@", appid];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
NSString *str = [NSString stringWithFormat:@"itms-apps://itunes.apple.com/cn/app/id%@?mt=8", appid];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
block循环应用会导致控制器无法释放,解决方法是创建一个weak的引用在block里面使用
__weak typeof(self) unsafeSelf = self;
__unsafe_unretained NJShareViewController *unsafeSelf = self;
__weak NJShareViewController *unsafeSelf = self;
__unsafe_unretained相当于__weak,两者只有一点区别:
__weak 当对象释放之后会自动设置为nil, 而__unsafe_unretained不会,还是会指向一个内存单元