iOS Learning Notes - 095. Lottery 10 - Full Screen Implementation of Sliding Removal Controller

Posted by fekaduw on Thu, 30 May 2019 22:25:27 +0200

Lottery 10-Sliding Removal Controller Full Screen Implementation

I. illustration

Two, analysis

The original system has sliding deletion, but we added the playback button after no, then this is embarrassing. Then we can do it.

In fact, we only need to set the agent of the system gesture to nil to achieve such a function, but with this implementation, we can slide to the left without the navigation bar. And there's a bug that if we slide on the root controller, then we can't push other controllers. So how to solve it? In fact, the solution is very simple. We remember our agent at first, and then when did controller, we judge whether the current controller is the root controller, and if it is restored, it is not assigned to nil.

Another way to deal with this is to add a sliding gesture ourselves, and then we can use the system's processing method and targer to deal with this gesture.

3. Processing methods of non-full-screen sliding deletion

The result of this approach is that it can only be deleted when sliding from the left.

This approach requires adding UINavigation Controller Delegate agents

//
//  QWMNavigationController.m
//  03_UIView79_Lottery
//
//  Created by Qi Civilization on 17/8/13.
//  Copyright 2017 Qi Civilization. All rights reserved.
//

#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate>
/** System Gesture Agent */
@property (nonatomic, strong) id popGesture;
@end

@implementation QWMNavigationController

········

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

// Solve the problem that if you slide on the root controller, you can't delete it.
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    if(self.viewControllers[0]==viewController){//Root controller
        self.interactivePopGestureRecognizer.delegate = self.popGesture;
    }else{
        // Clear gesture agent can achieve sliding return, iOS6 does not support
        self.interactivePopGestureRecognizer.delegate = nil;
    }
}

·····

@end

4. Processing Method of Full Screen Sliding Delete 1-KVC

In this way, you add a sliding gesture UIPanGesture Recognizer to the target and action of the gesture and use the system gesture.

So let's use

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

Print out the system gesture information
as follows

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

From the above information, we can see that the action of the gesture we added is handleNavigation Transition: Method.
But we haven't got the target yet.

We use the runtime mechanism in oc to get our attribute names, and then use KVC to get our target

We use the runtime mechanism to print out the attributes in UIGesture Recognizer

// The OC runtime mechanism can only dynamically acquire the membership attributes of the current class, but cannot acquire the attributes of its subclass or parent class.
// _ unsafe_unretained Class to obtain which class's member properties
// unsigned int *outCount gets the number of all member attributes under Class

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

Print results

2017-08-26 16:21:36.885 03_UIView79_Lottery [12961:57679]_gesture Flags
 2017-08-26 16:21:36.885 03_UIView79_Lottery [12961:57679]_targets
 2017-08-26 16:21:36.885 03_UIView79_Lottery [12961:57679]_delayed Touches
 2017-08-26 16:21:36.886 03_UIView79_Lottery [12961:57679]_delayed Presses
 2017-08-26 16:21:36.886 03_UIView79_Lottery [12961:57679]_view
 2017-08-26 16:21:36.886 03_UIView79_Lottery [12961:57679]_lastTouch Timestamp
 2017-08-26 16:21:36.887 03_UIView79_Lottery [12961:57679]_state
 2017-08-26 16:21:36.887 03_UIView79_Lottery [12961:57679]_allowed TouchTypes
 2017-08-26 16:21:36.887 03_UIView79_Lottery [12961:57679]_initial TouchType
 2017-08-26 16:21:36.888 03_UIView79_Lottery [12961:57679]_Internal Active Touches
 2017-08-26 16:21:36.888 03_UIView79_Lottery [12961:57679]_force Classifier
 2017-08-26 16:21:36.888 03_UIView79_Lottery [12961:57679]_requiredPreview Force State
 2017-08-26 16:21:36.888 03_UIView79_Lottery [12961:57679]_Touch Force Observable
 2017-08-26 16:21:36.888 03_UIView79_Lottery [12961:57679]_Touch Force Observable AndClassifier Observation
 2017-08-26 16:21:36.888 03_UIView79_Lottery [12961:57679]_force Targets
 2017-08-26 16:21:36.888 03_UIView79_Lottery [12961:57679]_forcePress Count
 2017-08-26 16:21:36.889 03_UIView79_Lottery [12961:57679]_began Observable
 2017-08-26 16:21:36.889 03_UIView79_Lottery [12961:57679]_Failure Requirements
 2017-08-26 16:21:36.889 03_UIView79_Lottery [12961:57679]_Failure Dependents
 2017-08-26 16:21:36.889 03_UIView79_Lottery [12961:57679]_delegate
 2017-08-26 16:21:36.889 03_UIView79_Lottery [12961:57679]_allowedPressTypes
 2017-08-26 16:21:36.890 03_UIView79_Lottery [12961:57679]_gesture Environment

We can see that there is a - target attribute, and then we get this value through KVC, and print it out.

UIScreenEdgePanGestureRecognizer * gest = self.interactivePopGestureRecognizer;

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

NSLog(@"%@",targets);

Result

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

We can see that this is an array, but we still can't know our target.

Let's debug it and have a look. We will find that the original attribute is called _target.

Now that we know the attribute name, we can get it through KVC.

// Getting _target by KVC
    id target = [targets[0] valueForKeyPath:@"_target"];

Complete as follows

//
//  QWMNavigationController.m
//  03_UIView79_Lottery
//
//  Created by Qi Civilization on 17/8/13.
//  Copyright 2017 Qi Civilization. All rights reserved.
//

#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
/** System Gesture Agent */
@property (nonatomic, strong) id popGesture;
@end

@implementation QWMNavigationController

.......

-(void)viewDidLoad{
    [super viewDidLoad];

    UIScreenEdgePanGestureRecognizer * gest = self.interactivePopGestureRecognizer;

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

    // Getting _target by KVC
    id target = [targets[0] valueForKeyPath:@"_target"];

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

@end

.......

5. Processing Method of Full Screen Sliding Delete 2 - delegate

There's a reason for this. When we create a gesture, we find that the target we add is the same as the delegate, so the system should be the same.
as

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

So the target you need is actually delegate.

id target = self.interactivePopGestureRecognizer.delegate;

But if we add this, we'll have the bug we've seen above: if we slide on the root controller, then we can't push other controllers.

So how to solve it?

We can add UIGesture Recognizer Delegate agent. Fingers start by deciding if it's the root controller. If so, we forbid gestures, if not our response gestures.

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

The complete code is as follows

//
//  QWMNavigationController.m
//  03_UIView79_Lottery
//
//  Created by Qi Civilization on 17/8/13.
//  Copyright 2017 Qi Civilization. All rights reserved.
//

#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
/** System Gesture Agent */
@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 > 1;
}
@end

Topics: Attribute