最近做一个图的加载动态效果时,看到一篇教程,不过他是在CAShapeLayer上完成的,当时我对CALayer并不是很了解。raywenderlich上的这篇文章有对它的具体介绍。采用的是swift,我把他改为了Objective-C,顺带翻译了带有简单例子的一段。
Brief Introduction
你可能会知道,在iOS app中你看到的所有东西都是view,含有button views,table views,slider views,甚至还有包含其他views的parent views。
但是你可能不知道每一个view后都有一个layer,比较特殊的是CAPlayer。
在这篇文章,你将会学习到什么是CAPlayer和它如何使用。此时,将假定你对于iOS app开发和Objective-C的基础很熟悉,包括在storyboard中构造你的UI。
Getting Started
想知道layers到底是什么最好的方法就是亲自动手做一个。所以让我们开始创建一个简单的工程
准备好去写一些代码了吗?好,打开Xcode然后:
- 点击menu选择File\New\Project..
- 从dialog选择iOS\Application\Single View Application
- 点击Next,在Product Name后输入CALayerPlayground,以及填写其他项目
- 选择Objective-C作为语言和Universal for Devices
- 注意不要选择Core Data
- 找到一个地方存在你的project,然后点击Create
- 在左侧Project navigator 选择Main.storyboard
- 点击menu选择View\Assistant Editor\Show Assistant Editor,如果Object Library没有显示的话,点击View\Utilities\Show Object Library使其显示
- 同时,选择Editor\Canvas\Show Bounds Rectangles,这样当你想添加一个view,就可以看到每一个view的边界轮廓
- 从Object library中拉出一个view倒View Controller Scene中。选中他,去右方的Sizeinspector((View\Utilities\Show Size Inspector),将x、y设为150,width、height设为300
- 在auto layout toolbar中点击Align按钮(storyboard的右下角)然后点击Horizontal Center in Container和Vertical Center in Container,将他们的Values设为0。最后点击Add 2 Constraints
- 点击Pin按钮,检查Width和Height,确定他们的值都设为300,and点击Add 2 Contstraints
最后,按住ctrol并拖住view到文件ViewController.m的@interface与@end中间。在出现的弹出窗口中,将这个outlet命名为viewForLayer。你的Xcode现在需要看起来像这个
点击Connect去创建outlet
将ViewController.m替换内容如下:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *viewForLayer;
@end
@implementation ViewController
//CALayer *l = lorLayer.layer;
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpPlayer];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)setUpPlayer{
CALayer *l = _viewForLayer.layer;
l.backgroundColor = [[UIColor blueColor] CGColor];
l.borderWidth = 100.0;
l.borderColor = [[UIColor redColor]CGColor];
l.shadowOpacity = 0.7;
l.shadowRadius = 10.0;//default :3
l.contents = (__bridge id _Nullable)([[UIImage imageNamed:@"star"] CGImage]);
l.contentsGravity = kCAGravityCenter;
}
正如前文所提到的,每一个ios中的view都有一个layer与其联系,你可以使用yourView.layer调用layer。故我们要做的第一件事是创建一个preoperty l(L的小写)去调用viewForlayer的layer,这样做可以减少你敲击键盘的次数。
这段代码同样调用了setUpLayer去设置一些关于layer的属性:shadow,background,border.你将会对setUppLayer了解更多的,不过首先我们要先用iOS Simulator(iOS模拟器)运行一下程序,检查一下你的自定义layer:
几行代码就有十分cool的效果是吧?还有再来一次=因为每一个view背后都有一个layer,你可以在你的app中对于任何view做这种事情。接下来,让我们更进一步吧!
Basic CALayer Properties
CaLayer有一些属性可以让你自定义他的外形。回头思考一下你已经做了什么:
- 改变了layer的背景颜色,(none->blue)
- 改变了borer的大小 (0->100)
- 改变了她本身的颜色 (black->red)
- 最后,你加上了一个shadow。通过改变shadow opacity(0->0.7)来实现的;改变opacity只会让shadow显现,然后你更进一步改变了shadow radius(3->10),其中3为默认半径。
你仍旧可以设置一些属性在CALayer。让我们再来一次。在setUpLayer()中增加:
l.contents = (__bridge id _Nullable)([[UIImage imageNamed:@"star"] CGImage]);
l.contentsGravity = kCAGravityCenter;```
在CALayer中content的属性允许你修改layer的内容变为图片,所以你可以设置图star。可以[在这里下载](http://cdn4.raywenderlich.com/wp-content/uploads/2014/12/star.png),然后添加到你的项目中。
创建运行,然后花一点时间去欣赏这个极好的艺术品:
![](https://img.haomeiwen.com/i669709/d64b91e64216712b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
注意下star是怎样在中间的-这是因为你设置了contentGravity为KCAGravityCenter。正如你可能期望的,你还可以改变gravity为top,right,bottom-right,bottom,bottom-left和top-left。
##Changing the Layer's Appearance
就当是为了好玩,让我们增加一些手势去操作layer的外表。从Object Library拖出一个tap gesture recognizer,覆盖在viewForLayer上。就像:
![](https://img.haomeiwen.com/i669709/8fbc8ef687a333f3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
重复这个操作去添加pinch gesture recognizer在viewForLayer。
然后control-drag两个gesture recognizer到ViewControll.m,位置在setUpLayer()与类的最后的大括号中间。例如:
![](https://img.haomeiwen.com/i669709/aaf6945e3e8bde2b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
像这样更改tapGestureRecognized(_:):
```Objective-C
- (IBAction)tapGestureRecognized:(UITapGestureRecognizer *)sender {
CALayer *l = _viewForLayer.layer;
// l.shadowOpacity = (l.shadowOpacity == 0.7)? 0.0:0.7;
if (l.shadowOpacity == 0.7) {
l.shadowOpacity = 0.0;
}else{
l.shadowOpacity = 0.7;
}
}```
这告诉viewForLayer在tap时,控制layer的shadow opacity在0.7、0之间。
你是说这个view?当然了。你可以重写CALayer的hitTest(_:)去做一样的事情。但是在这个方法里有一个逻辑,每一个layer也只能做hit testing,因为它不能对recognized gesture做出相应反应。所以你需要建立一个tap recognizer。
现在更改pinchGestureRecognized(_:)如下:
- (IBAction)pinchGestureRecognized:(UIPinchGestureRecognizer *)sender {
CALayer l = _viewForLayer.layer;
CGFloat offset = (sender.scale <1) ? 0.5 :-0.5;
const CGRect oldFrame = l.frame;
const CGPoint oldOrigin = oldFrame.origin;
const CGPoint newOrigin = CGPointMake(oldOrigin.x+offset, oldOrigin.y+offset);
const CGSize newSize = CGSizeMake(oldFrame.size.width+(offset * -2.0), oldFrame.size.width+(offset-2.0));
const CGRect newFrame = CGRectMake(newOrigin.x, newOrigin.y, newSize.width, newSize.height);
if (newFrame.size.width >= 100.0 && newFrame.size.width<=300.0) {
l.borderWidth -= offset;
l.cornerRadius +=(offset/2.0);
l.frame = newFrame;
}```
这里你在创建一个基于user's pinch positive或者negative offset,然后调整layer的frame size,border width与boder的conrner radius。
layer的corner radius的默认值是0,意味着一开始是一个90°矩形。xxxxxxxxxxxxx。想要xxxxx?设置corner radius为width的一半。
注意改变corner radius并没有剪切layer content(图star),除非你将masksToBounds设置为true。
Build & Run,然后试着点和放大缩小。
嘿,多一点打磨,你成为一个很漂亮的阿凡达的制造者!
这里附上我的code.
网友评论