DLSlideView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. //
  2. // DLSlideView.m
  3. // DLSlideController
  4. //
  5. // Created by Dongle Su on 14-12-7.
  6. // Copyright (c) 2014年 dongle. All rights reserved.
  7. //
  8. #import "DLSlideView.h"
  9. #define kPanSwitchOffsetThreshold 50.0f
  10. @implementation DLSlideView{
  11. NSInteger oldIndex_;
  12. NSInteger panToIndex_;
  13. UIPanGestureRecognizer *pan_;
  14. CGPoint panStartPoint_;
  15. UIViewController *oldCtrl_;
  16. UIViewController *willCtrl_;
  17. BOOL isSwitching_;
  18. }
  19. - (void)commonInit{
  20. oldIndex_ = -1;
  21. isSwitching_ = NO;
  22. pan_ = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHandler:)];
  23. [self addGestureRecognizer:pan_];
  24. }
  25. - (id)initWithCoder:(NSCoder *)aDecoder{
  26. if (self = [super initWithCoder:aDecoder]) {
  27. [self commonInit];
  28. }
  29. return self;
  30. }
  31. - (id)initWithFrame:(CGRect)frame{
  32. if (self = [super initWithFrame:frame]) {
  33. [self commonInit];
  34. }
  35. return self;
  36. }
  37. - (NSInteger)selectedIndex{
  38. return oldIndex_;
  39. }
  40. - (void)setSelectedIndex:(NSInteger)selectedIndex{
  41. if (selectedIndex != oldIndex_) {
  42. [self switchTo:selectedIndex];
  43. }
  44. }
  45. //- (void)setViewControllers:(NSArray *)vcs{
  46. // _viewControllers = vcs;
  47. //}
  48. - (void)removeOld{
  49. [self removeCtrl:oldCtrl_];
  50. [oldCtrl_ endAppearanceTransition];
  51. oldCtrl_ = nil;
  52. oldIndex_ = -1;
  53. }
  54. - (void)removeWill{
  55. [willCtrl_ beginAppearanceTransition:NO animated:NO];
  56. [self removeCtrl:willCtrl_];
  57. [willCtrl_ endAppearanceTransition];
  58. willCtrl_ = nil;
  59. panToIndex_ = -1;
  60. }
  61. - (void)showAt:(NSInteger)index{
  62. if (oldIndex_ != index) {
  63. //[self removeAt:oldIndex_];
  64. [self removeOld];
  65. UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:index];
  66. [self.baseViewController addChildViewController:vc];
  67. vc.view.frame = self.bounds;
  68. [self addSubview:vc.view];
  69. [vc didMoveToParentViewController:self.baseViewController];
  70. oldIndex_ = index;
  71. oldCtrl_ = vc;
  72. if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:didSwitchTo:)]) {
  73. [self.delegate DLSlideView:self didSwitchTo:index];
  74. }
  75. }
  76. }
  77. - (void)removeCtrl:(UIViewController *)ctrl{
  78. UIViewController *vc = ctrl;
  79. [vc willMoveToParentViewController:nil];
  80. [vc.view removeFromSuperview];
  81. [vc removeFromParentViewController];
  82. }
  83. //- (void)removeAt:(int)index{
  84. // if (oldIndex_ == index) {
  85. // oldIndex_ = -1;
  86. // }
  87. //
  88. // if (index >= 0 && index <= [self.dataSource numberOfControllersInDLSlideView:self]) {
  89. // UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:index];
  90. // [vc willMoveToParentViewController:nil];
  91. // [vc.view removeFromSuperview];
  92. // [vc removeFromParentViewController];
  93. // }
  94. //}
  95. - (void)switchTo:(NSInteger)index{
  96. if (index == oldIndex_) {
  97. return;
  98. }
  99. if (isSwitching_) {
  100. return;
  101. }
  102. if (oldCtrl_ != nil && oldCtrl_.parentViewController == self.baseViewController) {
  103. isSwitching_ = YES;
  104. //UIViewController *oldvc = [self.dataSource DLSlideView:self controllerAt:oldIndex_];;
  105. UIViewController *oldvc = oldCtrl_;
  106. UIViewController *newvc = [self.dataSource DLSlideView:self controllerAt:index];
  107. [oldvc willMoveToParentViewController:nil];
  108. [self.baseViewController addChildViewController:newvc];
  109. CGRect nowRect = oldvc.view.frame;
  110. CGRect leftRect = CGRectMake(nowRect.origin.x-nowRect.size.width, nowRect.origin.y, nowRect.size.width, nowRect.size.height);
  111. CGRect rightRect = CGRectMake(nowRect.origin.x+nowRect.size.width, nowRect.origin.y, nowRect.size.width, nowRect.size.height);
  112. CGRect newStartRect;
  113. CGRect oldEndRect;
  114. if (index > oldIndex_) {
  115. newStartRect = rightRect;
  116. oldEndRect = leftRect;
  117. }
  118. else{
  119. newStartRect = leftRect;
  120. oldEndRect = rightRect;
  121. }
  122. newvc.view.frame = newStartRect;
  123. [newvc willMoveToParentViewController:self.baseViewController];
  124. [self.baseViewController transitionFromViewController:oldvc toViewController:newvc duration:0.4 options:0 animations:^{
  125. newvc.view.frame = nowRect;
  126. oldvc.view.frame = oldEndRect;
  127. } completion:^(BOOL finished) {
  128. [oldvc removeFromParentViewController];
  129. [newvc didMoveToParentViewController:self.baseViewController];
  130. if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:didSwitchTo:)]) {
  131. [self.delegate DLSlideView:self didSwitchTo:index];
  132. }
  133. isSwitching_ = NO;
  134. }];
  135. oldIndex_ = index;
  136. oldCtrl_ = newvc;
  137. }
  138. else{
  139. [self showAt:index];
  140. }
  141. willCtrl_ = nil;
  142. panToIndex_ = -1;
  143. }
  144. - (void)repositionForOffsetX:(CGFloat)offsetx{
  145. float x = 0.0f;
  146. if (panToIndex_ < oldIndex_) {
  147. x = self.bounds.origin.x - self.bounds.size.width + offsetx;
  148. }
  149. else if(panToIndex_ > oldIndex_){
  150. x = self.bounds.origin.x + self.bounds.size.width + offsetx;
  151. }
  152. //UIViewController *oldvc = [self.dataSource DLSlideView:self controllerAt:oldIndex_];
  153. UIViewController *oldvc = oldCtrl_;
  154. oldvc.view.frame = CGRectMake(self.bounds.origin.x + offsetx, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
  155. if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self]) {
  156. //UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:panToIndex_];
  157. UIViewController *vc = willCtrl_;
  158. vc.view.frame = CGRectMake(x, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
  159. // if (vc.parentViewController == nil) {
  160. //
  161. // [self.baseViewController addChildViewController:vc];
  162. // [vc willMoveToParentViewController:self.baseViewController];
  163. // [vc beginAppearanceTransition:YES animated:YES];
  164. // [self addSubview:vc.view];
  165. // //[vc didMoveToParentViewController:self.baseViewController];
  166. // }
  167. }
  168. if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:switchingFrom:to:percent:)]) {
  169. [self.delegate DLSlideView:self switchingFrom:oldIndex_ to:panToIndex_ percent:fabs(offsetx)/self.bounds.size.width];
  170. }
  171. }
  172. - (void)backToOldWithOffset:(CGFloat)offsetx{
  173. NSTimeInterval animatedTime = 0;
  174. animatedTime = 0.3;
  175. //animatedTime = fabs(self.frame.size.width - fabs(offsetx)) / self.frame.size.width * 0.35;
  176. [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
  177. [UIView animateWithDuration:animatedTime animations:^{
  178. [self repositionForOffsetX:0];
  179. } completion:^(BOOL finished) {
  180. if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self] && panToIndex_ != oldIndex_) {
  181. //[self removeAt:panToIndex_];
  182. [oldCtrl_ beginAppearanceTransition:YES animated:NO];
  183. [self removeWill];
  184. [oldCtrl_ endAppearanceTransition];
  185. }
  186. if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:switchCanceled:)]) {
  187. [self.delegate DLSlideView:self switchCanceled:oldIndex_];
  188. }
  189. }];
  190. // [UIView animateWithDuration:animatedTime delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
  191. // float pantox = 0.0f;
  192. // if (offsetx > 0) {
  193. // pantox = -self.bounds.size.width;
  194. // }
  195. // else{
  196. // pantox = self.bounds.size.width;
  197. // }
  198. //
  199. // //UIViewController *oldvc = [self.dataSource DLSlideView:self controllerAt:oldIndex_];;
  200. // UIViewController *oldvc = oldCtrl_;
  201. // oldvc.view.frame = CGRectMake(0, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
  202. // if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self]) {
  203. // //UIViewController *vc = [self.dataSource DLSlideView:self controllerAt:panToIndex_];
  204. // UIViewController *vc = willCtrl_;
  205. // vc.view.frame = CGRectMake(pantox, self.bounds.origin.y, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
  206. // }
  207. // } completion:^(BOOL finished) {
  208. // if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self] && panToIndex_ != oldIndex_) {
  209. // //[self removeAt:panToIndex_];
  210. // [self removeWill];
  211. // }
  212. // }];
  213. }
  214. - (void)panHandler:(UIPanGestureRecognizer *)pan{
  215. if (oldIndex_ < 0) {
  216. return;
  217. }
  218. CGPoint point = [pan translationInView:self];
  219. if (pan.state == UIGestureRecognizerStateBegan) {
  220. panStartPoint_ = point;
  221. //[oldCtrl_ willMoveToParentViewController:nil];
  222. [oldCtrl_ beginAppearanceTransition:NO animated:YES];
  223. }
  224. else if (pan.state == UIGestureRecognizerStateChanged){
  225. NSInteger panToIndex = -1;
  226. float offsetx = point.x - panStartPoint_.x;
  227. if (offsetx > 0) {
  228. panToIndex = oldIndex_ - 1;
  229. }
  230. else if(offsetx < 0){
  231. panToIndex = oldIndex_ + 1;
  232. }
  233. // fix bug #5
  234. if (panToIndex != panToIndex_) {
  235. if (willCtrl_) {
  236. [self removeWill];
  237. }
  238. }
  239. if (panToIndex < 0 || panToIndex >= [self.dataSource numberOfControllersInDLSlideView:self]) {
  240. panToIndex_ = panToIndex;
  241. [self repositionForOffsetX:offsetx/2.0f];
  242. }
  243. else{
  244. if (panToIndex != panToIndex_) {
  245. //fix bug #5
  246. // if (willCtrl_) {
  247. // [self removeWill];
  248. // }
  249. willCtrl_ = [self.dataSource DLSlideView:self controllerAt:panToIndex];
  250. [self.baseViewController addChildViewController:willCtrl_];
  251. [willCtrl_ willMoveToParentViewController:self.baseViewController];
  252. [willCtrl_ beginAppearanceTransition:YES animated:YES];
  253. [self addSubview:willCtrl_.view];
  254. panToIndex_ = panToIndex;
  255. }
  256. [self repositionForOffsetX:offsetx];
  257. }
  258. }
  259. else if (pan.state == UIGestureRecognizerStateEnded){
  260. float offsetx = point.x - panStartPoint_.x;
  261. if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self] && panToIndex_ != oldIndex_) {
  262. if (fabs(offsetx) > kPanSwitchOffsetThreshold) {
  263. NSTimeInterval animatedTime = 0;
  264. animatedTime = fabs(self.frame.size.width - fabs(offsetx)) / self.frame.size.width * 0.4;
  265. [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
  266. [UIView animateWithDuration:animatedTime animations:^{
  267. [self repositionForOffsetX:offsetx > 0 ? self.bounds.size.width : -self.bounds.size.width];
  268. } completion:^(BOOL finished) {
  269. //[self removeAt:oldIndex_];
  270. [self removeOld];
  271. if (panToIndex_ >= 0 && panToIndex_ < [self.dataSource numberOfControllersInDLSlideView:self]) {
  272. [willCtrl_ endAppearanceTransition];
  273. [willCtrl_ didMoveToParentViewController:self.baseViewController];
  274. oldIndex_ = panToIndex_;
  275. oldCtrl_ = willCtrl_;
  276. willCtrl_ = nil;
  277. panToIndex_ = -1;
  278. }
  279. if (self.delegate && [self.delegate respondsToSelector:@selector(DLSlideView:didSwitchTo:)]) {
  280. [self.delegate DLSlideView:self didSwitchTo:oldIndex_];
  281. }
  282. }];
  283. }
  284. else{
  285. [self backToOldWithOffset:offsetx];
  286. }
  287. }
  288. else{
  289. [self backToOldWithOffset:offsetx];
  290. }
  291. }
  292. }
  293. @end