一個動態產生的Popover
實作如下
1. 開啓一個專案
2. 在storyboard加上一個button
3. 在mainViewController.h加上一個popover的變數
#import <UIKit/UIKit.h>
@interface mainViewController : UIViewController
{
UIPopoverController *popover;
}
@end
4. 在mainViewController.m加上程式碼
#import "mainViewController.h"
@interface mainViewController ()
@end
@implementation mainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startPopover:(id)sender {
UIView *anchor = sender;
UIViewController *showView1 = [[UIViewController alloc] init];
showView1.view.backgroundColor = [UIColor redColor];
UILabel *testLabel =[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 150)];
testLabel.backgroundColor = [UIColor clearColor];
testLabel.textColor = [UIColor blackColor];
testLabel.text = @"Hello";
[showView1.view addSubview:testLabel ];
popover = [[UIPopoverController alloc]
initWithContentViewController:showView1];
[popover setPopoverContentSize:CGSizeMake(300, 300)];
[popover presentPopoverFromRect:anchor.frame inView:anchor.superview permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
@end
5. 執行結果,因為popover不能設定x方向的位置,所以x位置為0。
2012年12月22日 星期六
2012年12月21日 星期五
NSRect V.S. CGRect
1. NSRect is used in Cocoa // #import <Cocoa/Cocoa.h>
2. CGRect is used in Core Graphics and Core Image // #import <UIKit/UIKit.h>
在此我們看到官方文件註明,因此兩個幾乎是一樣的,只是在不同的OS使用而已。
// NSValue/+valueWithRect:(NSRect)rect is available on Mac OS X // NSValue/+valueWithCGRect:(CGRect)rect is available on iOS
參考
http://developer.apple.com/library/ios/#qa/qa1620/_index.html#//apple_ref/doc/uid/DTS40008060
其他官方文件
1. https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaDrawingGuide/QuartzOpenGL/QuartzOpenGL.html#//apple_ref/doc/uid/TP40003290-CH211-BAADHIAF
2. https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_DataTypes/Reference/reference.html
Cocoa defines several fundamental data types for manipulating geometric information in the drawing environment. These data types include
NSPoint, NSRect, and NSSize.
You use these data types to specify lines, rectangles, and width and
height information for the shapes you want to draw. Everything from
lines and rectangles to circles, arcs, and Bezier curves can be
specified using one or more of these data structures.The coordinate values for point, rectangle, and size data types are all specified using floating-point values. Floating-point values allow for much finer precision as the resolution of the underlying destination device goes up.
The
NSPoint, NSRect, and NSSize data types have equivalents in the Quartz environment: CGPoint, CGRect, and CGSize.
Because the layout of the Cocoa and Quartz types are identical, you can
convert between two types by casting from one type to its counterpart. NSPoint
Represents a point in a Cartesian coordinate system.
typedef struct _NSPoint {
CGFloat x;
CGFloat y;
} NSPoint;
NSSize
Represents a two-dimensional size.
typedef struct _NSSize {
CGFloat width;
CGFloat height;
} NSSize;
NSRect
Represents a rectangle.
typedef struct _NSRect {
NSPoint origin;
NSSize size;
} NSRect;
NSRECT example
- (id)initWithFrame:(NSRect)frame
{
self = [super
initWithFrame:frame];
if (self) {
// Initialization code here.
}
return
self;
}
- (void)drawRect:(NSRect)dirtyRect
{
NSLog(@"have draw");
if (flag==0) {
[[NSColorredColor]
set]; //设置颜色
NSRectFill(dirtyRect);
}else
{
[[NSColoryellowColor]
set]; //设置颜色
NSRectFill(dirtyRect);
flag=0;
}
//填充rect区域.
}
CGRECT Example
- (id)initWithFrame:(CGRect)frame
{
[self setup]; // get initialized if someone uses alloc/initWithFrame: to create us
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGPoint midPoint; // center of our bounds in our coordinate system
midPoint.x = self.bounds.origin.x + self.bounds.size.width/2;
midPoint.y = self.bounds.origin.y + self.bounds.size.height/2;
CGFloat size = self.bounds.size.width / 2;
if (self.bounds.size.height < self.bounds.size.width) size = self.bounds.size.height / 2;
size *= self.scale; // scale is percentage of full view size
CGContextSetLineWidth(context, 5.0);
[[UIColor blueColor] setStroke];
[self drawCircleAtPoint:midPoint withRadius:size inContext:context]; // head
}
{
self = [super initWithFrame:frame];
if (self) {[self setup]; // get initialized if someone uses alloc/initWithFrame: to create us
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGPoint midPoint; // center of our bounds in our coordinate system
midPoint.x = self.bounds.origin.x + self.bounds.size.width/2;
midPoint.y = self.bounds.origin.y + self.bounds.size.height/2;
CGFloat size = self.bounds.size.width / 2;
if (self.bounds.size.height < self.bounds.size.width) size = self.bounds.size.height / 2;
size *= self.scale; // scale is percentage of full view size
CGContextSetLineWidth(context, 5.0);
[[UIColor blueColor] setStroke];
[self drawCircleAtPoint:midPoint withRadius:size inContext:context]; // head
}
其他的轉換例
refer to http://cocoadev.com/wiki/NSRectToCGRectFrom Mac OS X 10.5 (Leopard) onwards, Apple provide an inline function to do this:
CGRect NSRectToCGRect(NSRect nsrect);
as well as the matching function:
NSRect NSRectFromCGRect(CGRect cgrect);
2012年12月20日 星期四
Core Animation的基本使用(二十一)
CAKeyframeAnimation
先大致瞭解一下动画类和定时
core animation提供了一组富于表现力的动画类,你在程序中可以使用他们:
1. CABasicAnimation 为层属性提供了简单的插值。(Core Animation的基本使用(五))
2. CAKeyframeAnimation 提供了关键帧动画支持。你指定需要做动画的层属性的键路径,由一组值组成的数组代表动画每个阶段的值,同样可以用数组指定关键帧时间和定时含税。在动画运行过程中,每个值依次使用指定的插值设置。
3.CATransition提供了一个过度效果,能够影响整个层的内容。在动画进行时,它淡入淡出,推入和暴露层的内容。现有的过渡效果可以被扩展,你可以提供自定义的Core图像过滤器。 (Core Animation的基本使用(ㄧ))
4. CAAnimationGroup允许一些动画对象的数组组合在一起同时运行。
任何动画要表现出运动或者变化,至少需要两个不同的关键状态,而中间的状态的变化可以通过插值计算完成,从而形成补间动画,表示关键状态的帧叫做关键帧.
CABasicAnimation 其实可以看作一种特殊的关键帧动画,只有头尾两个关帧.
CAKeyframeAnimation则可以支持任意多个关键帧,关键帧有两种方式来指定,
1. 使用path或者使用values,path是一个CGPathRef的值,且path只能对CALayer的 anchorPoint 和 position 属性起作用,且设置了path之后values就不再起效了.
2. values则更加灵活. keyTimes这个可选参数可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每 一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的.
other. 还可以通过设置可选参数timingFunctions(CAKeyframeAnimation中timingFunction是无效的)
为关键帧之间的过渡设置timingFunction,如果values有n个元素,那么timingFunctions则应该有n-1个.但很多时候并不需要 timingFunctions,因为已经设置了够多的关键帧了,比如没1/60秒就设置了一个关键帧,那么帧率将达到60FPS,完全不需要相邻两帧的 过渡效果(当然也有可能某两帧 值相距较大,可以使用均匀变化或者增加帧率,比如每0.01秒设置一个关键帧).
先大致瞭解一下动画类和定时
core animation提供了一组富于表现力的动画类,你在程序中可以使用他们:
1. CABasicAnimation 为层属性提供了简单的插值。(Core Animation的基本使用(五))
2. CAKeyframeAnimation 提供了关键帧动画支持。你指定需要做动画的层属性的键路径,由一组值组成的数组代表动画每个阶段的值,同样可以用数组指定关键帧时间和定时含税。在动画运行过程中,每个值依次使用指定的插值设置。
3.CATransition提供了一个过度效果,能够影响整个层的内容。在动画进行时,它淡入淡出,推入和暴露层的内容。现有的过渡效果可以被扩展,你可以提供自定义的Core图像过滤器。 (Core Animation的基本使用(ㄧ))
4. CAAnimationGroup允许一些动画对象的数组组合在一起同时运行。
任何动画要表现出运动或者变化,至少需要两个不同的关键状态,而中间的状态的变化可以通过插值计算完成,从而形成补间动画,表示关键状态的帧叫做关键帧.
CABasicAnimation 其实可以看作一种特殊的关键帧动画,只有头尾两个关帧.
CAKeyframeAnimation则可以支持任意多个关键帧,关键帧有两种方式来指定,
1. 使用path或者使用values,path是一个CGPathRef的值,且path只能对CALayer的 anchorPoint 和 position 属性起作用,且设置了path之后values就不再起效了.
2. values则更加灵活. keyTimes这个可选参数可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每 一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的.
other. 还可以通过设置可选参数timingFunctions(CAKeyframeAnimation中timingFunction是无效的)
为关键帧之间的过渡设置timingFunction,如果values有n个元素,那么timingFunctions则应该有n-1个.但很多时候并不需要 timingFunctions,因为已经设置了够多的关键帧了,比如没1/60秒就设置了一个关键帧,那么帧率将达到60FPS,完全不需要相邻两帧的 过渡效果(当然也有可能某两帧 值相距较大,可以使用均匀变化或者增加帧率,比如每0.01秒设置一个关键帧).
在关键帧动画中还有一个非常重要的参数,那便是calculationMode,计算模式.其主要针对的是每一帧的内容为一个座标点的情况,也就是对
anchorPoint 和 position
进行的动画.当在平面座标系中有多个离散的点的时候,可以是离散的,也可以直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算.
calculationMode目前提供如下几种模式 kCAAnimationLinear
kCAAnimationDiscrete
kCAAnimationPaced
kCAAnimationCubic
kCAAnimationCubicPaced
kCAAnimationDiscrete
kCAAnimationPaced
kCAAnimationCubic
kCAAnimationCubicPaced
kCAAnimationLinear calculationMode的默认值,表示当关键帧为座标点的时候,关键帧之间直接直线相连进行插值计算;
kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示;
kCAAnimationPaced 使得动画均匀进行,而不是按keyTimes设置的或者按关键帧平分时间,此时keyTimes和timingFunctions无效;
kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,对于曲线的形状还可以通过tensionValues,continuityValues,biasValues来进行调整自定义,这里的数学原理是Kochanek–Bartels spline,这里的主要目的是使得运行的轨迹变得圆滑;
kCAAnimationCubicPaced 看这个名字就知道和kCAAnimationCubic有一定联系,其实就是在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的。
此處的運用還頗為複雜,待有需要再來研究。
官方文件
https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CAKeyframeAnimation_class/Introduction/Introduction.html#//apple_ref/occ/cl/CAKeyframeAnimation
先留一段example,待有空再來研究細節的使用。
實作一個基本例來測試僅就path的地方簡單的測試一下。
1. 開啓一個專案
2. 在Storyboard加上一個Button
3. 在mainViewController.h加上instance變數
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
@interface mainViewController : UIViewController
{
CALayer *pinLayer;
CGMutablePathRef starPath;
}
@end
4. 在mainViewController.m加上程式碼
#import "mainViewController.h"
@interface mainViewController ()
@end
@implementation mainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self createPath];
pinLayer = [CALayer layer];
[pinLayer setBounds:CGRectMake(0.0, 0.0, 10.0, 10.0)];
// Set the corner radius to half the size of the
// bounds to simulate a circle.
[pinLayer setCornerRadius:5.0];
[pinLayer setBackgroundColor:[[UIColor redColor] CGColor]];
[pinLayer setPosition:CGPointMake(160.0, 260.0)];
self.view.layer.backgroundColor = [[UIColor blueColor] CGColor];
[self.view.layer insertSublayer:pinLayer atIndex:0];
}
- (void)createPath;
{
CGMutablePathRef starPath = CGPathCreateMutable();
CGPathMoveToPoint(starPath,NULL,160.0, 260.0);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startAnimation:(id)sender {
if( starPath )
{
// Reset our starPath CGMutablePathRef if
// it has already run before
CFRelease(starPath);
[self createPath];
}
// Define a path for the star shape.
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL,160.0, 380.0);
CGPathAddLineToPoint(path, NULL, 101.0, 179.0);
CGPathAddLineToPoint(path, NULL, 255.0, 290.0);
CGPathAddLineToPoint(path, NULL, 64.0, 290.0);
CGPathAddLineToPoint(path, NULL, 218.0, 179.0);
CGPathCloseSubpath(path);
CAKeyframeAnimation *animation =
[CAKeyframeAnimation
animationWithKeyPath:@"position"];
[animation setDuration:10.0f];
[animation setDelegate:self];
// Set the animation's path
[animation setPath:path];
[pinLayer addAnimation:animation forKey:@"position"];
}
@end
5.執行結果,紅點會以五星圖的位置移動。
kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示;
kCAAnimationPaced 使得动画均匀进行,而不是按keyTimes设置的或者按关键帧平分时间,此时keyTimes和timingFunctions无效;
kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,对于曲线的形状还可以通过tensionValues,continuityValues,biasValues来进行调整自定义,这里的数学原理是Kochanek–Bartels spline,这里的主要目的是使得运行的轨迹变得圆滑;
kCAAnimationCubicPaced 看这个名字就知道和kCAAnimationCubic有一定联系,其实就是在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的。
此處的運用還頗為複雜,待有需要再來研究。
官方文件
https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CAKeyframeAnimation_class/Introduction/Introduction.html#//apple_ref/occ/cl/CAKeyframeAnimation
先留一段example,待有空再來研究細節的使用。
CALayer *layer = imageView.layer;
CAKeyframeAnimation *animation;
animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.duration = 8;
animation.cumulative = NO;
animation.repeatCount = 0;
animation.values = [NSArray arrayWithObjects: // i.e., Rotation values for the 3 keyframes, in RADIANS
[NSNumber numberWithFloat:[self dialStartPosition] * M_PI],
[NSNumber numberWithFloat:2.5 * M_PI],
[NSNumber numberWithFloat:[self dialEndPosition] * M_PI], nil];
animation.keyTimes = [NSArray arrayWithObjects: // Relative timing values for the 3 keyframes
[NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:.055],
[NSNumber numberWithFloat:1], nil];
animation.timingFunctions = [NSArray arrayWithObjects:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
// from keyframe 1 to keyframe 2
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], nil]; // from keyframe 2 to keyframe 3
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
[layer addAnimation:animation forKey:nil];
實作一個基本例來測試僅就path的地方簡單的測試一下。
1. 開啓一個專案
2. 在Storyboard加上一個Button
3. 在mainViewController.h加上instance變數
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
@interface mainViewController : UIViewController
{
CALayer *pinLayer;
CGMutablePathRef starPath;
}
@end
4. 在mainViewController.m加上程式碼
#import "mainViewController.h"
@interface mainViewController ()
@end
@implementation mainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self createPath];
pinLayer = [CALayer layer];
[pinLayer setBounds:CGRectMake(0.0, 0.0, 10.0, 10.0)];
// Set the corner radius to half the size of the
// bounds to simulate a circle.
[pinLayer setCornerRadius:5.0];
[pinLayer setBackgroundColor:[[UIColor redColor] CGColor]];
[pinLayer setPosition:CGPointMake(160.0, 260.0)];
self.view.layer.backgroundColor = [[UIColor blueColor] CGColor];
[self.view.layer insertSublayer:pinLayer atIndex:0];
}
- (void)createPath;
{
CGMutablePathRef starPath = CGPathCreateMutable();
CGPathMoveToPoint(starPath,NULL,160.0, 260.0);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startAnimation:(id)sender {
if( starPath )
{
// Reset our starPath CGMutablePathRef if
// it has already run before
CFRelease(starPath);
[self createPath];
}
// Define a path for the star shape.
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL,160.0, 380.0);
CGPathAddLineToPoint(path, NULL, 101.0, 179.0);
CGPathAddLineToPoint(path, NULL, 255.0, 290.0);
CGPathAddLineToPoint(path, NULL, 64.0, 290.0);
CGPathAddLineToPoint(path, NULL, 218.0, 179.0);
CGPathCloseSubpath(path);
CAKeyframeAnimation *animation =
[CAKeyframeAnimation
animationWithKeyPath:@"position"];
[animation setDuration:10.0f];
[animation setDelegate:self];
// Set the animation's path
[animation setPath:path];
[pinLayer addAnimation:animation forKey:@"position"];
}
@end
5.執行結果,紅點會以五星圖的位置移動。
2012年12月19日 星期三
Core Animation的基本使用(二十)
Autoresizing Mask
在CALayer Class Guide有描述此功能,但實作時發現沒有相關的property,無法使用,查看了網路資料,例子好像都是2009以前的,因此懷疑已被Apple移除,現在只從在UIView相關的Class還有此功能。
kCALayerHeightSizable
如果被设置,层的高度随超层的高度改变。否则,层的高度不随超层的高度改变。
kCALayerWidthSizable
如果被设置,层的宽度随超层的宽度改变。否则,层的宽度不随超层的宽度改变。
kCALayerMinXMargin
如果被设置,层的左边缘将随超层的宽度重新定位。否则,层的左边缘相对于超层的边缘保持相同的位置。
kCALayerMaxXMargin
如果被设置,层的右边缘将随超层的宽度重新定位。否则,层的右边缘相对于超层的边缘保持相同的位置。
kCALayerMaxYMargin
如果被设置,层的上边缘将随超层的宽度重新定位。否则,层的上边缘相对于超层的边缘保持相同的位置。
kCALayerMinYMargin
如果被设置,层的下边缘将随超层的宽度重新定位。否则,层的下边缘相对于超层的边缘保持相同的位置。
举例来说,为了让层保留在其超层的左下角,可使用kCALayerMaxXMargin | kCALayerMaxYMargin掩码。当在同轴方向上有多个活动掩码时,改变值将在它们之中均匀的分布,图1提供了这些常量值位置的图形表示。
图1 层的autoresizing mask常量

当这些常量之一被省略时,层的布局在那个方面被固定。如果一个常量出现在掩码中,那层的布局在那个方面是活动的。
层的子类可以覆盖resizeSublayersWithOldSize: 和 resizeWithOldSuperlayerSize: 方法,来自定义层的autoresizing行为。只要层的bounds属性被修改,resizeSublayersWithOldSize:将被自定调 用,并发送一个resizeWithOldSuperlayerSize:消息给每一个子层。每一个子层将旧的bounds size和新的size做比较,并根据autoresizing mask调整其位置和尺寸。
在CALayer Class Guide有描述此功能,但實作時發現沒有相關的property,無法使用,查看了網路資料,例子好像都是2009以前的,因此懷疑已被Apple移除,現在只從在UIView相關的Class還有此功能。
kCALayerHeightSizable
如果被设置,层的高度随超层的高度改变。否则,层的高度不随超层的高度改变。
kCALayerWidthSizable
如果被设置,层的宽度随超层的宽度改变。否则,层的宽度不随超层的宽度改变。
kCALayerMinXMargin
如果被设置,层的左边缘将随超层的宽度重新定位。否则,层的左边缘相对于超层的边缘保持相同的位置。
kCALayerMaxXMargin
如果被设置,层的右边缘将随超层的宽度重新定位。否则,层的右边缘相对于超层的边缘保持相同的位置。
kCALayerMaxYMargin
如果被设置,层的上边缘将随超层的宽度重新定位。否则,层的上边缘相对于超层的边缘保持相同的位置。
kCALayerMinYMargin
如果被设置,层的下边缘将随超层的宽度重新定位。否则,层的下边缘相对于超层的边缘保持相同的位置。
举例来说,为了让层保留在其超层的左下角,可使用kCALayerMaxXMargin | kCALayerMaxYMargin掩码。当在同轴方向上有多个活动掩码时,改变值将在它们之中均匀的分布,图1提供了这些常量值位置的图形表示。
图1 层的autoresizing mask常量

当这些常量之一被省略时,层的布局在那个方面被固定。如果一个常量出现在掩码中,那层的布局在那个方面是活动的。
层的子类可以覆盖resizeSublayersWithOldSize: 和 resizeWithOldSuperlayerSize: 方法,来自定义层的autoresizing行为。只要层的bounds属性被修改,resizeSublayersWithOldSize:将被自定调 用,并发送一个resizeWithOldSuperlayerSize:消息给每一个子层。每一个子层将旧的bounds size和新的size做比较,并根据autoresizing mask调整其位置和尺寸。
2012年12月18日 星期二
Core Animation的基本使用(十九)
CAAnimationGroup允许将一组动画放在一个数组里面,然后同时执行。
官方文件
https://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CAAnimationGroup_class/Introduction/Introduction.html#//apple_ref/occ/cl/CAAnimationGroup
直接用實作來看看執行結果
1. 沿用前一個專案,然後加上一個Button。
2. 在mainViewController.m加上程式碼
- (IBAction)startAnimationGroup:(id)sender {
CGRect oldRect = CGRectMake(0.0, 0.0, 100.0, 100.0);
CGRect newRect = CGRectMake(0.0, 0.0, 300.0, 300.0);
CABasicAnimation *boundsAnimation =[CABasicAnimation animationWithKeyPath:@"bounds"];
[boundsAnimation setFromValue:[NSValue valueWithCGRect:oldRect]];
[boundsAnimation setToValue:[NSValue valueWithCGRect:newRect]];
[boundsAnimation setDuration:15.0f];
[boundsAnimation setBeginTime:0.0f];
CABasicAnimation *positionAnimation = [CABasicAnimation
animationWithKeyPath:@"postition"];
[positionAnimation setFromValue:[NSValue valueWithCGPoint:mainLayer.position]];
[positionAnimation setToValue:[NSValue valueWithCGPoint:CGPointMake(0,0)]];
[positionAnimation setDuration:15.0f];
[positionAnimation setBeginTime:5.0f];
CABasicAnimation *borderWidthAnimation = [CABasicAnimation animationWithKeyPath:@"borderWidth"];
[borderWidthAnimation setFromValue:[NSNumber numberWithFloat:5.0f]];
[borderWidthAnimation setToValue:[NSNumber numberWithFloat:30.0f]];
[borderWidthAnimation setDuration:15.0f];
[borderWidthAnimation setBeginTime:10.0f];
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:15];
[group setAnimations:
[NSArray arrayWithObjects:boundsAnimation,
positionAnimation,
borderWidthAnimation, nil]];
[mainLayer addAnimation:group forKey:nil];
}
3. 執行結果,從原始的狀態,然後變成一個小的,再開始漸漸變大。
官方文件
https://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CAAnimationGroup_class/Introduction/Introduction.html#//apple_ref/occ/cl/CAAnimationGroup
直接用實作來看看執行結果
1. 沿用前一個專案,然後加上一個Button。
2. 在mainViewController.m加上程式碼
- (IBAction)startAnimationGroup:(id)sender {
CGRect oldRect = CGRectMake(0.0, 0.0, 100.0, 100.0);
CGRect newRect = CGRectMake(0.0, 0.0, 300.0, 300.0);
CABasicAnimation *boundsAnimation =[CABasicAnimation animationWithKeyPath:@"bounds"];
[boundsAnimation setFromValue:[NSValue valueWithCGRect:oldRect]];
[boundsAnimation setToValue:[NSValue valueWithCGRect:newRect]];
[boundsAnimation setDuration:15.0f];
[boundsAnimation setBeginTime:0.0f];
CABasicAnimation *positionAnimation = [CABasicAnimation
animationWithKeyPath:@"postition"];
[positionAnimation setFromValue:[NSValue valueWithCGPoint:mainLayer.position]];
[positionAnimation setToValue:[NSValue valueWithCGPoint:CGPointMake(0,0)]];
[positionAnimation setDuration:15.0f];
[positionAnimation setBeginTime:5.0f];
CABasicAnimation *borderWidthAnimation = [CABasicAnimation animationWithKeyPath:@"borderWidth"];
[borderWidthAnimation setFromValue:[NSNumber numberWithFloat:5.0f]];
[borderWidthAnimation setToValue:[NSNumber numberWithFloat:30.0f]];
[borderWidthAnimation setDuration:15.0f];
[borderWidthAnimation setBeginTime:10.0f];
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:15];
[group setAnimations:
[NSArray arrayWithObjects:boundsAnimation,
positionAnimation,
borderWidthAnimation, nil]];
[mainLayer addAnimation:group forKey:nil];
}
3. 執行結果,從原始的狀態,然後變成一個小的,再開始漸漸變大。
2012年12月17日 星期一
Core Animation的基本使用(十八)
CALayer的属性contentsGravity允许你在图层的边界内容修改图层的contents图片的位置或者伸缩值。
使用contentsGravity位置常量,你可以指定图片位于图层任何一个边界,比如位于图层的角落,或者图层边界的中心。然而当你使用位置常量的时候,contentsCenter属性会被忽略。表1列举了位置常量和他们相应的位置。
表1 层的contentsGravity属性的定位常量
定位常量
描述
kCAGravityTopLeft
将内容图像定位到层的左上角。
kCAGravityTop
将内容图像定位到层的上边缘的水平居中位置。
kCAGravityTopRight
将内容图像定位到层的右上角。
kCAGravityLeft
将内容图像定位到层的左边缘的垂直居中位置。
kCAGravityCenter
将内容图像定位到层的中心。
kCAGravityRight
将内容图像定位到层的右边缘的垂直居中位置。
kCAGravityBottomLeft
将内容图像定位到层的左下角。
kCAGravityBottom
将内容图像定位到层的下边缘的水平居中位置。
kCAGravityBottomRight
将内容图像定位到层的右下角。
“层坐标系”标明了所支持的内容位置和相应的常量。
图1 层的contentsGravity属性的定位常量

通过设置contentsGravity属性为其他一个常量(如表2所示)。图层的内容图片可以被向上或者向下拉伸, 仅当使用其他任何一个调整大小的常量的时候,contentsCenter属性才会对内容图片起作用。另外實作上發現,使用上Top的位置在下面,而Button的位置在上面,不知有什麼問題。
表2 层的contentsGravity的缩放常量
缩放常量
描述
kCAGravityResize
缩放内容图像以填充层边界,可能无视内容的自然比例,这是默认值。
kCAGravityResizeAspect
缩放内容图像使其竟可能占满层边界显示,但他仍然保持自然比例。
kCAGravityResizeAspectFill
缩放内容图片使其占满层显示,但仍保持自然比例。这可能导致内容超越到层边界之外。
“变换层的几何特性”表明了如何使用resizing模式,让一个正方形图像在一个矩形层内调整缩放比例。
图2 层的contentsGravity属性的缩放常量

如果沒有設定,則Default值為kCAGravityResize,讓內容自動填滿Layer。
以下是實作的測試例
1. 沿用前一篇的例子來作修改,加上十二個Button,分別代表十二個屬性,並且選用一個較為適中的圖檔大約300x300pixels,這樣才好看出結果。
2. 直接在mainViewController.m加上所需要的程式碼。
#import "mainViewController.h"
@interface mainViewController ()
@end
@implementation mainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Create the tach's background layer
mainLayer = [CALayer layer];
mainLayer.bounds = CGRectMake(0, 0, 800, 500);
mainLayer.position = CGPointMake(500, 500);
mainLayer.contents = (id)[UIImage imageNamed:@"speed.png"].CGImage;
mainLayer.backgroundColor = [[UIColor redColor] CGColor];
maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(100, 100, 200, 200);
UIColor *c2 = [UIColor blueColor];
maskLayer.name = @"maskLayer";
maskLayer.cornerRadius = 100.0f; //變成圓形的
[maskLayer setBackgroundColor:(c2.CGColor)];
[self.view.layer addSublayer:mainLayer];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startMask:(id)sender {
UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
[self.view addGestureRecognizer:panGesture];
[mainLayer setMask:maskLayer];
}
-(void)handleGesture:(UIGestureRecognizer*)gestureRecognizer
{
if([gestureRecognizer isMemberOfClass:[UIPanGestureRecognizer class]])
{
UIView* piece = [gestureRecognizer view];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ||
[gestureRecognizer state] == UIGestureRecognizerStateChanged)
{
UIPanGestureRecognizer* panGestureRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
CGPoint translation = [panGestureRecognizer translationInView:self.view];
CGFloat X, Y;
X = maskLayer.position.x+translation.x;
Y = maskLayer.position.y + translation.y;
if (X >600)
X = 600;
if (X<100)
X=100;
if (Y > 600)
Y =600;
if (Y<100)
Y=100;
maskLayer.position = CGPointMake(X, Y);
}
}
}
- (IBAction)enablekCAGravityTopLeft:(id)sender {
mainLayer.contentsGravity = kCAGravityTopLeft;
}
- (IBAction)enablekCAGravityTop:(id)sender {
mainLayer.contentsGravity = kCAGravityTop;
}
- (IBAction)enablekCAGravityTopRight:(id)sender {
mainLayer.contentsGravity = kCAGravityTopRight;
}
- (IBAction)enablekCAGravityLeft:(id)sender {
mainLayer.contentsGravity = kCAGravityLeft;
}
- (IBAction)enablekCAGravityCenter:(id)sender {
mainLayer.contentsGravity = kCAGravityCenter;
}
- (IBAction)enablekCAGravityRight:(id)sender {
mainLayer.contentsGravity = kCAGravityRight;
}
- (IBAction)enablekCAGravityBottomLeft:(id)sender{
mainLayer.contentsGravity = kCAGravityBottomLeft;
}
- (IBAction)enablekCAGravityBottom:(id)sender {
mainLayer.contentsGravity = kCAGravityBottom;
}
- (IBAction)enablekCAGravityBottomRight:(id)sender{
mainLayer.contentsGravity = kCAGravityBottomRight;
}
- (IBAction)enablekCAGravityResize:(id)sender {
mainLayer.contentsGravity = kCAGravityResize;
}
- (IBAction)enablekCAGravityResizeAspectFill:(id)sender {
mainLayer.contentsGravity = kCAGravityResizeAspectFill;
}
- (IBAction)enablekCAGravityResizeAspect:(id)sender {
mainLayer.contentsGravity = kCAGravityResizeAspect;
}
@end
3. 執行結果,依照表格的順序執行,分別截圖。第一張是剛執行App的原始狀態。
使用contentsGravity位置常量,你可以指定图片位于图层任何一个边界,比如位于图层的角落,或者图层边界的中心。然而当你使用位置常量的时候,contentsCenter属性会被忽略。表1列举了位置常量和他们相应的位置。
表1 层的contentsGravity属性的定位常量
定位常量
描述
kCAGravityTopLeft
将内容图像定位到层的左上角。
kCAGravityTop
将内容图像定位到层的上边缘的水平居中位置。
kCAGravityTopRight
将内容图像定位到层的右上角。
kCAGravityLeft
将内容图像定位到层的左边缘的垂直居中位置。
kCAGravityCenter
将内容图像定位到层的中心。
kCAGravityRight
将内容图像定位到层的右边缘的垂直居中位置。
kCAGravityBottomLeft
将内容图像定位到层的左下角。
kCAGravityBottom
将内容图像定位到层的下边缘的水平居中位置。
kCAGravityBottomRight
将内容图像定位到层的右下角。
“层坐标系”标明了所支持的内容位置和相应的常量。
图1 层的contentsGravity属性的定位常量

表2 层的contentsGravity的缩放常量
缩放常量
描述
kCAGravityResize
缩放内容图像以填充层边界,可能无视内容的自然比例,这是默认值。
kCAGravityResizeAspect
缩放内容图像使其竟可能占满层边界显示,但他仍然保持自然比例。
kCAGravityResizeAspectFill
缩放内容图片使其占满层显示,但仍保持自然比例。这可能导致内容超越到层边界之外。
“变换层的几何特性”表明了如何使用resizing模式,让一个正方形图像在一个矩形层内调整缩放比例。
图2 层的contentsGravity属性的缩放常量

如果沒有設定,則Default值為kCAGravityResize,讓內容自動填滿Layer。
以下是實作的測試例
1. 沿用前一篇的例子來作修改,加上十二個Button,分別代表十二個屬性,並且選用一個較為適中的圖檔大約300x300pixels,這樣才好看出結果。
2. 直接在mainViewController.m加上所需要的程式碼。
#import "mainViewController.h"
@interface mainViewController ()
@end
@implementation mainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Create the tach's background layer
mainLayer = [CALayer layer];
mainLayer.bounds = CGRectMake(0, 0, 800, 500);
mainLayer.position = CGPointMake(500, 500);
mainLayer.contents = (id)[UIImage imageNamed:@"speed.png"].CGImage;
mainLayer.backgroundColor = [[UIColor redColor] CGColor];
maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(100, 100, 200, 200);
UIColor *c2 = [UIColor blueColor];
maskLayer.name = @"maskLayer";
maskLayer.cornerRadius = 100.0f; //變成圓形的
[maskLayer setBackgroundColor:(c2.CGColor)];
[self.view.layer addSublayer:mainLayer];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startMask:(id)sender {
UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
[self.view addGestureRecognizer:panGesture];
[mainLayer setMask:maskLayer];
}
-(void)handleGesture:(UIGestureRecognizer*)gestureRecognizer
{
if([gestureRecognizer isMemberOfClass:[UIPanGestureRecognizer class]])
{
UIView* piece = [gestureRecognizer view];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ||
[gestureRecognizer state] == UIGestureRecognizerStateChanged)
{
UIPanGestureRecognizer* panGestureRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
CGPoint translation = [panGestureRecognizer translationInView:self.view];
CGFloat X, Y;
X = maskLayer.position.x+translation.x;
Y = maskLayer.position.y + translation.y;
if (X >600)
X = 600;
if (X<100)
X=100;
if (Y > 600)
Y =600;
if (Y<100)
Y=100;
maskLayer.position = CGPointMake(X, Y);
}
}
}
- (IBAction)enablekCAGravityTopLeft:(id)sender {
mainLayer.contentsGravity = kCAGravityTopLeft;
}
- (IBAction)enablekCAGravityTop:(id)sender {
mainLayer.contentsGravity = kCAGravityTop;
}
- (IBAction)enablekCAGravityTopRight:(id)sender {
mainLayer.contentsGravity = kCAGravityTopRight;
}
- (IBAction)enablekCAGravityLeft:(id)sender {
mainLayer.contentsGravity = kCAGravityLeft;
}
- (IBAction)enablekCAGravityCenter:(id)sender {
mainLayer.contentsGravity = kCAGravityCenter;
}
- (IBAction)enablekCAGravityRight:(id)sender {
mainLayer.contentsGravity = kCAGravityRight;
}
- (IBAction)enablekCAGravityBottomLeft:(id)sender{
mainLayer.contentsGravity = kCAGravityBottomLeft;
}
- (IBAction)enablekCAGravityBottom:(id)sender {
mainLayer.contentsGravity = kCAGravityBottom;
}
- (IBAction)enablekCAGravityBottomRight:(id)sender{
mainLayer.contentsGravity = kCAGravityBottomRight;
}
- (IBAction)enablekCAGravityResize:(id)sender {
mainLayer.contentsGravity = kCAGravityResize;
}
- (IBAction)enablekCAGravityResizeAspectFill:(id)sender {
mainLayer.contentsGravity = kCAGravityResizeAspectFill;
}
- (IBAction)enablekCAGravityResizeAspect:(id)sender {
mainLayer.contentsGravity = kCAGravityResizeAspect;
}
@end
3. 執行結果,依照表格的順序執行,分別截圖。第一張是剛執行App的原始狀態。
2012年12月16日 星期日
Core Animation的基本使用(十七)
layer的mask效果
setmask提供了類似聚焦的功能,當我們將作為mask的maskLayer放在顯示用的displayLayer上的時候,displayLayer將只會顯示maskLayer的大小範圍的可視面積,此時displayLayer的其它面積都將看不見,如此就表現出了類似聚焦(探照燈)的功能。
另外還有一個附屬功能
当cocoa视图的子视图位于层边界之外时,这些视图将被父视图剪切。层去掉了这个限制,允许子层被完整的显示,而无视其在父层中的位置。
层的masksToBounds属性决定子层是否被父层所剪切。masksToBounds属性的默认值是NO,这防止了子层被父层剪切。图2显示了设置layerA的masksToBounds,以及这如何影响到layerB和layerC的显示。
masksToBounds属性的取值

以下寫了一個實作來表現,使用一個手指移動來帶動mask,製造聚焦(探照燈)的效果。此例子不包含masksToBounds,因為已經在Core Animation的基本使用(二)時作驗證過了。
1.開啓一個新的專案
2. 在storyboard加上一個Button,並且在專案上加入一個圖檔
3. 在mainViewController.h加入兩個Layer變數
#import <UIKit/UIKit.h>#import <QuartzCore/QuartzCore.h>
@interface mainViewController : UIViewController
{
CALayer *mainLayer;
CALayer *maskLayer;
}
@end
4.在mainViewController.m加入程式碼
#import "mainViewController.h"@interface mainViewController ()
@end
@implementation mainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
mainLayer = [CALayer layer];
mainLayer.bounds = CGRectMake(0, 0, 600, 600);
mainLayer.position = CGPointMake(500, 500);
mainLayer.contents = (id)[UIImage imageNamed:@"TaiwanMap.jpg"].CGImage;
maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(100, 100, 200, 200);
UIColor *c2 = [UIColor blueColor];
maskLayer.name = @"maskLayer";
maskLayer.cornerRadius = 100.0f; //變成圓形的
[maskLayer setBackgroundColor:(c2.CGColor)];
[self.view.layer addSublayer:mainLayer];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startMask:(id)sender {
UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
[self.view addGestureRecognizer:panGesture];
[mainLayer setMask:maskLayer];
}
-(void)handleGesture:(UIGestureRecognizer*)gestureRecognizer
{
if([gestureRecognizer isMemberOfClass:[UIPanGestureRecognizer class]])
{
UIView* piece = [gestureRecognizer view];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ||
[gestureRecognizer state] == UIGestureRecognizerStateChanged)
{
UIPanGestureRecognizer* panGestureRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
CGPoint translation = [panGestureRecognizer translationInView:self.view];
CGFloat X, Y;
X = maskLayer.position.x+translation.x;
Y = maskLayer.position.y + translation.y;
if (X >600)
X = 600;
if (X<100)
X=100;
if (Y > 600)
Y =600;
if (Y<100)
Y=100;
maskLayer.position = CGPointMake(X, Y);
}
}
}
@end
5. 執行結果
訂閱:
文章 (Atom)






























