PulldownMenu.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. //
  2. // PulldownMenu.m
  3. //
  4. // Created by Bernard Gatt
  5. //
  6. #import "PulldownMenu.h"
  7. @implementation PulldownMenu
  8. @synthesize menuList,
  9. handle,
  10. cellHeight,
  11. handleHeight,
  12. animationDuration,
  13. topMarginLandscape,
  14. topMarginPortrait,
  15. cellColor,
  16. cellFont,
  17. cellTextColor,
  18. cellSelectedColor,
  19. cellSelectionStyle,
  20. fullyOpen,
  21. delegate;
  22. - (id)init
  23. {
  24. self = [super init];
  25. self.backgroundColor = [UIColor clearColor];
  26. menuItems = [[NSMutableArray alloc] init];
  27. // Setting defaults
  28. cellHeight = 60.0f;
  29. handleHeight = 0.0f;
  30. animationDuration = 0.3f;
  31. topMarginPortrait = 0;
  32. topMarginLandscape = 0;
  33. cellColor = [UIColor colorWithRed:0.10 green:0.68 blue:0.94 alpha:0.7];//[UIColor grayColor];
  34. cellSelectedColor = [UIColor colorWithRed:0.10 green:0.68 blue:0.94 alpha:0.5];//[UIColor blackColor];
  35. cellFont = [UIFont fontWithName:@"GillSans-Bold" size:19.0f];
  36. cellTextColor = [UIColor whiteColor];
  37. cellSelectionStyle = UITableViewCellSelectionStyleDefault;
  38. return self;
  39. }
  40. - (id)initWithNavigationController:(UINavigationController *)navigationController
  41. {
  42. self = [self init];
  43. if (self)
  44. {
  45. [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
  46. [[NSNotificationCenter defaultCenter] addObserver: self
  47. selector: @selector(deviceOrientationDidChange:)
  48. name: UIDeviceOrientationDidChangeNotification
  49. object: nil];
  50. masterNavigationController = navigationController;
  51. navigationDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)];
  52. navigationDragGestureRecognizer.minimumNumberOfTouches = 1;
  53. navigationDragGestureRecognizer.maximumNumberOfTouches = 1;
  54. handleDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)];
  55. handleDragGestureRecognizer.minimumNumberOfTouches = 1;
  56. handleDragGestureRecognizer.maximumNumberOfTouches = 1;
  57. [masterNavigationController.navigationBar addGestureRecognizer:navigationDragGestureRecognizer];
  58. masterView = masterNavigationController.view;
  59. }
  60. return self;
  61. }
  62. - (id)initWithView:(UIView *)view
  63. {
  64. self = [self init];
  65. if (self)
  66. {
  67. topMargin = 0;
  68. masterView = view;
  69. }
  70. return self;
  71. }
  72. - (void)loadMenu
  73. {
  74. tableHeight = ([menuItems count] * cellHeight);
  75. [self updateValues];
  76. [self setFrame:CGRectMake(0, 0, 0, tableHeight+handleHeight)];
  77. fullyOpen = NO;
  78. menuList = [[UITableView alloc] init];
  79. menuList.scrollEnabled = false;
  80. menuList.backgroundColor = [UIColor clearColor];
  81. // self.backgroundColor = [UIColor yellowColor];
  82. // menuList.style
  83. [menuList setRowHeight:cellHeight];
  84. [menuList setDataSource:self];
  85. [menuList setDelegate:self];
  86. [self addSubview:menuList];
  87. handle = [[UIView alloc] init];
  88. [handle setBackgroundColor:[UIColor blackColor]];
  89. [self addSubview:handle];
  90. handleDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)];
  91. handleDragGestureRecognizer.minimumNumberOfTouches = 1;
  92. handleDragGestureRecognizer.maximumNumberOfTouches = 1;
  93. [handle addGestureRecognizer:handleDragGestureRecognizer];
  94. [self setTranslatesAutoresizingMaskIntoConstraints:NO];
  95. [handle setTranslatesAutoresizingMaskIntoConstraints:NO];
  96. [menuList setTranslatesAutoresizingMaskIntoConstraints:NO];
  97. [self createConstraints];
  98. }
  99. - (void)insertButton:(NSString *)title
  100. {
  101. [menuItems addObject:title];
  102. }
  103. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  104. {
  105. [self.delegate menuItemSelected:indexPath];
  106. }
  107. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  108. return 1;
  109. }
  110. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  111. {
  112. return [menuItems count];
  113. }
  114. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  115. {
  116. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"menuListCell"];
  117. if (cell == nil) {
  118. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"menuListCell"];
  119. }
  120. cell.backgroundColor = cellColor;
  121. // UIView *cellSelectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame];
  122. // cellSelectedBackgroundView.backgroundColor = cellSelectedColor;
  123. // cell.selectedBackgroundView = cellSelectedBackgroundView;
  124. cell.textLabel.textAlignment=NSTextAlignmentCenter;
  125. cell.selectionStyle = cellSelectionStyle;
  126. [cell.textLabel setTextColor:cellTextColor];
  127. cell.textLabel.font = cellFont;
  128. [cell.textLabel setText:[menuItems objectAtIndex:indexPath.item]];
  129. return cell;
  130. }
  131. - (void)dragMenu:(UIPanGestureRecognizer *)sender
  132. {
  133. if ([sender state] == UIGestureRecognizerStateChanged)
  134. {
  135. CGPoint gesturePosition = [sender translationInView:masterNavigationController.navigationBar];
  136. CGPoint newPosition = gesturePosition;
  137. newPosition.x = self.frame.size.width / 2;
  138. if (fullyOpen)
  139. {
  140. if (newPosition.y < 0)
  141. {
  142. newPosition.y += ((self.frame.size.height / 2) + topMargin);
  143. [self setCenter:newPosition];
  144. }
  145. }
  146. else
  147. {
  148. newPosition.y += -((self.frame.size.height / 2) - topMargin);
  149. if (newPosition.y <= ((self.frame.size.height / 2) + topMargin))
  150. {
  151. [self setCenter:newPosition];
  152. }
  153. }
  154. }
  155. else if ([sender state] == UIGestureRecognizerStateEnded)
  156. {
  157. [self animateDropDown];
  158. }
  159. }
  160. - (void)animateDropDown
  161. {
  162. [UIView animateWithDuration: animationDuration
  163. delay: 0.0
  164. options: UIViewAnimationOptionCurveEaseOut
  165. animations:^{
  166. if (fullyOpen)
  167. {
  168. self.center = CGPointMake(self.frame.size.width / 2, -((self.frame.size.height / 2) + topMargin));
  169. fullyOpen = NO;
  170. }
  171. else
  172. {
  173. self.center = CGPointMake(self.frame.size.width / 2, ((self.frame.size.height / 2) + topMargin));
  174. fullyOpen = YES;
  175. }
  176. }
  177. completion:^(BOOL finished){
  178. [delegate pullDownAnimated:fullyOpen];
  179. }];
  180. }
  181. - (void)animateDropDown:(CGPoint) position
  182. {
  183. [UIView animateWithDuration: animationDuration
  184. delay: 0.0
  185. options: UIViewAnimationOptionCurveEaseOut
  186. animations:^{
  187. if (fullyOpen)
  188. {
  189. self.center = CGPointMake(self.frame.size.width / 2+position.x, -((self.frame.size.height / 2)+position.y + topMargin));
  190. fullyOpen = NO;
  191. }
  192. else
  193. {
  194. self.center = CGPointMake(self.frame.size.width / 2+position.x, ((self.frame.size.height / 2)+position.y + topMargin));
  195. fullyOpen = YES;
  196. }
  197. }
  198. completion:^(BOOL finished){
  199. [delegate pullDownAnimated:fullyOpen];
  200. }];
  201. }
  202. - (void)createConstraints
  203. {
  204. NSLayoutConstraint *pullDownTopPositionConstraint = [NSLayoutConstraint
  205. constraintWithItem:self
  206. attribute:NSLayoutAttributeTop
  207. relatedBy:NSLayoutRelationEqual
  208. toItem:masterView
  209. attribute:NSLayoutAttributeTop
  210. multiplier:1.0
  211. constant:-self.frame.size.height];
  212. NSLayoutConstraint *pullDownCenterXPositionConstraint = [NSLayoutConstraint
  213. constraintWithItem:self
  214. attribute:NSLayoutAttributeCenterX
  215. relatedBy:NSLayoutRelationEqual
  216. toItem:masterView
  217. attribute:NSLayoutAttributeCenterX
  218. multiplier:1.0
  219. constant:0];
  220. NSLayoutConstraint *pullDownWidthConstraint = [NSLayoutConstraint
  221. constraintWithItem:self
  222. attribute:NSLayoutAttributeWidth
  223. relatedBy:NSLayoutRelationEqual
  224. toItem:masterView
  225. attribute:NSLayoutAttributeWidth
  226. multiplier:1.0
  227. constant:0];
  228. NSLayoutConstraint *pullDownHeightMaxConstraint = [NSLayoutConstraint
  229. constraintWithItem:self
  230. attribute:NSLayoutAttributeHeight
  231. relatedBy:NSLayoutRelationLessThanOrEqual
  232. toItem:masterView
  233. attribute:NSLayoutAttributeHeight
  234. multiplier:0.5
  235. constant:0];
  236. pullDownHeightMaxConstraint.priority = 1000;
  237. NSLayoutConstraint *pullDownHeightConstraint = [NSLayoutConstraint
  238. constraintWithItem:self
  239. attribute:NSLayoutAttributeHeight
  240. relatedBy:0
  241. toItem:nil
  242. attribute:NSLayoutAttributeNotAnAttribute
  243. multiplier:1.0
  244. constant:tableHeight+handleHeight];
  245. pullDownHeightConstraint.priority = 900;
  246. NSLayoutConstraint *pullHandleWidthConstraint = [NSLayoutConstraint
  247. constraintWithItem:handle
  248. attribute:NSLayoutAttributeWidth
  249. relatedBy:NSLayoutRelationEqual
  250. toItem:masterView
  251. attribute:NSLayoutAttributeWidth
  252. multiplier:1.0
  253. constant:0];
  254. NSLayoutConstraint *pullHandleHeightConstraint = [NSLayoutConstraint
  255. constraintWithItem:handle
  256. attribute:NSLayoutAttributeHeight
  257. relatedBy:0
  258. toItem:nil
  259. attribute:NSLayoutAttributeNotAnAttribute
  260. multiplier:1.0
  261. constant:handleHeight];
  262. NSLayoutConstraint *pullHandleBottomPositionConstraint = [NSLayoutConstraint
  263. constraintWithItem:handle
  264. attribute:NSLayoutAttributeBottom
  265. relatedBy:NSLayoutRelationEqual
  266. toItem:self
  267. attribute:NSLayoutAttributeBottom
  268. multiplier:1.0
  269. constant:0];
  270. NSLayoutConstraint *pullHandleCenterPositionConstraint = [NSLayoutConstraint
  271. constraintWithItem:handle
  272. attribute:NSLayoutAttributeCenterX
  273. relatedBy:0
  274. toItem:self
  275. attribute:NSLayoutAttributeCenterX
  276. multiplier:1.0
  277. constant:0];
  278. NSLayoutConstraint *menuListHeightMaxConstraint = [NSLayoutConstraint
  279. constraintWithItem:menuList
  280. attribute:NSLayoutAttributeHeight
  281. relatedBy:NSLayoutRelationLessThanOrEqual
  282. toItem:masterView
  283. attribute:NSLayoutAttributeHeight
  284. multiplier:1.0
  285. constant:-topMargin];
  286. NSLayoutConstraint *menuListHeightConstraint = [NSLayoutConstraint
  287. constraintWithItem:menuList
  288. attribute:NSLayoutAttributeHeight
  289. relatedBy:NSLayoutRelationEqual
  290. toItem:self
  291. attribute:NSLayoutAttributeHeight
  292. multiplier:1.0
  293. constant:-handleHeight];
  294. NSLayoutConstraint *menuListWidthConstraint = [NSLayoutConstraint
  295. constraintWithItem:menuList
  296. attribute:NSLayoutAttributeWidth
  297. relatedBy:NSLayoutRelationEqual
  298. toItem:self
  299. attribute:NSLayoutAttributeWidth
  300. multiplier:1.0
  301. constant:0];
  302. NSLayoutConstraint *menuListCenterXPositionConstraint = [NSLayoutConstraint
  303. constraintWithItem:menuList
  304. attribute:NSLayoutAttributeCenterX
  305. relatedBy:NSLayoutRelationEqual
  306. toItem:self
  307. attribute:NSLayoutAttributeCenterX
  308. multiplier:1.0
  309. constant:0];
  310. NSLayoutConstraint *menuListTopPositionConstraint = [NSLayoutConstraint
  311. constraintWithItem:menuList
  312. attribute:NSLayoutAttributeTop
  313. relatedBy:NSLayoutRelationEqual
  314. toItem:self
  315. attribute:NSLayoutAttributeTop
  316. multiplier:1.0
  317. constant:0];
  318. [masterView addConstraint: pullDownTopPositionConstraint];
  319. [masterView addConstraint: pullDownCenterXPositionConstraint];
  320. [masterView addConstraint: pullDownWidthConstraint];
  321. [masterView addConstraint: pullDownHeightConstraint];
  322. [masterView addConstraint: pullDownHeightMaxConstraint];
  323. [masterView addConstraint: pullHandleHeightConstraint];
  324. [masterView addConstraint: pullHandleWidthConstraint];
  325. [masterView addConstraint: pullHandleBottomPositionConstraint];
  326. [masterView addConstraint: pullHandleCenterPositionConstraint];
  327. [masterView addConstraint: menuListHeightMaxConstraint];
  328. [masterView addConstraint: menuListHeightConstraint];
  329. [masterView addConstraint: menuListWidthConstraint];
  330. [masterView addConstraint: menuListCenterXPositionConstraint];
  331. [masterView addConstraint: menuListTopPositionConstraint];
  332. }
  333. - (void)deviceOrientationDidChange:(NSNotification *)notification
  334. {
  335. UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
  336. if (orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown || orientation == UIDeviceOrientationUnknown || currentOrientation == orientation) {
  337. return;
  338. }
  339. currentOrientation = orientation;
  340. [self performSelector:@selector(orientationChanged) withObject:nil afterDelay:0];
  341. }
  342. - (void)orientationChanged
  343. {
  344. [self updateValues];
  345. UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
  346. if ((UIDeviceOrientationIsPortrait(currentOrientation) && UIDeviceOrientationIsPortrait(orientation)) ||
  347. (UIDeviceOrientationIsLandscape(currentOrientation) && UIDeviceOrientationIsLandscape(orientation))) {
  348. currentOrientation = orientation;
  349. if (fullyOpen)
  350. {
  351. [self animateDropDown];
  352. }
  353. return;
  354. }
  355. }
  356. - (void)updateValues
  357. {
  358. topMargin = 0;
  359. BOOL isStatusBarShowing = ![[UIApplication sharedApplication] isStatusBarHidden];
  360. if (UIInterfaceOrientationIsLandscape(self.window.rootViewController.interfaceOrientation)) {
  361. if (isStatusBarShowing) { topMargin = [UIApplication.sharedApplication statusBarFrame].size.width; }
  362. topMargin += topMarginLandscape;
  363. }
  364. else
  365. {
  366. if (isStatusBarShowing) { topMargin = [UIApplication.sharedApplication statusBarFrame].size.height; }
  367. topMargin += topMarginPortrait;
  368. }
  369. if (masterNavigationController != nil)
  370. {
  371. topMargin += masterNavigationController.navigationBar.frame.size.height;
  372. }
  373. }
  374. @end