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

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