实现腾讯qq,新浪微博,网易等app中右拖动返回上一层的效果demo。
首先看一下效果图:
首先要理解UIWindow,UIWindow对象是所有UIView的根,管理和协调的应用程序的显示
UIWindow类是UIView的子类,可以看作是特殊的UIView。
一般应用程序只有一个UIWindow对象,即使有多个UIWindow对象,也只有一个UIWindow可以接受到用户的触屏事件。
//window窗口 #define WINDOW [[UIApplication sharedApplication]keyWindow]
第一步:要在UIView上添加一个pan拖动的手势,并添加处发方法handlePanGesture;
//拖动手势 UIPanGestureRecognizer *panGesture=[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)]; //添加手势 [self.view addGestureRecognizer:panGesture];
第二步:handlePanGesture方法中首先判断是不是顶级视图,是return,如果不是需要返回上一层;
首先定义所需变量:
@interface MyNavigationViewController () { CGPoint startTouch;//拖动时的开始坐标 BOOL isMoving;//是否在拖动中 UIView *blackMask;//那层黑面罩 UIImageView *lastScreenShotView;//截图 } @property (nonatomic,retain) UIView *backgroundView;//背景 @property (nonatomic,retain) NSMutableArray *screenShotsList;//存截图的数组 @end
然后是handlePanGesture方法处理:
//拖动手势 -(IBAction)handlePanGesture:(UIGestureRecognizer*)sender{ //如果是顶级viewcontroller,结束 if (self.viewControllers.count <= 1) return; //得到触摸中在window上拖动的过程中的xy坐标 CGPoint translation=[sender locationInView:WINDOW]; //状态结束,保存数据 if(sender.state == UIGestureRecognizerStateEnded){ NSLog(@"结束%f,%f",translation.x,translation.y); isMoving = NO; self.backgroundView.hidden = NO; //如果结束坐标大于开始坐标50像素就动画效果移动 if (translation.x - startTouch.x > 50) { [UIView animateWithDuration:0.3 animations:^{ //动画效果,移动 [self moveViewWithX:320]; } completion:^(BOOL finished) { //返回上一层 [self popViewControllerAnimated:NO]; //并且还原坐标 CGRect frame = self.view.frame; frame.origin.x = 0; self.view.frame = frame; }]; }else{ //不大于50时就移动原位 [UIView animateWithDuration:0.3 animations:^{ //动画效果 [self moveViewWithX:0]; } completion:^(BOOL finished) { //背景隐藏 self.backgroundView.hidden = YES; }]; } return; }else if(sender.state == UIGestureRecognizerStateBegan){ NSLog(@"开始%f,%f",translation.x,translation.y); //开始坐标 startTouch = translation; //是否开始移动 isMoving = YES; if (!self.backgroundView) { //添加背景 CGRect frame = self.view.frame; self.backgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width , frame.size.height)]; //把backgroundView插入到Window视图上,并below低于self.view层 [WINDOW insertSubview:self.backgroundView belowSubview:self.view]; //在backgroundView添加黑色的面罩 blackMask = [[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width , frame.size.height)]; blackMask.backgroundColor = [UIColor blackColor]; [self.backgroundView addSubview:blackMask]; } self.backgroundView.hidden = NO; if (lastScreenShotView) [lastScreenShotView removeFromSuperview]; //数组中最后截图 UIImage *lastScreenShot = [self.screenShotsList lastObject]; //并把截图插入到backgroundView上,并黑色的背景下面 lastScreenShotView = [[UIImageView alloc]initWithImage:lastScreenShot]; [self.backgroundView insertSubview:lastScreenShotView belowSubview:blackMask]; } if (isMoving) { [self moveViewWithX:translation.x - startTouch.x]; } }
以上代码实现的是在UIWindow上放一个屏幕大小的UIView *backgroundView,并且这个UIView要插入到UIWindow视图里当前UIVIew的下面,这个方法是[WINDOW insertSubview:self.backgroundView belowSubview:self.view];
然后在backgroundView上要两个view:
UIView *blackMask;//那层黑面罩
UIImageView *lastScreenShotView;//截屏图
在拖动中不断的改变blackMask透明值,改变lastScreenShotView缩放大小:
- (void)moveViewWithX:(float)x { NSLog(@"Move to:%f",x); x = x>320?320:x; x = x<0?0:x; CGRect frame = self.view.frame; frame.origin.x = x; self.view.frame = frame; float scale = (x/6400)+0.95;//缩放大小 float alpha = 0.4 - (x/800);//透明值 //缩放scale lastScreenShotView.transform = CGAffineTransformMakeScale(scale, scale); //背景颜色透明值 blackMask.alpha = alpha; }
另外要把当前屏转化成图片的方法,UIView转成UIImage
//把UIView转化成UIImage,实现截屏 - (UIImage *)ViewRenderImage { //创建基于位图的图形上下文 Creates a bitmap-based graphics context with the specified options.:UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale),size大小,opaque是否透明,不透明(YES),scale比例缩放 UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0); //当前层渲染到上下文 [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; //上下文形成图片 UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); //结束并删除当前基于位图的图形上下文。 UIGraphicsEndImageContext(); //反回图片 return img; }
第三步:当push的时候,需要把当前图片添加存到数组中;当pop的时候,需要把最后一个图片移除。
#pragma UINavigationController 覆盖方法 -(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { //图像数组中存放一个当前的界面图像,然后再push [self.screenShotsList addObject:[self ViewRenderImage]]; [super pushViewController:viewController animated:animated]; } -(UIViewController *)popViewControllerAnimated:(BOOL)animated { //移除最后一个 [self.screenShotsList removeLastObject]; return [super popViewControllerAnimated:animated]; }
Demo下载地址:http://download.csdn.net/detail/rhljiayou/5979139