先上效果图把:


项目有这个需求,之前是别人做的效果不太好,后来需要重写,但还是不是我负责,但是那段时间不算很忙,也用自己的思路尝试着写了一下,实现的效果很差。
现在这个完成效果是项目组的主程写的,最近有空看了一下代码,然后自己模仿着重写了一下。
看完代码,其实实现思路很简单
1.在控制器中添加三个UIView,分别用来放三个子控制器;
2.为view添加panGesture,在手势的delegate中获取位移来处理界面变化;
3.利用UIView的transform属性来实现界面的变化和移动。
关于transform属性,是用矩阵乘法对界面进行位移,旋转,放大缩小等,其实可以简单理解为基于参考坐标系做出一系列变化:
CGAffineTransformRotate // 旋转
CGAffineTransformScale // 放大缩小
CGAffineTransformTranslate // 位移
基本思路就是这样,接下来是具体实现:
1.初始化方法:
- (instancetype)initWithMainViewController:(UIViewController *)mainVC
leftViewController:(UIViewController *)leftVC
rightViewController:(UIViewController *)rightVC
{
self = [super init];
if (self) {
[self prepare];
self.mainViewController = mainVC;
self.leftViewController = leftVC;
self.rightViewController = rightVC;
}
return self;
}
2.初始化界面:
为控制器添加_leftContainerView,_rightContainerView及_mainContainerView,在leftViewController的setter方法中做一些设置,配置界面的默认位置及大小等:
- (void)setLeftViewController:(UIViewController *)leftViewController
{
if (!leftViewController) {
return;
}
_canShowLeft = YES;
_leftViewController = leftViewController;
_leftViewController.view.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
[self addChildViewController:leftViewController];
[_leftContainerView addSubview:leftViewController.view];
_leftContainerView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -leftShowWidth, 0);
_leftContainerView.transform = CGAffineTransformScale(_leftContainerView.transform, leftScale, leftScale);
}
此处使用的参数为预先设置好的,可以修改leftScale或rightScale,改变为图1或图3的显示效果:
#pragma mark ---------- left config -----------
static CGFloat const leftShowWidth = 240.f;
static CGFloat const leftScale = 0.8f; // 缩放比例
static CGFloat const leftDragbleWidth = 80.f; // 左侧可拖动宽度
static CGFloat const leftMinDragLength = 100.f; //触发所需要拖动的最短距离
3.做好界面默认配置以后,需要的就是添加Pan手势,并做处理,
此处只表述思路,实际代码复杂的多
- (void)panGestureHandler:(UIPanGestureRecognizer *)gesture
{
CGPoint point = [gesture locationInView:self.view];
switch (gesture.state) {
case UIGestureRecognizerStateBegan:
{
// 记录拖拽的起点
_startDragPoint = point;
_lastDragPoint = point;
}
break;
case UIGestureRecognizerStateChanged:
{
CGFloat move_length = point.x - _lastDragPoint.x;
CGFloat scale = 1;
_lastDragPoint = point;
// 进行判断是呼出哪边的界面 此处写呼出左侧界面
scale = 1-(move_length/leftShowWidth)*(1-leftScale);
// 根据拖拽移动的距离进行界面的变化
_mainContainerView.transform = CGAffineTransformTranslate(_mainContainerView.transform, move_length, 0);
_mainContainerView.transform = CGAffineTransformScale(_mainContainerView.transform, scale, scale);
CGFloat left_scale = 1+(move_length/leftShowWidth)*(1-leftScale);
_leftContainerView.transform = CGAffineTransformTranslate(_leftContainerView.transform, move_length, 0);
_leftContainerView.transform = CGAffineTransformScale(_leftContainerView.transform, left_scale, left_scale);
}
break;
case UIGestureRecognizerStateEnded:
{
CGFloat move_length = fabs(point.x - _startDragPoint.x);
// 判断拖拽距离是否足够显示或隐藏界面
// 此处只作为例子,以左侧界面为例子
if (move_length>leftMinDragLength) {
if (_isLeftShow) {
[self hideLeft];
}else{
[self showLeft];
}
}else{
if (_isLeftShow) {
[self showLeft];
}else{
[self hideLeft];
}
}
break;
上述代码中,进行界面变化前还需增加判断,何时停止变化。
在show和hide方法中,需要进行动画duration的计算,然后进行界面变化。剩下的基本就是在两个leftController和rightController中进行界面布局了。
由于使用了多个controller,所以leftController和rightController的跳转操作要交由mainController的navigationController来进行,代码中提供了属性以供跳转,若有不同需求,需要重写此属性的getter方法。
@property (nonatomic, strong, readonly) UINavigationController *sliderNavigationController;
基本思路就是这样,比较复杂的基本上是界面位移缩放比例的换算,需要在GestureChanged状态中进行处理。
若有BUG或改进方法,欢迎留言或给我发邮件。
网友评论