一直想要研究下QQ的侧滑效果,最近也正好在做这方面的东西,便记录一下实现的思路,其实在网上也有很多第三方的开源侧滑框架这里推荐一下MMDrawerController.
接下来开始今天的主题,先来介绍下我的大体思路:
首先我的底部是一个容器viewController(关于容器controller的概念可以去看一看Objc中国的第一个专题中的这篇文章),在这个容器controller上面加载了一个MainViewConller以及一个menuView并且我的MainViewController是一个NavigationController的rootViewController,在手势滑动的时候在这个mainViewController上加了一个遮罩的UIControl.
[self.view addSubview:self.menuView];
_mainNav = [[UINavigationController alloc] initWithRootViewController:self.mainViewController];
[self addChildViewController:_mainNav];
_mainNav.view.frame = self.view.frame;
[self.view addSubview:_mainNav.view];
[_mainNav didMoveToParentViewController:self];
然后在我的容器controller中添加了一个UIScreenEdgePanGestureRecognizer
手势,这个手势只作用于屏幕的边缘,可以根据edges
属性来设置手势的方向,这里我设置的是UIRectEdgeLeft
.下面是手势中的方法
// 手指在屏幕中位置
CGFloat panLocationX = [pan locationInView:self.view].x;
// 根据屏幕宽度算出比例
CGFloat percentage = panLocationX / CGRectGetWidth(self.view.bounds);
switch (pan.state)
{
case UIGestureRecognizerStateBegan:
case UIGestureRecognizerStateChanged:
{
// 将比例传入方法中进行计算
[self viewUpdateTrasition:percentage];
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
{
if (percentage > 0.5)
{
[self viewShowMenu];
}
else
{
[self viewHideMenu];
}
}
break;
default:
break;
}
主要的实现是在这个方法中viewUpdateTrasition:
// 在这里添加遮罩的UIControl
[_mainNav.view addSubview:self.maskControl];
// 将传入的比例规整在0-1之间
CGFloat currentProgress = MAX(MIN(progress, 1), 0);
// 这里使mainViewController的视图跟着手指的移动而移动
_mainNav.view.transform = CGAffineTransformMakeTranslation((CGRectGetWidth(self.view.bounds) - 100) * currentProgress, 0);
// 设置遮罩视图的透明度
self.maskControl.alpha = currentProgress;
// 计算出menuView的宽度
CGFloat width = CGRectGetWidth(self.view.bounds) - 100;
CGRect frame = self.menuView.bounds;
frame.size.width = width;
// 根据比例设置menuView的frame中的x值
frame.origin.x = - (1 - currentProgress) * width * 0.4f;
// 更新menuView的位置
self.menuView.frame = frame;
[self.menuView setNeedsLayout];
[self.menuView layoutIfNeeded];
// 条件判断,当比例为0的时候移除遮罩
if (progress == 0)
{
[self.maskControl removeFromSuperview];
}
这里需要重点说明几个地方:
(CGRectGetWidth(self.view.bounds) - 100) * currentProgress
这里减去100是为了使mainViewController的NavigationController移动到距离屏幕还剩100的位置的时候停止.
CGFloat width = CGRectGetWidth(self.view.bounds) - 100
这减去100是设置menu的宽度.
frame.origin.x = - (1 - currentProgress) * width * 0.4f
这里是通过比例计算出menuView所移动的位置,这里乘以0.4是为了造成一个时差的效果.
下面是一个大致的效果:
开.gif 关.gif
网友评论