You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
12 KiB
336 lines
12 KiB
// |
|
// DLSlideView.m |
|
// DLSlideController |
|
// |
|
// Created by Dongle Su on 14-12-7. |
|
// Copyright (c) 2014年 dongle. All rights reserved. |
|
// |
|
|
|
#import "DLSlideView.h" |
|
|
|
#define kPanSwitchOffsetThreshold 50.0f |
|
|
|
@implementation DLSlideView{ |
|
NSInteger oldIndex_; |
|
NSInteger panToIndex_; |
|
UIPanGestureRecognizer *pan_; |
|
CGPoint panStartPoint_; |
|
|
|
UIViewController *oldCtrl_; |
|
UIViewController *willCtrl_; |
|
|
|
BOOL isSwitching_; |
|
} |
|
|
|
- (void)commonInit{ |
|
oldIndex_ = -1; |
|
isSwitching_ = NO; |
|
|
|
pan_ = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHandler:)]; |
|
[self addGestureRecognizer:pan_]; |
|
} |
|
|
|
- (id)initWithCoder:(NSCoder *)aDecoder{ |
|
if (self = [super initWithCoder:aDecoder]) { |
|
[self commonInit]; |
|
} |
|
return self; |
|
} |
|
|
|
- (id)initWithFrame:(CGRect)frame{ |
|
if (self = [super initWithFrame:frame]) { |
|
[self commonInit]; |
|
} |
|
return self; |
|
} |
|
|
|
- (NSInteger)selectedIndex{ |
|
return oldIndex_; |
|
} |
|
- (void)setSelectedIndex:(NSInteger)selectedIndex{ |
|
if (selectedIndex != oldIndex_) { |
|
[self switchTo:selectedIndex]; |
|
} |
|
} |
|
//- (void)setViewControllers:(NSArray *)vcs{ |
|
// _viewControllers = vcs; |
|
//} |
|
|
|
- (void)removeOld{ |
|
[self removeCtrl:oldCtrl_]; |
|
[oldCtrl_ endAppearanceTransition]; |
|
oldCtrl_ = nil; |
|
oldIndex_ = -1; |
|
} |
|
- (void)removeWill{ |
|
[willCtrl_ beginAppearanceTransition:NO animated:NO]; |
|
[self removeCtrl:willCtrl_]; |
|
[willCtrl_ endAppearanceTransition]; |
|
willCtrl_ = nil; |
|
panToIndex_ = -1; |
|
} |
|
- (void)showAt:(NSInteger)index{ |
|
if (oldIndex_ != index) { |
|
//[self removeAt:oldIndex_]; |
|
[self removeOld]; |
|
|
|
UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:index]; |
|
[self.baseViewController addChildViewController:vc]; |
|
vc.view.frame = self.bounds; |
|
[self addSubview:vc.view]; |
|
[vc didMoveToParentViewController:self.baseViewController]; |
|
oldIndex_ = index; |
|
oldCtrl_ = vc; |
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:didSwitchTo:)]) { |
|
[self.delegate DLSlideView:self didSwitchTo:index]; |
|
} |
|
} |
|
} |
|
|
|
- (void)removeCtrl:(UIViewController *)ctrl{ |
|
UIViewController *vc = ctrl; |
|
[vc willMoveToParentViewController:nil]; |
|
[vc.view removeFromSuperview]; |
|
[vc removeFromParentViewController]; |
|
} |
|
|
|
//- (void)removeAt:(int)index{ |
|
// if (oldIndex_ == index) { |
|
// oldIndex_ = -1; |
|
// } |
|
// |
|
// if (index >= 0 && index <= [self.dataSource numberOfControllersInDLSlideView:self]) { |
|
// UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:index]; |
|
// [vc willMoveToParentViewController:nil]; |
|
// [vc.view removeFromSuperview]; |
|
// [vc removeFromParentViewController]; |
|
// } |
|
//} |
|
- (void)switchTo:(NSInteger)index{ |
|
if (index == oldIndex_) { |
|
return; |
|
} |
|
if (isSwitching_) { |
|
return; |
|
} |
|
|
|
if (oldCtrl_ != nil && oldCtrl_.parentViewController == self.baseViewController) { |
|
isSwitching_ = YES; |
|
//UIViewController *oldvc = [self.dataSource DLSlideView:self controllerAt:oldIndex_];; |
|
UIViewController *oldvc = oldCtrl_; |
|
UIViewController *newvc = [self.dataSource DLSlideView:self controllerAt:index]; |
|
|
|
[oldvc willMoveToParentViewController:nil]; |
|
[self.baseViewController addChildViewController:newvc]; |
|
|
|
CGRect nowRect = oldvc.view.frame; |
|
CGRect leftRect = CGRectMake(nowRect.origin.x-nowRect.size.width, nowRect.origin.y, nowRect.size.width, nowRect.size.height); |
|
CGRect rightRect = CGRectMake(nowRect.origin.x+nowRect.size.width, nowRect.origin.y, nowRect.size.width, nowRect.size.height); |
|
|
|
CGRect newStartRect; |
|
CGRect oldEndRect; |
|
if (index > oldIndex_) { |
|
newStartRect = rightRect; |
|
oldEndRect = leftRect; |
|
} |
|
else{ |
|
newStartRect = leftRect; |
|
oldEndRect = rightRect; |
|
} |
|
|
|
newvc.view.frame = newStartRect; |
|
[newvc willMoveToParentViewController:self.baseViewController]; |
|
|
|
[self.baseViewController transitionFromViewController:oldvc toViewController:newvc duration:0.4 options:0 animations:^{ |
|
newvc.view.frame = nowRect; |
|
oldvc.view.frame = oldEndRect; |
|
} completion:^(BOOL finished) { |
|
[oldvc removeFromParentViewController]; |
|
[newvc didMoveToParentViewController:self.baseViewController]; |
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:didSwitchTo:)]) { |
|
[self.delegate DLSlideView:self didSwitchTo:index]; |
|
} |
|
|
|
isSwitching_ = NO; |
|
}]; |
|
|
|
oldIndex_ = index; |
|
oldCtrl_ = newvc; |
|
} |
|
else{ |
|
[self showAt:index]; |
|
} |
|
|
|
willCtrl_ = nil; |
|
panToIndex_ = -1; |
|
} |
|
|
|
- (void)repositionForOffsetX:(CGFloat)offsetx{ |
|
float x = 0.0f; |
|
|
|
if (panToIndex_ < oldIndex_) { |
|
x = self.bounds.origin.x - self.bounds.size.width + offsetx; |
|
} |
|
else if(panToIndex_ > oldIndex_){ |
|
x = self.bounds.origin.x + self.bounds.size.width + offsetx; |
|
} |
|
|
|
//UIViewController *oldvc = [self.dataSource DLSlideView:self controllerAt:oldIndex_]; |
|
UIViewController *oldvc = oldCtrl_; |
|
oldvc.view.frame = CGRectMake(self.bounds.origin.x + offsetx, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)); |
|
|
|
if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self]) { |
|
//UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:panToIndex_]; |
|
UIViewController *vc = willCtrl_; |
|
vc.view.frame = CGRectMake(x, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)); |
|
// if (vc.parentViewController == nil) { |
|
// |
|
// [self.baseViewController addChildViewController:vc]; |
|
// [vc willMoveToParentViewController:self.baseViewController]; |
|
// [vc beginAppearanceTransition:YES animated:YES]; |
|
// [self addSubview:vc.view]; |
|
// //[vc didMoveToParentViewController:self.baseViewController]; |
|
// } |
|
} |
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:switchingFrom:to:percent:)]) { |
|
[self.delegate DLSlideView:self switchingFrom:oldIndex_ to:panToIndex_ percent:fabs(offsetx)/self.bounds.size.width]; |
|
} |
|
} |
|
|
|
- (void)backToOldWithOffset:(CGFloat)offsetx{ |
|
NSTimeInterval animatedTime = 0; |
|
animatedTime = 0.3; |
|
|
|
//animatedTime = fabs(self.frame.size.width - fabs(offsetx)) / self.frame.size.width * 0.35; |
|
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; |
|
[UIView animateWithDuration:animatedTime animations:^{ |
|
[self repositionForOffsetX:0]; |
|
} completion:^(BOOL finished) { |
|
if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self] && panToIndex_ != oldIndex_) { |
|
//[self removeAt:panToIndex_]; |
|
[oldCtrl_ beginAppearanceTransition:YES animated:NO]; |
|
[self removeWill]; |
|
[oldCtrl_ endAppearanceTransition]; |
|
} |
|
if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:switchCanceled:)]) { |
|
[self.delegate DLSlideView:self switchCanceled:oldIndex_]; |
|
} |
|
}]; |
|
|
|
// [UIView animateWithDuration:animatedTime delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ |
|
// float pantox = 0.0f; |
|
// if (offsetx > 0) { |
|
// pantox = -self.bounds.size.width; |
|
// } |
|
// else{ |
|
// pantox = self.bounds.size.width; |
|
// } |
|
// |
|
// //UIViewController *oldvc = [self.dataSource DLSlideView:self controllerAt:oldIndex_];; |
|
// UIViewController *oldvc = oldCtrl_; |
|
// oldvc.view.frame = CGRectMake(0, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)); |
|
// if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self]) { |
|
// //UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:panToIndex_]; |
|
// UIViewController *vc = willCtrl_; |
|
// vc.view.frame = CGRectMake(pantox, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)); |
|
// } |
|
// } completion:^(BOOL finished) { |
|
// if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self] && panToIndex_ != oldIndex_) { |
|
// //[self removeAt:panToIndex_]; |
|
// [self removeWill]; |
|
// } |
|
// }]; |
|
|
|
} |
|
- (void)panHandler:(UIPanGestureRecognizer *)pan{ |
|
if (oldIndex_ < 0) { |
|
return; |
|
} |
|
|
|
CGPoint point = [pan translationInView:self]; |
|
|
|
if (pan.state == UIGestureRecognizerStateBegan) { |
|
panStartPoint_ = point; |
|
//[oldCtrl_ willMoveToParentViewController:nil]; |
|
[oldCtrl_ beginAppearanceTransition:NO animated:YES]; |
|
} |
|
else if (pan.state == UIGestureRecognizerStateChanged){ |
|
NSInteger panToIndex = -1; |
|
float offsetx = point.x - panStartPoint_.x; |
|
|
|
if (offsetx > 0) { |
|
panToIndex = oldIndex_ - 1; |
|
} |
|
else if(offsetx < 0){ |
|
panToIndex = oldIndex_ + 1; |
|
} |
|
|
|
// fix bug #5 |
|
if (panToIndex != panToIndex_) { |
|
if (willCtrl_) { |
|
[self removeWill]; |
|
} |
|
} |
|
|
|
if (panToIndex < 0 || panToIndex >= [self.dataSource numberOfControllersInDLSlideView:self]) { |
|
panToIndex_ = panToIndex; |
|
[self repositionForOffsetX:offsetx/2.0f]; |
|
} |
|
else{ |
|
if (panToIndex != panToIndex_) { |
|
//fix bug #5 |
|
// if (willCtrl_) { |
|
// [self removeWill]; |
|
// } |
|
willCtrl_ = [self.dataSource DLSlideView:self controllerAt:panToIndex]; |
|
[self.baseViewController addChildViewController:willCtrl_]; |
|
[willCtrl_ willMoveToParentViewController:self.baseViewController]; |
|
[willCtrl_ beginAppearanceTransition:YES animated:YES]; |
|
[self addSubview:willCtrl_.view]; |
|
|
|
panToIndex_ = panToIndex; |
|
} |
|
[self repositionForOffsetX:offsetx]; |
|
} |
|
} |
|
else if (pan.state == UIGestureRecognizerStateEnded){ |
|
float offsetx = point.x - panStartPoint_.x; |
|
|
|
if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self] && panToIndex_ != oldIndex_) { |
|
if (fabs(offsetx) > kPanSwitchOffsetThreshold) { |
|
NSTimeInterval animatedTime = 0; |
|
animatedTime = fabs(self.frame.size.width - fabs(offsetx)) / self.frame.size.width * 0.4; |
|
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; |
|
[UIView animateWithDuration:animatedTime animations:^{ |
|
[self repositionForOffsetX:offsetx > 0 ? self.bounds.size.width : -self.bounds.size.width]; |
|
} completion:^(BOOL finished) { |
|
//[self removeAt:oldIndex_]; |
|
[self removeOld]; |
|
|
|
if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self]) { |
|
[willCtrl_ endAppearanceTransition]; |
|
[willCtrl_ didMoveToParentViewController:self.baseViewController]; |
|
oldIndex_ = panToIndex_; |
|
oldCtrl_ = willCtrl_; |
|
willCtrl_ = nil; |
|
panToIndex_ = -1; |
|
} |
|
if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:didSwitchTo:)]) { |
|
[self.delegate DLSlideView:self didSwitchTo:oldIndex_]; |
|
} |
|
}]; |
|
} |
|
else{ |
|
[self backToOldWithOffset:offsetx]; |
|
} |
|
} |
|
else{ |
|
[self backToOldWithOffset:offsetx]; |
|
} |
|
} |
|
} |
|
|
|
@end
|
|
|