天天看點

iOS學習筆記-095.彩票10——滑動移除控制器全屏實作彩票10——滑動移除控制器全屏實作

  • 彩票10滑動移除控制器全屏實作
    • 一圖示
    • 二分析
    • 三非全屏滑動删除的處理方式
    • 四全屏滑動删除的處理方式 1 KVC
    • 五全屏滑動删除的處理方式 2 delegate

彩票10——滑動移除控制器全屏實作

一、圖示

iOS學習筆記-095.彩票10——滑動移除控制器全屏實作彩票10——滑動移除控制器全屏實作

二、分析

原本系統有滑動删除的,但是我們添加了放回按鈕以後沒有了,那麼這下就尴尬了吧。那麼我們就行來實作一下。

其實我們隻需要把 系統手勢的代理設定為nil 就可以實作這樣的功能了,但是這用實作,我們是能滑動左邊的并且不包含導覽列。并且會産生一個bug,就是如果我們在根控制器上滑動了,那麼我們就 push 不了其他控制器了。那麼怎麼解決呢,其實解決方式很簡單,我們一開始記住我們的代理,然後在 did 控制器的時候,我們判斷一下,目前的控制器是不是根控制器,如果是還原,不是指派為nil。

另外的處理方式,就是我們自己添加一個滑動手勢,然後我們使用系統的處理方法和targer來處理這個手勢就行了。

三、非全屏滑動删除的處理方式

這種方式處理的結果就是隻能從左側滑動時删除。

這種方式需要添加 UINavigationControllerDelegate 代理

//
//  QWMNavigationController.m
//  03_UIView79_彩票
//
//  Created by 杞文明 on 17/8/13.
//  Copyright © 2017年 杞文明. All rights reserved.
//

#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate>
/** 系統手勢代理 */
@property (nonatomic, strong) id popGesture;
@end

@implementation QWMNavigationController

········

-(void)viewDidLoad{
    [super viewDidLoad];
    self.popGesture = self.interactivePopGestureRecognizer.delegate;
    self.delegate = self;
}

// 解決如果在根控制器上滑動了,不能删除的情況
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    if(self.viewControllers[]==viewController){//根控制器
        self.interactivePopGestureRecognizer.delegate = self.popGesture;
    }else{
        // 清空手勢代理就能實作滑動傳回, iOS6不支援
        self.interactivePopGestureRecognizer.delegate = nil;
    }
}

·····

@end
           

四、全屏滑動删除的處理方式 1 —— KVC

這種方式的處理就是,自己添加一個滑動手勢 UIPanGestureRecognizer 這個手勢的 target 和 action,使用系統手勢使用的。

那麼我們使用

NSLog(@"%@",self.interactivePopGestureRecognizer);
           

列印一下系統手勢的資訊

如下

<UIScreenEdgePanGestureRecognizer: 0x7fd258d1ab20; 
    state = Possible; 
    delaysTouchesBegan = YES; 
    view = <UILayoutContainerView 0x7fd258d198a0>; 
    target= <
       (action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fd258e1be20>)
    >
>
           

通過上面的資訊,我們可以知道 我們 添加的手勢的 action 就是

handleNavigationTransition:

方法。

但是我們 target 我們還沒辦法拿到。

我們使用 oc 中的 runtime 機制,來擷取我們的屬性名稱,然後使用 KVC 來擷取我們的 target

我們使用 runtime 機制列印出 UIGestureRecognizer 裡面的屬性

// oc  runtime 機制 隻能動态擷取目前類的成員屬性,不能擷取其子類,或者父類的屬性
// __unsafe_unretained Class  要擷取哪個類的成員屬性
// unsigned int *outCount  擷取Class 下面的所有成員屬性的個數

unsigned int outCount;
Ivar * ivars = class_copyIvarList([UIGestureRecognizer class], &outCount);
for (int i=; i<outCount; i++) {
    NSString * name = @(ivar_getName(ivars[i]));
    NSLog(@"%@",name);
}
           

列印結果

2017-08-26 16:21:36.885 03_UIView79_彩票[12961:57679] _gestureFlags
2017-08-26 16:21:36.885 03_UIView79_彩票[12961:57679] _targets
2017-08-26 16:21:36.885 03_UIView79_彩票[12961:57679] _delayedTouches
2017-08-26 16:21:36.886 03_UIView79_彩票[12961:57679] _delayedPresses
2017-08-26 16:21:36.886 03_UIView79_彩票[12961:57679] _view
2017-08-26 16:21:36.886 03_UIView79_彩票[12961:57679] _lastTouchTimestamp
2017-08-26 16:21:36.887 03_UIView79_彩票[12961:57679] _state
2017-08-26 16:21:36.887 03_UIView79_彩票[12961:57679] _allowedTouchTypes
2017-08-26 16:21:36.887 03_UIView79_彩票[12961:57679] _initialTouchType
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _internalActiveTouches
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _forceClassifier
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _requiredPreviewForceState
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _touchForceObservable
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _touchForceObservableAndClassifierObservation
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _forceTargets
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _forcePressCount
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _beganObservable
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _failureRequirements
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _failureDependents
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _delegate
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _allowedPressTypes
2017-08-26 16:21:36.890 03_UIView79_彩票[12961:57679] _gestureEnvironment
           

我們可以看到有一個 —targets 屬性,然後我們 通過 KVC 擷取這個值,然後列印一下。

UIScreenEdgePanGestureRecognizer * gest = self.interactivePopGestureRecognizer;

id targets = [gest valueForKeyPath:@"_targets"];

NSLog(@"%@",targets);
           

結果

(
    "(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fb3c9d0b5d0>)"
)
           

我們可以看到 這是一個數組,但是我們還是沒法知道我麼的 target。

我們調試一下看一下。我們會發現原來屬性叫 _target

iOS學習筆記-095.彩票10——滑動移除控制器全屏實作彩票10——滑動移除控制器全屏實作

現在我們已經知道屬性名了,那麼我麼既可以通過 KVC 來擷取了

// 通過 KVC 方式擷取 _target
    id target = [targets[] valueForKeyPath:@"_target"];
           

完整如下

//
//  QWMNavigationController.m
//  03_UIView79_彩票
//
//  Created by 杞文明 on 17/8/13.
//  Copyright © 2017年 杞文明. All rights reserved.
//

#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
/** 系統手勢代理 */
@property (nonatomic, strong) id popGesture;
@end

@implementation QWMNavigationController

.......

-(void)viewDidLoad{
    [super viewDidLoad];

    UIScreenEdgePanGestureRecognizer * gest = self.interactivePopGestureRecognizer;

    //KVC擷取 _targets 
    NSArray * targets = [gest valueForKeyPath:@"_targets"];

    // 通過 KVC 方式擷取 _target
    id target = [targets[] valueForKeyPath:@"_target"];

    //添加滑動手勢
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:target action:@selector(handleNavigationTransition:)];
    [self.view addGestureRecognizer:pan];
}

@end

.......
           

五、全屏滑動删除的處理方式 2 ——delegate

這種處理方式,其實有原因的,我們在建立一個手勢的時候,我們發現,我們添加的 target 和 delegate 是一樣的,那麼系統的應該也是一樣的。

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
pan.delegate = self;
           

是以需要的 target 其實就是delegate 。

id target = self.interactivePopGestureRecognizer.delegate;
           

但是如果我們這個添加了 會出現上面我們出現過的bug : 就是如果我們在根控制器上滑動了,那麼我們就 push 不了其他控制器了.

那麼怎麼解決呢?

我們可以添加 UIGestureRecognizerDelegate 代理。手指開始時去判斷是不是根控制器,如果是的話,那麼我們禁止手勢,如果不是我們響應手勢

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    return self.viewControllers.count > ;
}
           

完整代碼如下

//
//  QWMNavigationController.m
//  03_UIView79_彩票
//
//  Created by 杞文明 on 17/8/13.
//  Copyright © 2017年 杞文明. All rights reserved.
//

#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
/** 系統手勢代理 */
@property (nonatomic, strong) id popGesture;
@end

@implementation QWMNavigationController
-(void)viewDidLoad{
    [super viewDidLoad];
    id target = self.interactivePopGestureRecognizer.delegate;

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:target action:@selector(handleNavigationTransition:)];
    [self.view addGestureRecognizer:pan];
    pan.delegate = self;
}

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    return self.viewControllers.count > ;
}
@end
           

繼續閱讀