2017-08-10 10:12:57 u010757842 阅读数 750

首先感谢作者,提供了完美的解决办法,讲解的非常的详细。原文地址 

我在这里只是为了帮助大家可以尽快的解决问题,稍微的总结下。


首先在页面中定义一个全局布尔值_flag,然后加入下面的代码,就能解决问题,html调用本地相册不再会调用dismiss返回上个页面。但是你点击返回按钮也失效了

- (UIViewController *)presentingViewController {
    if (_flag) {
        return nil;
    } else {
        return [super presentingViewController];
    }
}
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    if ([viewControllerToPresent isKindOfClass:[UIDocumentMenuViewController class]]
        ||[viewControllerToPresent isKindOfClass:[UIImagePickerController class]]) {
        _flag = YES;
    }
    
    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
}

解决模态跳转的页面WebView中加载html调用本地相册会dismiss和返回按钮dismiss失效办法(终极方案)

首先分别定义布尔值_flag和dismissBool 

-(void)clickHome//返回按钮的方法
{
    [self dismissViewControllerAnimated:YES completion:nil];
    dismissBool = YES;
}
-(UIViewController *)presentingViewController {
    if (!dismissBool) {
        if (_flag) {
            return nil;
        } else {
            return [super presentingViewController];
        }
    }else{
        return [super presentingViewController];
    }
    
}
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    if ([viewControllerToPresent isKindOfClass:[UIDocumentMenuViewController class]]
        ||[viewControllerToPresent isKindOfClass:[UIImagePickerController class]]) {
        _flag = YES;
    }
    
    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
}


2018-05-18 19:47:28 github_36843038 阅读数 1136

简介

现在越来越多的应用有看大图或者进入详情页面,但是,再返回的时候,普通意义上,会点击左上角的返回,这时候你就会发现,还需要将手指移动到左上角,这样,无意给用户增添了麻烦,并且,现在手机屏幕越来越大,这样返回的越来越困难,在体验上特别的差劲.

尽管苹果推出了从左边缘右滑返回,FDFullscreenPopGesture这个很强大的,全屏右滑返回…..尽管现在考虑到用户体验上,已经有了很大的提升,但是,仍然,在大屏上,不是很好操作…因为,你在正常使用手机的时候,大拇指使用的频率要远远大于其他手指,而且,大拇指,上下滑动的体验度是要大于左右滑动的体验度的…..所以,这里就有着下滑返回的需求必要的…

开始

解决完需求的原因,下面我们来看看如何做?

1.转场动画的设置

1. 遵循协议

需要转场的ViewCointroller遵循:UIViewControllerTransitioningDelegate

2. 转场代理设置

// 设置Presented的动画
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    return [[PresentVCAnimation alloc] init];
}

/// 设置Dismiss返回的动画设置
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    return [[DismissVCAnimation alloc] init];
}

/// 设置过场动画
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
    return (self.interactiveTransition.isInteracting ? self.interactiveTransition : nil);
}

2. PresentVCAnimation

PresentVCAnimation.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface PresentVCAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end

PresentVCAnimation.m

#import "PresentVCAnimation.h"

@implementation PresentVCAnimation
// 设置动画的时间长度
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.25;
}

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    // 前一个ViewController,动画的发起者
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    // 后一个ViewController,动画的结束者
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    // 转场动画的最终的frame
    CGRect finalFrameForVC = [transitionContext finalFrameForViewController:toVC];
    // 下面敲黑板啦
    // 转换的容器view,这里是存放转场动画的容器
    UIView *containerView = [transitionContext containerView];
    // 这里一般情况下,没有涉及到VC的View放大或者缩小,即可看做是屏幕的尺寸
    CGRect bounds = [UIScreen mainScreen].bounds;
    // 这是后一个ViewController的frame
    toVC.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height);
    [containerView addSubview:toVC.view];

    // 下面是改变前一个ViewController和后一个ViewController的动画
    [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
        fromVC.view.alpha = 0.5;
        toVC.view.frame = finalFrameForVC;
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];
        fromVC.view.alpha = 1.0;
    }];
}

-(void)animationEnded:(BOOL)transitionCompleted {
}

3.DismissVCAnimation

DismissVCAnimation.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DismissVCAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end

DismissVCAnimation.m

#import "DismissVCAnimation.h"

@implementation DismissVCAnimation
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.25;
}

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    // 前一个ViewController,动画的发起者
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    // 后一个ViewController,动画的结束者
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    CGRect screenBounds = [UIScreen mainScreen].bounds;
    // 获取前一个页面的frame
    CGRect initFrame = [transitionContext initialFrameForViewController:fromVC];
     // 转场动画的toView的最终的frame
    CGRect finalFrame = CGRectOffset(initFrame, 0, screenBounds.size.height);
    // 转换的容器view
    UIView *containerView = [transitionContext containerView];
    // 下面这里是为了让转场动画衔接的更和谐,不然,下滑一点距离就直接看到之前页面的内容,体验不好
    UIView *bgView = [[UIView alloc] initWithFrame:fromVC.view.bounds];
    bgView.backgroundColor = [UIColor blackColor];
    [toVC.view addSubview:bgView ];

    [containerView addSubview:toVC.view];
    [containerView sendSubviewToBack:toVC.view];

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        fromVC.view.frame = finalFrame;
        bgView.alpha = 0;
    } completion:^(BOOL finished) {
        [bgView removeFromSuperview];
        BOOL complate = [transitionContext transitionWasCancelled];
        [transitionContext completeTransition:(!complate)];
    }];
}

-(void)animationEnded:(BOOL)transitionCompleted {
}
@end

4.SwipeUpInteractiveTransition

这个是针对滑动手势对转场动画的影响的类.

这里面主要处理了滑动行为的状态,需要重点了解的是:
1.判断用户是不是存在返回意图的行为,这里面规定了两种行为,而这两种行为,均为在当前页面手势结束的时候处理

返回意图的行为的判断条件:

  • 当下滑距离大于当前屏幕比例的 0.382 (无耻的取了黄金比例的对半,因为,感觉有逼格,可进行相应调整)
  • 快速滑动行为,也就是滑动速度 : iOS开发–手势滑动的速度

SwipeUpInteractiveTransition.h

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface SwipeUpInteractiveTransition : UIPercentDrivenInteractiveTransition
/// 手势中...
@property (nonatomic, assign) BOOL isInteracting;
/// 完成动画
@property (nonatomic, assign) BOOL shouldComplete;
// 初始化
- (instancetype)initWithGestureViewController:(UIViewController *)gestureVC;
@end

SwipeUpInteractiveTransition.m

#define KEY_WINDOW  [[UIApplication sharedApplication].delegate window]

#import "SwipeUpInteractiveTransition.h"

@interface SwipeUpInteractiveTransition()
// 手势添加的View
@property (nonatomic, strong) UIViewController *gestureVC;
// 记录手势结束前的点击位置
@property (nonatomic, assign) CGPoint oldTranslation;
// 是不是需要返回,这里是需要猜想并判断用户是不是存在返回行为
@property (nonatomic, assign) BOOL isNeedDismiss;
@end

@implementation SwipeUpInteractiveTransition
- (instancetype)initWithGestureViewController:(UIViewController *)gestureVC
{
    self = [super init];
    if (self) {
        _gestureVC = gestureVC;
        // 添加手势
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureHandler:)];
        [_gestureVC.view addGestureRecognizer:pan];
    }
    return self;
}

- (void)panGestureHandler:(UIPanGestureRecognizer *)gesture {
    // 获取手势触控的点在作用View的相对位置
    CGPoint translation = [gesture translationInView:gesture.view];
    // 每次手势触发的时候,重置,也就是用户不存在返回意图
    self.isNeedDismiss = NO;
    switch (gesture.state) {
        case UIGestureRecognizerStateBegan: {
            // 手势开始
            // 交互动画判断
            _isInteracting = YES;
            [_gestureVC dismissViewControllerAnimated:YES completion:nil];

            break;
        }
        case UIGestureRecognizerStateChanged: {
        // 当前触控点的赋值
            self.oldTranslation = translation;
            // 触控点的转化,因为updateInteractiveTransition的参数范围是[0.1],所以这里需要左边比例的转换
            CGFloat fraction = (translation.y / KEY_WINDOW.bounds.size.height);
            // 保证范围
            fraction = fmin(fmaxf(fraction, 0.0), 1.0);
            // 这里进行滑动中的判断,取的是黄金比例,也就是,如果滑动距离占比约38%,即可判断用户存在返回的行为
            _shouldComplete = fraction > 0.382;
            // 更新进度
            [self updateInteractiveTransition:fraction];
            break;
        }
        case UIGestureRecognizerStateEnded: {
           // 这里是重要的判断
           // 如果用户存在快速向下滑动的行为(等同于全屏快速向右滑动返回的行为),self.isNeedDismiss为YES
           // 而这个判断的快速范围如下 
            CGPoint speed = [gesture velocityInView:gesture.view];
           // 这个数据经过了大量测试和舒适度的数据,大家可以参考,具体的还需要根据实际情况而定.可以看我的量
            if (speed.y >= 920) {
                self.isNeedDismiss = YES;
                _shouldComplete = YES;
            }
            // 手势交互结束
            _isInteracting = NO;
            // 下面进行之前判断的处理
            // 使用dispatch_source_t定时回调,进行改变self.oldTranslation的数据,进行模拟手势移动,因为如果直接调用[self cancelInteractiveTransition];或者[self updateInteractiveTransition:fraction];就会发现,动画瞬间变化,瞬间复位或者瞬间消失返回.考虑到用户体验,如下
            dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
            //定时器模式  事件源
            dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, quene);
            //NSEC_PER_SEC是秒,*1是每秒
            dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), NSEC_PER_SEC * 0.0001, 0);
            //设置响应dispatch源事件的block,在dispatch源指定的队列上运行
            dispatch_source_set_event_handler(timer, ^{
                //回调主线程,在主线程中操作UI
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (!_isNeedDismiss && (!_shouldComplete || gesture.state == UIGestureRecognizerStateCancelled)) {
                        if (self.oldTranslation.y <= 0) {
                        // 当满足条件,执行取消动画
                            [self cancelInteractiveTransition];
                            // 移除时间回调
                            dispatch_source_cancel(timer);
                        } else {
                        // 模拟上滑行为
                            CGFloat fraction = (self.oldTranslation.y / KEY_WINDOW.bounds.size.height);
                            fraction = fmin(fmaxf(fraction, 0.0), 1.0);
                            self.oldTranslation = CGPointMake(self.oldTranslation.x, self.oldTranslation.y - 0.3);

                            [self updateInteractiveTransition:fraction];
                        }
                    } else {
                        if (self.oldTranslation.y > KEY_WINDOW.bounds.size.height) {
                        // 当滑出当前屏幕,执行完成动画
                            [self finishInteractiveTransition];
                                                        // 移除时间回调
                            dispatch_source_cancel(timer);
                        } else {
                        // 模拟下滑行为
                            CGFloat fraction = (self.oldTranslation.y / KEY_WINDOW.bounds.size.height);
                            fraction = fmin(fmaxf(fraction, 0.0), 1.0);
                            self.oldTranslation = CGPointMake(self.oldTranslation.x, self.oldTranslation.y + 0.3);

                            [self updateInteractiveTransition:fraction];
                        }
                    }
                });
            });
            //启动源
            dispatch_resume(timer);
            break;
        }
        default:
            break;
    }
}
@end
2015-07-29 16:03:43 CHENYUFENG1991 阅读数 3665

     我们在之前的一篇博客中谈到如何使用dismissViewControllerAnimation()的方法在iOS中返回,现在我们有一个更为方便的方法来实现界面跳转之后的返回操作。使用的是Unwind Segue.具体实现步骤如下:

(1)分别在两个ViewController中创建一个按钮,一个作为跳转,一个作为返回,并且链接“跳转”按钮到第二个ViewController.整体界面布局如下:



(2)在第一个ViewController中写一个@IBAction修饰的close()的方法,方法只需要定义,不需要方法体。如下:


(3)来到storyboard中,点击鼠标右键拖拽“返回”按钮到该界面右上角的“Exit”图标处(该界面上方有三个图标,分别为View Controller,First Responder,Exit)。拖拽之后会出现Action Segue,选择下面出现的close即可。



(4)运行程序,发现两个界面能成功跳转和返回。是不是发现这种方法比调用dismissViewControllerAnimation() 更fashion呢?


github主页:https://github.com/chenyufeng1991  。欢迎大家访问!


2015-10-27 10:42:43 berlor 阅读数 1035

  有一 A  视图和B视图,A视图 上有 一 tableview 1,b上也有一 tableview 2.。  从a视图 跳转到 b ,并传 a视图 选择的 table 数据源 到b; b 修改后 ,dismiss 返回a 。 报错了!!!!

      找了半天   原来 在  a

       [self.navigationController presentViewController:wrnav animated:YES completion:nil] ;


时 将 a 的 数据源 直接 赋值给 b  了


         wrnav.stuarr2=_stuarr;

而 stuarr2 也没有初始化


所以在  b页面 修改了 stuarr2  实际上也是修改了 a的stuarr,在返回后  没有刷新页面 导致 点击cell时 remove 数据 找不到 而报错;



正确的做法是   NSMutableArray *stuarrcopy =[NSMutableArray arrayWithArray:_stuidarr];
  
   wrnav.stuarr2=stuarrcopy;


或者 在跳回来后 刷新table view;



  

  

2019-07-10 01:57:10 u010639530 阅读数 160

废话

对于模态出来的viewcontroller,我们往往无法使用侧滑返回功能。但是我们都知道可以用dismiss去返回,不过对于大部分用户大大来说并不关心什么模态不模态的,我既然花了学习成本去熟悉你这种侧滑就给返回的交互,你必须给劳资实现。OK,这里给大家介绍一种简单不能再简单的方法,我不是diss在座的各位,我是希望在座的各位大神来diss我,因为我还是个小学森。

正文

首先,

你的iOS程序的架构中必不可少有个baseViewController去被它的儿子们继承吧,没有的话赶紧去重写,有了这个baseViewController真的方便很多,你可以把tableView的创建和代理、和DataSource、和自定义navigationBar、和statusBar、和。。。等等暂时写在这里哦,如图。

@interface OriginalDetailVC : BaseViewController

@property (nonatomic, strong) NSString * sid;

@end

然后,

这个baseViewController里面必然需要有个各位儿子们都要返回的实例方法,暂时方法名就叫 backAction好了,代码的逻辑蠢萌蠢萌的,大致就是能让我pop回去呢我就pop回去,能让我dismiss回去我就dismiss,如图。

// MARK: - 返回
- (void)backAction
{
    if ([self.navigationController respondsToSelector:@selector(popViewControllerAnimated:)]) {
        [self.navigationController popViewControllerAnimated:YES];
    }
    if ([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

再然后,

为这个父亲大人(baseViewController)的view添加滑动手势 UIPanGestureRecognizer,当然,如果你有点儿偏心,不希望每个儿子都有这个技能,你可以去特定的儿子那里添加侧滑手势,手势的目标方法咱们就叫 rightPanAction: 好了,如图。

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

再再然后,

去把这个方法 rightPanAction: 实现吧,后面就很easy了,把手势滑出的x轴坐标拿出来,你想要让它滑动多少才返回,你就判断多少,以我多年的经验,乔帮主可能会认为超过 100就可以返回了,当然这个返回方法还是上面那个 backAction实例方法,不用担心回不回得去,因为我们已经做了蠢萌的判断了,如图。

- (void)rightPanAction:(UIPanGestureRecognizer *)gest
{
    CGPoint gestPoint = [gest translationInView:self.view];
    if (gestPoint.x > 100) {
        [self backAction];
    }
}

完事儿

也许很简单,但是还挺好用的,求diss ^_^

dismiss到跟视图

阅读数 371

没有更多推荐了,返回首页