開發(fā)語言有面向?qū)ο箝_發(fā),其實產(chǎn)品交互也有面向?qū)ο蟮母拍?譬如APP有一個功能模塊它能夠通過多個步驟產(chǎn)生一個或多個結(jié)果,到達結(jié)果界面后返回的指令是回到該模塊的入口處.這樣就不會重復pop,以增強模塊的結(jié)果輸出.這種情況下,返回時我們常調(diào)用的方法是
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
在點擊返回按鈕的時候調(diào)用該方法能讓我們回到指定界面,但如果我們打開了側(cè)滑返回手勢,就會發(fā)現(xiàn)側(cè)滑依然返回到上一個界面.而翻閱相關文檔,并沒有能快速達到效果的API,所以需要對UINavigationController和UIViewController的部分方法進行重寫.
首先,建一個UIViewController的子類
@interface BaseViewController : UIViewController
@property(nonatomic,strong) UIButton *leftButton;
@end
給返回按鈕的添加執(zhí)行方法
[self.leftButton addTarget:self
action:@selector(popOrDismiss:)
forControlEvents:UIControlEventTouchUpInside];
//默認pop或者dismiss到上一個界面
-(void)popOrDismiss:(UIButton*)buuton
{
if (self.navigationController.viewControllers.count == 1)
{
[self dismissViewControllerAnimated:YES completion:nil];
}
else
{
[self.navigationController popViewControllerAnimated:YES];
}
}
再建一個UINavigationController的子類
@interface DDNavigationViewController ()<UIGestureRecognizerDelegate>
@property (nonatomic,assign) BOOL leftPanUse;//是否為滑動狀態(tài)
@property (strong, nonatomic)UIPanGestureRecognizer *panGestureRecognizer;//滑動手勢
@property (strong, nonatomic)UIImageView *backView;//圖片
@property (strong, nonatomic)NSMutableArray *backImgs;//緩存圖片數(shù)組
@property (assign) CGPoint panBeginPoint;//滑動起始位置
@property (assign) CGPoint panEndPoint;//滑動結(jié)束為止
@property (nonatomic,assign) NSInteger toIndex;//目標ViewControlelr的index
@end
系統(tǒng)默認的滑動手勢由于暴露的比較少,并且為readonly,所以關閉系統(tǒng)滑動然后新建一個滑動手勢
//原生方法無效
self.interactivePopGestureRecognizer.enabled = NO;
//設置新的滑動手勢
self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizerAction:)];
self.panGestureRecognizer.delegate = self;
[self.view addGestureRecognizer:self.panGestureRecognizer];
每次push的時候需要將上個界面截屏并將圖片存入緩存圖片數(shù)組中,以便于pop的時候找到對應的ViewController的截屏來保證動畫的流暢度.
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
//截圖
UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, 1.0);
[[UIApplication sharedApplication].keyWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.backImgs addObject:img];
[super pushViewController:viewController animated:animated];
}
通過手勢代理對滑動手勢狀態(tài)進行監(jiān)控.滑動開始時讓最上層的BaseViewController子類執(zhí)行點擊返回的方法,返回方法中執(zhí)行DDNavigationViewController的pop方法,這樣就能在DDNavigationViewController中拿到目標ViewController
-(void)popOrDismiss:(UIButton*)buuton
{
[self.navigationController popToViewController:viewController animated:YES];
}
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (self.leftPanUse == YES) //正在滑動,得到目標ViewController的index,不執(zhí)行pop操作
{
self.toIndex = [self.viewControllers indexOfObject:viewController];
return nil;
}
else//滑動結(jié)束,執(zhí)行pop操作,并刪除緩存圖片
{
NSInteger index = [self.viewControllers indexOfObject:viewController];
[_backImgs removeObjectsInRange:NSMakeRange(index, _backImgs.count - index)];
return [super popToViewController:viewController animated:animated];
}
}
- (void)panGestureRecognizerAction:(UIPanGestureRecognizer*)panGestureRecognizer{
if ([self.viewControllers count] == 1) {
return ;
}
if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"滑動開始");
self.leftPanUse = YES;
BaseViewController *base = [self.viewControllers lastObject];
[base popOrDismiss:nil];
//存放滑動開始的位置
self.panBeginPoint = [panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow];
//插入圖片
[self insertLastViewFromSuperView:self.view.superview index:self.toIndex];
}else if(panGestureRecognizer.state == UIGestureRecognizerStateEnded){
NSLog(@"滑動結(jié)束");
//存放數(shù)據(jù)
self.panEndPoint = [panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow];
self.leftPanUse = NO;
if ((_panEndPoint.x - _panBeginPoint.x) > 150) {
[UIView animateWithDuration:0.3 animations:^{
[self moveNavigationViewWithLenght:[UIScreen mainScreen].bounds.size.width];
} completion:^(BOOL finished) {
[self moveNavigationViewWithLenght:0];
[self removeLastViewFromSuperViewWithIndex:self.toIndex];
UIViewController *viewControler = self.viewControllers[self.toIndex];
[self popToViewController:viewControler animated:NO];
}];
}else{
[UIView animateWithDuration:0.3 animations:^{
[self moveNavigationViewWithLenght:0];
} completion:^(BOOL finished) {
[self removeLastViewFromSuperViewWithIndex:self.toIndex];
}];
}
}else{
//添加移動效果
CGFloat panLength = ([panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow].x - _panBeginPoint.x);
if (panLength > 0) {
[self moveNavigationViewWithLenght:panLength];
}
}
}
這樣,在Viewcontroller中只要重寫popOrDismiss(不重寫則默認返回上一界面)就能點擊返回和滑動返回到同一個界面.
PS:簡書用的不熟,沒能繪制邏輯圖,導致這塊講的有點繞.后面會補上demo