Source Code: https://www.dropbox.com/sh/nfy3asv2x0ygly3/AAAuL_sEywcF_mWEMQnzjs-ra
Other reference: http://www.edumobile.org/iphone/iphone-programming-tutorials/handling-subviews-of-the-main-view-in-uiviewcontroller-part-1/
It is often the case that the controls provided by iOS for the iPhone or iPad don’t quite meet our needs. In this blog we’ll learn how to mimic a simple Drop – Down list using a label, some custom buttons, and a hidden view. So let’s get started!
Open Xcode, choose “Create a new Xcode project,” select the Single View Application template, and click Next. Name the project “DropDownDemo,” and choose options as shown here:
Click Next, choose a location to save the project, and click Create.
When the app template has been created, open the ViewController.zib file, and drag controls to the view as shown below:
The properties for these controls should be set in the following way:
View: no properties set
◦ Label – Select A Color: Change the text to “Select A Color,” change the background to a light yellow color.
◦ Button: Change the text to “▼” by navigating to Edit | Special Characters in the menu, then selecting the down arrow character. Change the font to System Bold 10.0. Change the background to a light yellow color. The button type is set to Custom.
◦ View: align the left and right sides of the view to the left side of the label and the right side of the button above it. We will also hide this button by checking the “Hidden” checkbox, but not just yet.
▪ Button – Red: set the button type to Custom, the text to “Red,” align the top of the button with the top of its containing view, and the left and right sides of the button with the left and right sides of the view. Set the tag value to 1, and the height of the button to 36.
▪ Button – Blue: as above, but the text is “Blue”, and the tag value is 2
▪ Button – Green: as above, but the text is “Green”, and the tag value is 3
After making these changes, select the view that contains the three buttons (Red, Blue, and Green), and put a check mark in the Hidden property.
Open the ViewController.h file, and add the following properties and methods:
</div> <div class="objc codesnip"></div> <div class="objc codesnip"><span class="co1">#import <UIKit/UIKit.h></span><span class="kw1">@interface</span> ViewController <span class="sy0">:</span> UIViewController<span class="kw1">@property</span> <span class="br0">(</span>nonatomic, strong<span class="br0">)</span> IBOutlet UILabel <span class="sy0">*</span>ddText; <span class="kw1">@property</span> <span class="br0">(</span>nonatomic, strong<span class="br0">)</span> IBOutlet UIView <span class="sy0">*</span>ddMenu; <span class="kw1">@property</span> <span class="br0">(</span>nonatomic, strong<span class="br0">)</span> IBOutlet UIButton <span class="sy0">*</span>ddMenuShowButton; <span class="sy0">-</span> <span class="br0">(</span>IBAction<span class="br0">)</span>ddMenuShow<span class="sy0">:</span><span class="br0">(</span>UIButton <span class="sy0">*</span><span class="br0">)</span>sender; <span class="sy0">-</span> <span class="br0">(</span>IBAction<span class="br0">)</span>ddMenuSelectionMade<span class="sy0">:</span><span class="br0">(</span>UIButton <span class="sy0">*</span><span class="br0">)</span>sender; <span class="kw1">@end</span> </source> </div> </div> In the ViewController.zib file, wire up ddText to the UILabel, ddMenu to the hidden view, and ddMenuShowButton to the small custom button containing the “▼” character. The ddMenuShow method is also wired to this small custom button (Touch Up Inside), and each of the other custom buttons (Red, Blue, and Green) are wired to the ddMenuSelectionMade method, also on TouchUpInside. Next, open the ViewController.h file, and make changes as shown below: <div class="codesnip-container"> <div class="objc codesnip"></div> <div class="objc codesnip"></div> <div class="objc codesnip"><span class="co1">#import "ViewController.h"</span><span class="kw1">@interface</span> ViewController <span class="br0">(</span><span class="br0">)</span><span class="kw1">@end</span> <span class="kw1">@implementation</span> ViewController <span class="kw1">@synthesize</span> ddMenu, ddText; <span class="kw1">@synthesize</span> ddMenuShowButton; <span class="sy0">-</span> <span class="br0">(</span>IBAction<span class="br0">)</span>ddMenuShow<span class="sy0">:</span><span class="br0">(</span>UIButton <span class="sy0">*</span><span class="br0">)</span>sender <span class="br0">{</span> <span class="kw1">if</span> <span class="br0">(</span>sender.tag <span class="sy0">==</span> 0<span class="br0">)</span> <span class="br0">{</span> sender.tag <span class="sy0">=</span> <span class="nu0">1</span>; self.ddMenu.hidden <span class="sy0">=</span> <span class="kw2">NO</span>; <span class="br0">[</span>sender setTitle<span class="sy0">:</span><span class="co3">@</span><span class="st0">"▲"</span> forState<span class="sy0">:</span>UIControlStateNormal<span class="br0">]</span>; <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span> sender.tag <span class="sy0">=</span> <span class="nu0">0</span>; self.ddMenu.hidden <span class="sy0">=</span> <span class="kw2">YES</span>; <span class="br0">[</span>sender setTitle<span class="sy0">:</span><span class="co3">@</span><span class="st0">"▼"</span> forState<span class="sy0">:</span>UIControlStateNormal<span class="br0">]</span>; <span class="br0">}</span> <span class="br0">}</span> <span class="sy0">-</span> <span class="br0">(</span>IBAction<span class="br0">)</span>ddMenuSelectionMade<span class="sy0">:</span><span class="br0">(</span>UIButton <span class="sy0">*</span><span class="br0">)</span>sender <span class="br0">{</span> self.ddText.text <span class="sy0">=</span> sender.titleLabel.text; <span class="br0">[</span>self.ddMenuShowButton setTitle<span class="sy0">:</span><span class="co3">@</span><span class="st0">"▼"</span>forState<span class="sy0">:</span>UIControlStateNormal<span class="br0">]</span>; self.ddMenuShowButton.tag <span class="sy0">=</span> <span class="nu0">0</span>; self.ddMenu.hidden <span class="sy0">=</span> <span class="kw2">YES</span>; <span class="kw1">switch</span> <span class="br0">(</span>sender.tag<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">case</span> 1<span class="sy0">:</span> self.view.backgroundColor <span class="sy0">=</span> <span class="br0">[</span>UIColor redColor<span class="br0">]</span>; <span class="kw2">break</span>; <span class="kw1">case</span> 2<span class="sy0">:</span> self.view.backgroundColor <span class="sy0">=</span> <span class="br0">[</span>UIColor blueColor<span class="br0">]</span>; <span class="kw2">break</span>; <span class="kw1">case</span> 3<span class="sy0">:</span> self.view.backgroundColor <span class="sy0">=</span> <span class="br0">[</span>UIColor greenColor<span class="br0">]</span>; <span class="kw2">break</span>; <span class="kw1">default</span><span class="sy0">:</span> <span class="kw2">break</span>; <span class="br0">}</span> <span class="br0">}</span> … </div> </div>
As always, we begin by synthesizing the properties. After this, we implement our two action methods. The ddMenuShow method shows or hides the menu depending on the current state of its tag. It also changes the direction of the arrow character using the setTitle: forState: method. NSStrings are Unicode strings, so it’s legal to use special characters directly in the string as we’ve done here.
The ddMenuSelectionMade method changes the color of the main view’s background depending on the tag value of the button pushed. It also makes changes to the ddMenuShowButton, and hides the ddMenu view.
Save and run the application.
In a production application, we would certainly want to create a custom UIControl and make the appearance of our drop down box conform to the Human Interface Guidelines. But this technique is a simple way to obtain functionality quickly for testing purposes during the development process.
Have Fun!
http://www.edumobile.org/iphone/iphone-programming-tutorials/a-simple-drop-down-list-for-iphone/
To setup the user interface in Interface Builder, you’ll need to create a UIPageControl and a UIScrollView within a UIViewController, and as many other UIViewControllers as to need.
The PageViewController will contain 2 subview a UIScrollView and a UIPageControl. The UIScrollView will contain the views while the UIPageControl will navigate and control which part of the UIScrollView is visible.
You’ll also need some mechanism for calling addChildViewController:
on the view controller, I’m my example I did this by sub-classing PagerViewController, but you could also do this before the view controller is push into view.
So, the public interface should look like this:
@interface PagerViewController : UIViewController @property (nonatomic, strong) IBOutlet UIScrollView *scrollView; @property (nonatomic, strong) IBOutlet UIPageControl *pageControl; - (IBAction)changePage:(id)sender; @end
On to the implementation file. First of all, I want to handle all the view appearence at rotation calls myself so, we need to over-ride automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers
and return NO indicating we don’t want the UIViewController super class doing this.
When the PagerViewController view comes into view, we will need to signal to the currently active child view controller that it has become visible. So we will forward on the view appeared/disappeared messages.
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers { return NO; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; if (viewController.view.superview != nil) { [viewController viewDidAppear:animated]; } } - (void)viewWillDisappear:(BOOL)animated { UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; if (viewController.view.superview != nil) { [viewController viewWillDisappear:animated]; } [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; if (viewController.view.superview != nil) { [viewController viewDidDisappear:animated]; } [super viewDidDisappear:animated]; }
viewWillAppear
is a little more complex since we also want to load all the child view controllers into the scroll view (we’ll cover loadScrollViewWithPage
next), and also make sure the scroll view’s content size is large enough to handle all the child views.
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; for (NSUInteger i =0; i < [self.childViewControllers count]; i++) { [self loadScrollViewWithPage:i]; } self.pageControl.currentPage = 0; _page = 0; [self.pageControl setNumberOfPages:[self.childViewControllers count]]; UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; if (viewController.view.superview != nil) { [viewController viewWillAppear:animated]; } self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [self.childViewControllers count], scrollView.frame.size.height); }
To load the content of the UIViewController into the UIScrolView contentView we go though each child and add its view as a subview of the UIScrollView off-setting the origin by a screen width each time.
- (void)loadScrollViewWithPage:(int)page { if (page < 0) return; if (page >= [self.childViewControllers count]) return; // replace the placeholder if necessary UIViewController *controller = [self.childViewControllers objectAtIndex:page]; if (controller == nil) { return; } // add the controller's view to the scroll view if (controller.view.superview == nil) { CGRect frame = self.scrollView.frame; frame.origin.x = frame.size.width * page; frame.origin.y = 0; controller.view.frame = frame; [self.scrollView addSubview:controller.view]; } }
To handle scrolling we need to implement a few UIScrollViewDelegate methods and also the - (IBAction)changePage:(id)sender
method we declared earlier.
We need to know how the scrolling occurred, i.e. was it initiated from a gesture swipe across the screen, or by tapping either side of the UIPageControl.
To work this out we update an ivar when the various delegate callback are called..
This code is largely taken from this Cocoa with Love post
I also call the child UIViewController’s viewillAppear etc. methods.
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { _pageControlUsed = NO; } // At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { _pageControlUsed = NO; } - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { UIViewController *oldViewController = [self.childViewControllers objectAtIndex:_page]; UIViewController *newViewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; [oldViewController viewDidDisappear:YES]; [newViewController viewDidAppear:YES]; _page = self.pageControl.currentPage; }
Now, to update the display after the page change we just need implement the scrollViewDidScroll
delegate method and the changePage
IBAction method.
changing the viewable UIViewController is done by simply scrolling the UIScrollView to the appropriate location.
- (IBAction)changePage:(id)sender { int page = ((UIPageControl *)sender).currentPage; // update the scroll view to the appropriate page CGRect frame = self.scrollView.frame; frame.origin.x = frame.size.width * page; frame.origin.y = 0; UIViewController *oldViewController = [self.childViewControllers objectAtIndex:_page]; UIViewController *newViewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; [oldViewController viewWillDisappear:YES]; [newViewController viewWillAppear:YES]; [self.scrollView scrollRectToVisible:frame animated:YES]; // Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above. _pageControlUsed = YES; } - (void)scrollViewDidScroll:(UIScrollView *)sender { // We don't want a "feedback loop" between the UIPageControl and the scroll delegate in // which a scroll event generated from the user hitting the page control triggers updates from // the delegate method. We use a boolean to disable the delegate logic when the page control is used. if (_pageControlUsed || _rotating) { // do nothing - the scroll was initiated from the page control, not the user dragging return; } // Switch the indicator when more than 50% of the previous/next page is visible CGFloat pageWidth = self.scrollView.frame.size.width; int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1; if (self.pageControl.currentPage != page) { UIViewController *oldViewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; UIViewController *newViewController = [self.childViewControllers objectAtIndex:page]; [oldViewController viewWillDisappear:YES]; [newViewController viewWillAppear:YES]; self.pageControl.currentPage = page; [oldViewController viewDidDisappear:YES]; [newViewController viewDidAppear:YES]; _page = page; } }
To handle device rotation, we need to return YES from shouldAutorotateToInterfaceOrientation
.
We also need to pass on the following messages to the currently active child UIViewController.
willAnimateRotationToInterfaceOrientation:duration:
willRotateToInterfaceOrientation:duration:
didRotateFromInterfaceOrientation:
But, we also need to handle our own rotation, i.e. resizing the scrollviews contentView, and adjusting the frame of the child subviews, otherwise everything is miss-aligned. This is done inwillAnimateRotationToInterfaceOrientation:duration:
, so that the resizing is also animated.
When the frame of UIScrollView adjusts scrollViewDidScroll:
also gets called, so to prevent that from flipping us to a different page we set and unset the _rotating
flag in the following methods:
willRotateToInterfaceOrientation:duration:
didRotateFromInterfaceOrientation:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; } - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; [viewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; _rotating = YES; } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; [viewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [self.childViewControllers count], scrollView.frame.size.height); NSUInteger page = 0; for (viewController in self.childViewControllers) { CGRect frame = self.scrollView.frame; frame.origin.x = frame.size.width * page; frame.origin.y = 0; viewController.view.frame = frame; page++; } CGRect frame = self.scrollView.frame; frame.origin.x = frame.size.width * _page; frame.origin.y = 0; [self.scrollView scrollRectToVisible:frame animated:NO]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { _rotating = NO; UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage]; [viewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; }
Please to go to see
- (UIImage *) changeColor: (UIImage *)image { UIGraphicsBeginImageContext(image.size); CGRect contextRect; contextRect.origin.x = 0.0f; contextRect.origin.y = 0.0f; contextRect.size = [image size]; // Retrieve source image and begin image context CGSize itemImageSize = [image size]; CGPoint itemImagePosition; itemImagePosition.x = ceilf((contextRect.size.width - itemImageSize.width) / 2); itemImagePosition.y = ceilf((contextRect.size.height - itemImageSize.height) ); UIGraphicsBeginImageContext(contextRect.size); CGContextRef c = UIGraphicsGetCurrentContext(); // Setup shadow // Setup transparency layer and clip to mask CGContextBeginTransparencyLayer(c, NULL); CGContextScaleCTM(c, 1.0, -1.0); CGContextClipToMask(c, CGRectMake(itemImagePosition.x, -itemImagePosition.y, itemImageSize.width, -itemImageSize.height), [image CGImage]); switch (colorSelected) { case 0: CGContextSetRGBFillColor(c, 0, 0, 1, 1); break; default: CGContextSetRGBFillColor(c, 1, 0, 0., 1); break; } contextRect.size.height = -contextRect.size.height; contextRect.size.height -= 15; // Fill and end the transparency layer CGContextFillRect(c, contextRect); CGContextEndTransparencyLayer(c); UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; }
GLOBAL VARIABLES
The simple, but crude way is to use Global Variables. Global Variables can get messy because once you use a certain name as global variable, you can not use it again at ANY OTHER PLACES. And this can get confusing when you have many lines of codes and more than one class.
A quick example of Global Variable Declaration is as follows:
In your header (.h) file, input the “allocation” of the variable.
“extern” does not declare it. What it does is just “allocate” a memory for that particular variable. Therefore to declare it, one need to declare in the implementation file (*.m) as follows:
So to use this variable in another class, all you need to do is import “MyAppHeader.h” and MYGlobalVariable should be ready to be used.
It works well, in fact, I also used it in some of my early apps. That is until I learn about Singleton.
SINGLETON
Believe it or not, MOST of us NOOBIES already used Singleton. The most common Singleton we use is…. *drumroll*… NSUserDefaults!
Do you like NSUserDefaults? I do. It is so easy and simple. And that is why you also should use Singleton in variable aspects of your app. It will make your coding very nice and easy to maintain.
How to implement a Singleton? I am no ObjC Guru, that much I can tell you, but hey, why reinvent the wheel, when some gurus have created the Singleton class for you? There are loadsssss of ways to write a Singleton Class, and you can find them here:
StackOverflow: Samples of Singletons
Anyway, here is MY singleton class. I used this Singleton class in one of my latest app – Clock Stand for iPad. I stripped off all the other variables and leave just 1 for example so that it is clear for you to see how to implement it.
And the implementation file (*.m)
Now, to create the Singleton Class, all you need to do is Right Click on the left panel of XCode and Choose Add File… and Choose Objective-C Class. Give a proper name (for eg, MySingletonCenter.h and MySingletonCenter.m) to it and add to project. After that just copy and paste the above Singleton code into the corresponding .h and .m. And you’re set to go.
To use Singleton in another class is easy.. in fact super easy just like NSUserDefaults.
1. #import “MySingletonCenter.h”
2. Everytime you want to read or write to it:
Reference: http://xcodenoobies.blogspot.com/2012/08/how-to-pass-data-between.html