ios - View Controller 之间的交互转换?

标签 ios cocoa-touch uiviewcontroller

通过 UIView 动画 API 和 View Controller 包含,当前的 Cocoa Touch 堆栈非常适合 View Controller 之间的自动转换。

我发现很难写的是 View Controller 之间的交互式 转换。例如,当我只想使用推送动画将一个 View 替换为另一个 View 时,我可以使用 UINavigationController 或使用包含 API 并自己编写转换。但我通常希望过渡是交互式的、触摸控制的:用户开始拖动当前 View ,传入 View 从侧面出现,过渡由平移触摸手势控制。用户只需平移一点即可“窥视”传入的 View ,然后向后平移,保持当前 View 可见。如果手势在某个阈值以下结束,则过渡将被取消,否则将完成。

(如果这还不够清楚,我说的是类似于 iBooks 中的翻页,但在不同的 View Controller 之间,并且泛化到任何此类交互式转换。)

我知道如何编写这样的过渡,但是当前的 View Controller 必须对过渡了解太多——它占用了太多的代码。更不用说可以很容易地实现两种不同的交互式转换,在这种情况下,所讨论的 Controller 充满了转换代码,并与之紧密耦合。

是否有一种模式可以抽象、概括交互式转换代码并将其移动到单独的类或代码块中?甚至可能是图书馆?

最佳答案

我不知道有任何库可以执行此操作,但我已经使用 UIViewController 上的类别或通过为我的 View Controller 创建一个包含转换代码的基类来抽象出转换代码。我将所有困惑的转换代码保留在基类中,而在我的 Controller 中,我只需要添加一个手势识别器并从其操作方法中调用基类方法。

-(IBAction)dragInController:(UIPanGestureRecognizer *)sender {
    [self dragController:[self.storyboard instantiateViewControllerWithIdentifier:@"GenericVC"] sender:sender];
}

编辑后:

这是我的尝试之一。这是 DragIntoBaseVC 中的代码,它是另一个 Controller 需要继承的 Controller ,以便使用上面的代码将 View 拖入其中。这只处理拖入(仅从右侧),而不处理拖出(仍在处理那个,以及如何使这个在方向上更通用)。很多代码都在那里处理旋转。它适用于任何方向(倒置除外),并且适用于 iPhone 和 iPad。我通过动 Canvas 局约束而不是设置框架来制作动画,因为这似乎是 Apple 的发展方向(我怀疑他们将来会贬低旧的 struts 和 springs 系统)。

#import "DragIntoBaseVC.h"

@interface DragIntoBaseVC ()
@property (strong,nonatomic) NSLayoutConstraint *leftCon;
@property (strong,nonatomic) UIViewController *incomingVC;
@property (nonatomic) NSInteger w;
@end

@implementation DragIntoBaseVC

static int first = 1;


-(void)dragController:(UIViewController *) incomingVC sender:(UIPanGestureRecognizer *) sender {
    if (first) {
        self.incomingVC = incomingVC;
        UIView *inView = incomingVC.view;
        [inView setTranslatesAutoresizingMaskIntoConstraints:NO];
        inView.transform = self.view.transform;
        [self.view.window addSubview:inView];
        self.w = self.view.bounds.size.width;
        NSLayoutConstraint *con2;

        switch ([UIDevice currentDevice].orientation) {
            case 0:
            case 1:
                self.leftCon = [NSLayoutConstraint constraintWithItem:inView attribute:NSLayoutAttributeLeft relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.w];
                con2 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTop relatedBy:0 toItem:inView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
                break;
            case 3:
                self.leftCon = [NSLayoutConstraint constraintWithItem:inView attribute:NSLayoutAttributeBottom relatedBy:0 toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:self.w];
                con2 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeLeft relatedBy:0 toItem:inView attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
                break;
            case 4:
                self.leftCon = [NSLayoutConstraint constraintWithItem:inView attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:-self.w];
                con2 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeRight relatedBy:0 toItem:inView attribute:NSLayoutAttributeRight multiplier:1 constant:0];
                break;
            default:
                break;
        }
        
        NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:0 toItem:inView attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
        NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:0 toItem:inView attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
        
        NSArray *constraints = @[self.leftCon,con2,con3,con4];
        [self.view.window addConstraints:constraints];
        first = 0;
    }
    
    CGPoint translate = [sender translationInView:self.view];
    if ([UIDevice currentDevice].orientation == 0 || [UIDevice currentDevice].orientation == 1 || [UIDevice currentDevice].orientation == 3) { // for portrait or landscapeRight
        if (sender.state == UIGestureRecognizerStateBegan || sender.state == UIGestureRecognizerStateChanged) {
            self.leftCon.constant += translate.x;
            [sender setTranslation:CGPointZero inView:self.view];
            
        }else if (sender.state == UIGestureRecognizerStateEnded){
            if (self.leftCon.constant < self.w/2) {
                [self.view removeGestureRecognizer:sender];
                [self finishTransition];
            }else{
                [self abortTransition:1];
            }
        }

    }else{ // for landscapeLeft
        if (sender.state == UIGestureRecognizerStateBegan || sender.state == UIGestureRecognizerStateChanged) {
            self.leftCon.constant -= translate.x;
            [sender setTranslation:CGPointZero inView:self.view];
            
        }else if (sender.state == UIGestureRecognizerStateEnded){
            if (-self.leftCon.constant < self.w/2) {
                [self.view removeGestureRecognizer:sender];
                [self finishTransition];
            }else{
                [self abortTransition:-1];
            }
        }
    }
}



-(void)finishTransition {
    self.leftCon.constant = 0;
    [UIView animateWithDuration:.3 animations:^{
        [self.view.window layoutSubviews];
    } completion:^(BOOL finished) {
        self.view.window.rootViewController = self.incomingVC;
    }];
}



-(void)abortTransition:(int) sign {
    self.leftCon.constant = self.w * sign;
    [UIView animateWithDuration:.3 animations:^{
        [self.view.window layoutSubviews];
    } completion:^(BOOL finished) {
        [self.incomingVC.view removeFromSuperview]; // this line and the next reset the system back to the inital state.
        first = 1;
    }];
}

关于ios - View Controller 之间的交互转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15543874/

相关文章:

iPhone重新加载表数据

android - XMPP FileTransfer - 为什么字节流协议(protocol)失败?

ios - 我如何创建一个具有两个数据源的 UITableView

ios - 应用程序因要求用户注册而被拒绝(指南 5.1.1)

ios - iPad 浏览量 "frame"

ios - 不使用 MFMailComposeViewController 发送电子邮件

ios - 如何使用 Storyboard在界面构建器中编辑手动添加的 UINavigationBar subview ?

swift - 初始 View Controller 应该调用 "deinit"吗?

iphone - popToRootViewController 时出现奇怪的错误

ios - 在 UITableViewCell 中播放视频