Advertisement
Guest User

UIScrollView that allows subviews to be dragged

a guest
Mar 22nd, 2012
439
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.56 KB | None | 0 0
  1. // PoliteScrollView.h
  2.  
  3. #import <UIKit/UIKit.h>
  4.  
  5. @interface PoliteScrollView : UIScrollView
  6.  
  7. // number of pixels perpendicular to the scroll views orientation to make a drag start counting as a subview drag
  8. // defaults to 1/10 of the scroll view's width or height, whichever is smaller
  9. @property(nonatomic,assign) CGFloat subviewDraggingThreshold;
  10. // yes when a subview is being dragged
  11. @property(nonatomic,assign) BOOL isDraggingSubview;
  12. // the subview being dragged
  13. @property(nonatomic,strong) UIView *draggingSubview;
  14.  
  15. @end
  16.  
  17. @protocol PoliteScrollViewDelegate <NSObject>
  18. @optional
  19. - (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesBegan:(NSSet *)touches;
  20. - (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesMoved:(NSSet *)touches;
  21. - (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesEnded:(NSSet *)touches;
  22. @end
  23.  
  24. // PoliteScrollView.m
  25.  
  26. #import "PoliteScrollView.h"
  27.  
  28. @interface PoliteScrollView ()
  29. @property(nonatomic,assign) CGPoint startLocation;
  30. @property(nonatomic,strong) UIView *hitView;
  31. @end
  32.  
  33. @implementation PoliteScrollView
  34.  
  35. @synthesize startLocation=_startLocation;
  36. @synthesize hitView=_hitView;
  37.  
  38. @synthesize subviewDraggingThreshold=_subviewDraggingThreshold;
  39. @synthesize isDraggingSubview=_isDraggingSubview;
  40. @synthesize draggingSubview=_draggingSubview;
  41.  
  42. - (BOOL)isHorizontal {
  43. return self.frame.size.width > self.frame.size.height;
  44. }
  45.  
  46. - (CGFloat)subviewDraggingThreshold {
  47. if (_subviewDraggingThreshold == 0.0) {
  48. CGFloat orthoSize = ([self isHorizontal])? self.frame.size.height : self.frame.size.width;
  49. _subviewDraggingThreshold = orthoSize / 10.0;
  50. }
  51. return _subviewDraggingThreshold;
  52. }
  53.  
  54. - (BOOL)isOrthoganalDrag:(CGPoint)delta {
  55. if ([self isHorizontal]) {
  56. return fabsf(delta.y) > self.subviewDraggingThreshold;
  57. } else {
  58. return fabsf(delta.x) > self.subviewDraggingThreshold;
  59. }
  60. }
  61.  
  62.  
  63. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  64. [super touchesBegan:touches withEvent:event];
  65. CGPoint location = [[touches anyObject] locationInView:self];
  66.  
  67. for (UIView *view in self.subviews) {
  68. if (CGRectContainsPoint(view.frame, location)) {
  69. self.hitView = view;
  70. self.startLocation = location;
  71. break;
  72. }
  73. }
  74. }
  75.  
  76. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  77.  
  78. [super touchesMoved:touches withEvent:event];
  79.  
  80. if (self.isDraggingSubview) {
  81.  
  82. if (self.delegate && [self.delegate respondsToSelector:@selector(scrollView:subviewTouchesMoved:)]) {
  83. [(id <PoliteScrollViewDelegate>)self.delegate scrollView:self subviewTouchesMoved:touches];
  84. }
  85. [self.draggingSubview touchesMoved:touches withEvent:event];
  86.  
  87. } else {
  88.  
  89. CGPoint location = [[touches anyObject] locationInView:self];
  90. CGPoint delta = CGPointMake(location.x-self.startLocation.x, location.y-self.startLocation.y);
  91. if ([self isOrthoganalDrag:delta]) {
  92. self.draggingSubview = self.hitView;
  93. self.isDraggingSubview = YES;
  94. self.scrollEnabled = NO;
  95.  
  96. if (self.delegate && [self.delegate respondsToSelector:@selector(scrollView:subviewTouchesBegan:)]) {
  97. [(id <PoliteScrollViewDelegate>)self.delegate scrollView:self subviewTouchesBegan:touches];
  98. }
  99. [self.draggingSubview touchesBegan:touches withEvent:event];
  100. }
  101. }
  102. }
  103.  
  104. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  105. [super touchesEnded:touches withEvent:event];
  106.  
  107. if (self.isDraggingSubview) {
  108.  
  109. if (self.delegate && [self.delegate respondsToSelector:@selector(scrollView:subviewTouchesEnded:)]) {
  110. [(id <PoliteScrollViewDelegate>)self.delegate scrollView:self subviewTouchesEnded:touches];
  111. }
  112. [self.draggingSubview touchesEnded:touches withEvent:event];
  113.  
  114. self.isDraggingSubview = NO;
  115. self.scrollEnabled = YES;
  116. self.draggingSubview = nil;
  117. }
  118. }
  119. @end
  120.  
  121. // DraggableImageView.h
  122.  
  123. #import <Foundation/Foundation.h>
  124.  
  125. @interface DraggableImageView : UIImageView
  126. - (id)initWithImageView:(UIImageView *)imageView;
  127. @end
  128.  
  129. // DraggableImageView.m
  130. #import "DraggableImageView.h"
  131.  
  132. @interface DraggableImageView ()
  133. @property(assign,nonatomic) CGPoint startLocation;
  134. @end
  135.  
  136. @implementation DraggableImageView
  137.  
  138. @synthesize startLocation=_startLocation;
  139.  
  140. - (id)initWithImageView:(UIImageView *)imageView {
  141.  
  142. self = [super initWithImage:imageView.image];
  143. if (self) {
  144. }
  145. return self;
  146. }
  147.  
  148. - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
  149.  
  150. CGPoint location = [[touches anyObject] locationInView:self];
  151. self.startLocation = location;
  152. }
  153.  
  154. - (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
  155.  
  156. CGPoint location = [[touches anyObject] locationInView:self];
  157. CGPoint prevlocation = [[touches anyObject] previousLocationInView:self];
  158. self.frame = CGRectOffset(self.frame, location.x-prevlocation.x, location.y-prevlocation.y);
  159. }
  160.  
  161. @end
  162.  
  163. // ViewController.m
  164.  
  165.  
  166. #import "ViewController.h"
  167. #import "PoliteScrollView.h"
  168. #import "DraggableImageView.h"
  169.  
  170. #define kPUPPY_COUNT 5
  171.  
  172. #define kPUPPY_WIDTH 100
  173. #define kPUPPY_HEIGHT 100
  174.  
  175.  
  176. @interface ViewController ()
  177. @property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
  178. @property (strong,nonatomic) DraggableImageView *dragImage;
  179. @end
  180.  
  181. @implementation ViewController
  182.  
  183. @synthesize scrollView=_scrollView;
  184. @synthesize dragImage=_dragImage;
  185.  
  186. - (void)initScrollView {
  187.  
  188. for(UIView *subview in [self.scrollView subviews]) [subview removeFromSuperview];
  189.  
  190. for (int i=0; i<kPUPPY_COUNT; i++) {
  191. UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"puppy%d.jpeg", i]];
  192. UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
  193. imageView.frame = CGRectMake(i*kPUPPY_WIDTH, 0.0, kPUPPY_WIDTH, kPUPPY_HEIGHT);
  194. [self.scrollView addSubview:imageView];
  195. }
  196. self.scrollView.clipsToBounds = NO;
  197. self.scrollView.contentSize = CGSizeMake(kPUPPY_COUNT*kPUPPY_WIDTH, kPUPPY_HEIGHT);
  198. }
  199.  
  200. - (void)viewDidLoad
  201. {
  202. [super viewDidLoad];
  203. [self initScrollView];
  204. }
  205.  
  206. - (void)viewDidUnload
  207. {
  208. [self setScrollView:nil];
  209. [super viewDidUnload];
  210. // Release any retained subviews of the main view.
  211. }
  212.  
  213. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  214. {
  215. return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
  216. }
  217.  
  218. - (IBAction)startOver:(id)sender {
  219.  
  220. for (UIView *view in [self.view subviews]) {
  221. if ([view isKindOfClass:[DraggableImageView self]]) {
  222. [view removeFromSuperview];
  223. }
  224. }
  225. }
  226.  
  227. - (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesBegan:(NSSet *)touches {
  228.  
  229. self.dragImage = [[DraggableImageView alloc] initWithImageView:(UIImageView *)scrollView.draggingSubview];
  230. self.dragImage.frame = [scrollView convertRect:scrollView.draggingSubview.frame toView:self.view];
  231. [self.view addSubview:self.dragImage];
  232. [self.dragImage touchesBegan:touches withEvent:nil];
  233. }
  234.  
  235. - (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesMoved:(NSSet *)touches {
  236.  
  237. [self.dragImage touchesMoved:touches withEvent:nil];
  238. }
  239.  
  240. - (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesEnded:(NSSet *)touches {
  241.  
  242. [self.dragImage touchesEnded:touches withEvent:nil];
  243. }
  244.  
  245. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement