界面分析
- 手指在图片上拖拽,图片的上半部分能够跟随手指的移动产生一个旋转的效果.
- 向下拖拽的时候,图片的下半部分会有阴影产生.
- 在手指松开的时候,恢复到初始状态,并且产生1个回弹效果.
界面实现
在一个imageView 上面对图片进行变换操作,显然不太现实.可以使用两个imageView上下拼接在一起,使用1个大view作为容器装置两个imageView.
给这个view绑定类
所以现在必须在上面的imageView显示图片的上半部分,在下面的imageView显示图片的下半部分.
有两种方式可以实现
- 第一种方式
在storyboard中设置顶部imageView的contentMode 为top,底部imageView的contentMode为bottom.
这样设置完之后看起来就像是拼接成的一整张图片了.但是使用这种方式设置完之后,由于图片的大小是超过imageView的大小的.并且旋转的坐标轴是整个view的中心位置,所以使用这种方式凭借的话还需要做一些配置
- (void)awakeFromNib {
self.topImageView.layer.masksToBounds = YES;
self.bottomImageView.layer.masksToBounds = YES;
//设置锚点
self.topImageView.layer.anchorPoint = CGPointMake(0.5, 1);
}
由于重新设置了锚点 所以此时运行程序界面会变成这样
重新布局使界面正确正确显示
- (void)layoutSubviews {
[super layoutSubviews];
self.topImageView.layer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
}
修改完之后
- 2 第二种方式比较简单.使用layer自带的一个属性contentsRect .
不用设置contentMode属性,只需要在
- (void)awakeFromNib {
//contentsRect 取值范围为 0 - 1
self.topImageView.layer.contentsRect = CGRectMake(0, 0, 1, 0.5);
self.bottomImageView.layer.contentsRect = CGRectMake(0, 0.5, 1, 0.5);
//设置锚点 让topImageView可以绕着底部旋转
self.topImageView.layer.anchorPoint = CGPointMake(0.5, 1);
//给foldView 添加拖拽手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
// 利用`CAGradientLayer`(渐变图层)制作阴影效果,添加到底部视图上,并且一开始需要隐藏,在拖动的时候慢慢显示出来。
// 颜色应是由`透明到黑色`渐变,表示阴影从无到有。
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
//渐变图层的颜色组属性
gradientLayer.colors = @[(id)[UIColor clearColor].CGColor,(id)[UIColor blackColor].CGColor];
//设置图层frame
gradientLayer.frame = self.bottomImageView.bounds;
//设置图层不透明度
gradientLayer.opacity = 0;
//设置渐变的起点 取值范围为 0 - 1
gradientLayer.startPoint = CGPointMake(0.5, 1);
//设置渐变终点
gradientLayer.endPoint = CGPointMake(0.5, 0);
//添加图层
[self.bottomImageView.layer addSublayer:gradientLayer];
//给foldView添加属性引用图层
self.gradientLayer = gradientLayer;
}
//重新布局
- (void)layoutSubviews {
[super layoutSubviews];
self.topImageView.layer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height * 0.5);
}
实现拖拽监听方法
- (void)pan:(UIPanGestureRecognizer *)pan {
//手指拖拽的距离
CGPoint offset = [pan translationInView:self];
//宽度
CGFloat height = self.bounds.size.height * 0.5;
// 计算Y轴每偏移一点,需要旋转多少角度,angle = offsetY * M_PI / width;
CGFloat angle = offset.y / height * M_PI ;
// 在拖动的时候计算不透明度值,假设拖动bottomImageView的一半时,阴影完全显示,不透明度应该为1,因此 opacity = y轴偏移量 * 1 / 200.0;
CGFloat opacity = offset.y * 1.0 / height;
if(pan.state == UIGestureRecognizerStateEnded) {//拖拽停止的时候
//弹簧动画
[UIView animateWithDuration:0.25 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:9 options:UIViewAnimationOptionCurveEaseInOut animations:^{
//手指停止拖拽的时候重置图层形变
self.topImageView.layer.transform = CATransform3DIdentity;
} completion:^(BOOL finished) {
}];
//将渐变层的不透明度改为0(透明).
self.gradientLayer.opacity = 0;
}else {
//初始化
CATransform3D trans = CATransform3DIdentity;
//设置M34就有立体感(近大远小)。 -1 / z ,z表示观察者在z轴上的值,z越小,看起来离我们越近,东西越大。
trans.m34 = 1 / 1000.0;
//设置绕x轴旋转
self.topImageView.layer.transform = CATransform3DRotate(trans, angle, 1, 0, 0);
//设置不透明度
self.gradientLayer.opacity = opacity;
}
}