iOS_20_微博自己定义可动画切换的导航控制器
终于效果:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
AnimatedNavigationController.h
//
// AnimatedNavigationController.h
// 20_帅哥no微博
//
// Created by beyond on 14-8-10.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 继承自导航控制器,可是多了一个功能,能够监听手势,进行动画切换 #import <UIKit/UIKit.h> @interface AnimatedNavigationController : UINavigationController @end
AnimatedNavigationController.m
//
// AnimatedNavigationController.m
// 20_帅哥no微博
//
// Created by beyond on 14-8-10.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "AnimatedNavigationController.h"
// 截图用到
#import <QuartzCore/QuartzCore.h>
#import "BeyondViewController.h"
@interface AnimatedNavigationController ()
{
// 屏幕截图
UIImageView *_screenshotImgView;
// 截图上面的黑色半透明遮罩
UIView *_coverView; // 存放全部截图
NSMutableArray *_screenshotImgs;
} @end @implementation AnimatedNavigationController - (void)viewDidLoad
{
[super viewDidLoad];
// 1,创建Pan手势识别器,并绑定监听方法
UIPanGestureRecognizer *panGestureRec = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureRec:)];
// 为导航控制器的view加入Pan手势识别器
[self.view addGestureRecognizer:panGestureRec]; // 2.创建截图的ImageView
_screenshotImgView = [[UIImageView alloc] init];
// app的frame是除去了状态栏高度的frame
_screenshotImgView.frame = [UIScreen mainScreen].applicationFrame;
//(0 20; 320 460); // 3.创建截图上面的黑色半透明遮罩
_coverView = [[UIView alloc] init];
// 遮罩的frame就是截图的frame
_coverView.frame = _screenshotImgView.frame;
// 遮罩为黑色
_coverView.backgroundColor = [UIColor blackColor]; // 4.存放全部的截图数组初始化
_screenshotImgs = [NSMutableArray array]; } // 重写push方法,在push之前 先截取图片
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// 仅仅有在导航控制器里面有子控制器的时候才须要截图
if (self.viewControllers.count >= 1) {
// 调用自己定义方法,使用上下文截图
[self screenShot];
}
// 截图完毕之后,才调用父类的push方法
[super pushViewController:viewController animated:YES];
} // 使用上下文截图,并使用指定的区域裁剪,模板代码
- (void)screenShot
{
// 将要被截图的view,即窗体的根控制器的view(必须不含状态栏,默认ios7中控制器是包括了状态栏的)
BeyondViewController *beyondVC = (BeyondViewController *)self.view.window.rootViewController;
// 背景图片 总的大小
CGSize size = beyondVC.view.frame.size;
// 开启上下文,使用參数之后,截出来的是原图(YES 0.0 质量高)
UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
// 要裁剪的矩形范围
CGRect rect = CGRectMake(0, -20.8, size.width, size.height + 20 );
//注:iOS7以后renderInContext:由drawViewHierarchyInRect:afterScreenUpdates:替代
[beyondVC.view drawViewHierarchyInRect:rect afterScreenUpdates:NO];
// 从上下文中,取出UIImage
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
// 加入截取好的图片到图片数组
[_screenshotImgs addObject:snapshot]; // 千万记得,结束上下文(移除栈顶的基于当前位图的图形上下文)
UIGraphicsEndImageContext(); } // 监听手势的方法,仅仅要是有手势就会运行
- (void)panGestureRec:(UIPanGestureRecognizer *)panGestureRec
{ // 假设当前显示的控制器已经是根控制器了,不须要做不论什么切换动画,直接返回
if(self.topViewController == self.viewControllers[0]) return;
// 推断pan手势的各个阶段
switch (panGestureRec.state) {
case UIGestureRecognizerStateBegan:
// 開始拖拽阶段
[self dragBegin];
break; case UIGestureRecognizerStateEnded:
// 结束拖拽阶段
[self dragEnd];
break; default:
// 正在拖拽阶段
[self dragging:panGestureRec];
break;
}
} #pragma mark 開始拖动,加入图片和遮罩
- (void)dragBegin
{
// 重点,每次開始Pan手势时,都要加入截图imageview 和 遮盖cover到window中
[self.view.window insertSubview:_screenshotImgView atIndex:0];
[self.view.window insertSubview:_coverView aboveSubview:_screenshotImgView]; // 而且,让imgView显示截图数组中的最后(最新)一张截图
_screenshotImgView.image = [_screenshotImgs lastObject];
} // 默认的将要进行缩放的截图的初始比例
#define kDefaultScale 0.6
// 默认的将要变透明的遮罩的初始透明度(全黑)
#define kDefaultAlpha 1.0 // 当拖动的距离,占了屏幕的总宽度的3/4时, 就让imageview全然显示。遮盖全然消失
#define kTargetTranslateScale 0.75
#pragma mark 正在拖动,动画效果的精髓,进行缩放和透明度变化
- (void)dragging:(UIPanGestureRecognizer *)pan
{ // 得到手指拖动的位移
CGFloat offsetX = [pan translationInView:self.view].x;
// 仅仅同意往右边拖,禁止向左拖
if (offsetX < 0) offsetX = 0;
// 让整个导航的view都平移
self.view.transform = CGAffineTransformMakeTranslation(offsetX, 0); // 计算眼下手指拖动位移占屏幕总的宽度的比例,当这个比例达到3/4时, 就让imageview全然显示。遮盖全然消失
double currentTranslateScaleX = offsetX/self.view.frame.size.width; // 让imageview缩放,默认的比例+(当前平移比例/目标平移比例)*(1-默认的比例)
double scale = kDefaultScale + (currentTranslateScaleX/kTargetTranslateScale) * (1 - kDefaultScale);
// 已经达到原始大小了,就能够了,不用放得更大了
if (scale > 1) scale = 1;
_screenshotImgView.transform = CGAffineTransformMakeScale(scale, scale); // 让遮盖透明度改变,直到减为0,让遮罩全然透明,默认的比例-(当前平移比例/目标平移比例)*默认的比例
double alpha = kDefaultAlpha - (currentTranslateScaleX/kTargetTranslateScale) * kDefaultAlpha;
_coverView.alpha = alpha;
} #pragma mark 结束拖动,推断结束时拖动的距离作对应的处理,并将图片和遮罩从父控件上移除
- (void)dragEnd
{
// 取出挪动的距离
CGFloat translateX = self.view.transform.tx;
// 取出宽度
CGFloat width = self.view.frame.size.width; if (translateX <= width * 0.5) {
// 假设手指移动的距离还不到屏幕的一半,往左边挪 (弹回)
[UIView animateWithDuration:0.3 animations:^{
// 重要~~让被右移的view弹回归位,仅仅要清空transform就可以办到
self.view.transform = CGAffineTransformIdentity;
// 让imageView大小恢复默认的scale
_screenshotImgView.transform = CGAffineTransformMakeScale(kDefaultScale, kDefaultScale);
// 让遮盖的透明度恢复默认的alpha 1.0
_coverView.alpha = kDefaultAlpha;
} completion:^(BOOL finished) {
// 重要,动画完毕之后,每次都要记得 移除两个view,下次開始拖动时,再加入进来
[_screenshotImgView removeFromSuperview];
[_coverView removeFromSuperview];
}];
} else {
// 假设手指移动的距离还超过了屏幕的一半,往右边挪
[UIView animateWithDuration:0.3 animations:^{
// 让被右移的view全然挪到屏幕的最右边,结束之后,还要记得清空view的transform
self.view.transform = CGAffineTransformMakeTranslation(width, 0);
// 让imageView缩放置为1
_screenshotImgView.transform = CGAffineTransformMakeScale(1, 1);
// 让遮盖alpha变为0,变得全然透明
_coverView.alpha = 0;
} completion:^(BOOL finished) {
// 重要~~让被右移的view全然挪到屏幕的最右边,结束之后,还要记得清空view的transform,不然下次再次開始drag时会出问题,由于view的transform没有归零
self.view.transform = CGAffineTransformIdentity;
// 移除两个view,下次開始拖动时,再加回来
[_screenshotImgView removeFromSuperview];
[_coverView removeFromSuperview]; // 运行正常的Pop操作:移除栈顶控制器,让真正的前一个控制器成为导航控制器的栈顶控制器
[self popViewControllerAnimated:NO]; // 重要~记得这时候,能够移除截图数组里面最后一张无用的截图了
[_screenshotImgs removeLastObject];
}];
}
}
@end
iOS_20_微博自己定义可动画切换的导航控制器的更多相关文章
- iOS 自己定义页面的切换动画与交互动画 By Swift
在iOS7之前,开发人员为了寻求自己定义Navigation Controller的Push/Pop动画,仅仅能受限于子类化一个UINavigationController,或是用自己定义的动画去覆盖 ...
- iOS_20_微博Dock的尾随切换
终于效果图:Dock尾随HomeVC一起切换 要求: 当点击HomeVC里面的微博列表的某一行时候, push到StatusDetail微博详情控制器,而且Dock也一起消失 当点击StatusDet ...
- Activity左边滑出,右边滑入的动画切换
Activity左边滑出,右边滑入的动画切换 转载请注明出处:http://blog.csdn.net/u012301841/article/details/46920809 大家都知道Android ...
- jQuery鼠标悬停内容动画切换效果
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JQuery动画插件Velocity.js发布:更快的动画切换速度
5月3日,Julian在其GitHub上发布了Velocity.js.Velocity.js是一款动画切换的jQuery插件,它重新实现了jQuery的$.animate()方法从而加快动画切换的速度 ...
- ACtivity实现欢迎界面并添加动画切换效果
先看效果: 中间切换动画没来得及截图,凑合着看吧. 主要是java代码的实现: Welcom.java package kehr.activity.welcome; import android.ap ...
- Velocity.js发布:更快的动画切换速度
Velocity.js是一款动画切换的jQuery插件,它重新实现了jQuery的$.animate()方法从而加快动画切换的速度.Velocity.js只有7k的大小,它不仅包含了$.animate ...
- Android中TweenAnimation四种动画切换效果
点击每个按钮都会有对应的动画显示 activity代码: package com.tmacsky; import android.app.Activity; import android.os.Bun ...
- iOS_20_微博的骨架结构
最后效果图: BeyondViewController.m // // BeyondViewController.m // 20_帅哥no微博 // // Created by beyond on 1 ...
随机推荐
- P5304 [GXOI/GZOI2019]旅行者(最短路/乱搞)
luogu bzoj Orz自己想出神仙正解的sxy 描述略 直接把所有起点推进去跑dijkstra... 并且染色,就是记录到这个点的最短路是由哪个起点引导出来的 然后再把所有边反指跑一次... 之 ...
- JavaScript小技巧整理篇(非常全)
能够为大家提供这些简短而实用的JavaScript技巧来提高大家编程能力,这对于我来说是件很开心的事.每天仅花上不到2分钟的时间中,你将可 以读遍JavaScript这门可怕的语言所呈现给我们的特性: ...
- Buffer.allocUnsafe()
Buffer.allocUnsafe(size) size {Number} 分配一个 size 字节大小的新的非零填充(non-zero-filled)的 Buffer.size 必须小于等于 re ...
- PHP:获取用户IP
文章来源:http://www.cnblogs.com/hello-tl/p/7685263.html //获取用户ip(外网ip 服务器上可以获取用户外网Ip 本机ip地址只能获取127.0.0.1 ...
- vscode 解决符号无法识别的问题
一开始浏览代码出现了下面这个问题, __attribute__ 标记为红色,符号无法识别,下面还出现了很多提示需要加 ), } 等符号,虽然编译没问题,但是看着红色标记和一堆提示真是要逼死强迫症. 既 ...
- npm run build 打包后,如何查看效果
我们用vue-cli搭建的项目执行npm build后本地打开页面空白,如果才能查看npm run build之后的结果呢 首先我们看一下提示 Tip: built files are meant t ...
- jQuery_DOM学习之------包裹元素的方法
1..wrap( ):在集合中匹配的每个元素周围包裹一个HTML结构 简单的看一段代码: <span>连接文字</span> 给span元素增加一个a包裹 $('span'). ...
- 《C语言程序设计(第四版)》阅读心得(二)
第六章引用数组处理批量数据 1.数组的定义 :类型符 数组名[常量表达式] 1) 在主函数中定义数组,常量表达式不能包含变量 +]; //合法 int n; int a[n]; //不合法 2)在被 ...
- 【转】Java IO流 overview
Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)
Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 7669 Solved: 1894[Submi ...