通过 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/