-
Basically there are no really good (and now working) guides on how to put a UIPickerView on a UIActionSheet. Mainly because some things changed with the latest firmware updates made by Apple. Well after some fiddling around, I got it working. Here is how:
Step 1: Adding the right delegates
Make sure your current class (probably a ViewController) uses the following delegates:
- UIActionSheetDelegate
- UINavigationControllerDelegate
- UIPickerViewDelegate
- UIPickerViewDataSource
Step 2: Trigger the UIActionSheet
Go to the method where you want to make the UIPickerView appear. In my case it is when I select a row from a table, but of course it could also be when you push a button or anything you want./* first create a UIActionSheet, where you define a title, delegate and a button to close the sheet again */ UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Select position" delegate:self cancelButtonTitle:@"Done" destructiveButtonTitle:nil otherButtonTitles:nil]; /* I always give my controls a tag, to make sure I can work with multiple actionsheets in one View (to identify them when an event triggers */ actionSheet.tag = POSITION_ROW; actionSheet.actionSheetStyle = UIActionSheetStyleDefault; /* Initialize a UIPickerView with 100px space above it, for the button of the UIActionSheet. */ UIPickerView* positionPicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0,100, 320, 216)]; positionPicker.dataSource = self; positionPicker.delegate = self; /* another unique tag for this UIPicker */ positionPicker.tag = POSITION_ROW; /* Add the UIPickerView to the UIActionSheet */ [actionSheet addSubview:positionPicker]; /* Select the previous selected value, which for me is stored in 'currentPosition' */ [positionPicker selectRow:currentPosition inComponent:0 animated:NO]; /* clean up */ [positionPicker release]; /* Add the UIActionSheet to the view */ [actionSheet showInView:self.view]; /* Make sure the UIActionSheet is big enough to fit your UIPickerView and it's buttons */ [actionSheet setBounds:CGRectMake(0,0, 320, 411)]; /* clean up */ [actionSheet release];
Step 3: Implementing the datasource and delegates for the UIPickerView
Now, the triggering of the UIActionSheet is now working, but you would also like to have some items in your UIPickerView. Well, take a look at the following code and read the comments./* Defines the total number of Components (like groups in a UITableView) in a UIPickerView */ - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView; { return 1; } /* What to do when a row from a UIPickerView is selected. This will trigger each time you scroll the UIPickerView, so only lightweight stuff. */ - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { overlayPosition = row; [tableSettings reloadData]; } /* For me the number of items in the UIPickerView is known on compile time. So here I just return 3 */ - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component; { return 3; } /* Because the UIPickerView expects a UIView for every row you insert in the UIPickerView, you need to make one. What I do here is really simple. I create a UILabel* and with each row it requests I just change the text in the UILabel. */ - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view { /* Create a UILabel and set it 40 pixels to the right, to make sure it is put nicely in the UIPickerView */ UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(40, 0, 280, 25)] autorelease]; label.textColor = [UIColor blackColor]; label.backgroundColor = [UIColor clearColor]; switch (row) { default: case kUnderClock: label.text = @"Under clock"; break; case kAboveSlider: label.text = @"Above lock slider"; break; case kCenter: label.text = @"Vertically centered"; break; } return label; }Step 4: Do stuff when buttons on the UIActionSheet are clicked
Now, the final thing you have to do is make sure you listen to the events of the UIActionSheet also. So here is the code:- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if (actionSheet.tag == POSITION_ROW) { /* Do stuff here, only intended for the right UIActionSheet. This only applies for when you use multiple UIActionSheets on the same ViewController. Closing it is unnecessary, because you already specified a destructive button. */ } } -
For the iPhone 4 release, I started development of Desktop Backgrounds HD. This is a wallpaper application which takes your higher resolution retina screen in account when downloading images from the wallpaper server. The whole purpose was to actually make my application resolution independent.
Desktop Backgrounds HD has the following features:
- Over 14.000+ unique HD backgrounds available
- Delivers the backgrounds to your phone in the right resolution (iPhone 3G, iPhone 4 and iPad)
- Create an overlay, to show some text over your background (v1.1)
- Dim backgrounds for better use behind your icons
- Mail your backgrounds to a friend (you need to have a mail account setup on your device) (v1.1)
- iOS 4 requirement (is this a feature?)
- Intelligent caching system, to keep data-transfers low
- Multi-task support
Here are some screenshots for the application:
-
For Desktop Backgrounds HD (which is currently in review) I wanted to implement a feature called “send image by email”. First I tried to include an image base64 encoded in an URL, with the mailto: protocol, but this resulted in numerous errors.
So after a coupe of google searches, I came up with the following solution, follow these steps and you will be sending emails with attachments before you can say “emails with attachments” 250 times.
Step 1
First add the MessageUI framework in your application.Step 2
The class you want to use the functionality in, should get the following 2 imports:#import <MessageUI/MessageUI.h> #import <MessageUI/MFMailComposeViewController.h>
Step 3
Make sure your class listens to the MFMailComposeViewControllerDelegate.Step 4
Next up, is to add code to add an attachment to the mail composer and open it up.MFMailComposeViewController* composer = [[MFMailComposeViewController alloc] init]; composer.mailComposeDelegate = self; [composer setSubject:@"The subject of the email"]; NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed:@"test.png"], 1); [composer addAttachmentData:imageData mimeType:@"image/png" fileName:@"test.png"]; NSString *emailBody = @"Check out this amazing PNG!"; [composer setMessageBody:emailBody isHTML:YES]; [self presentModalViewController:composer animated:YES]; [composer release];
Step 5
Add this method, to make sure you get back full control over your view-controller:- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error { [self dismissModalViewControllerAnimated:YES]; }In this last method you can also perform error checking, which is not included in this example. Hope this helps anyone, and if not… too bad :D
-
For an application I am making, I am making a view where users can configure all kinds of settings, which has direct effect on an UIView I have. I want to grab that UIView and save it as an image.
Well there are examples enough about this, most of them are all the same, but there is one annoying thing. It saves the view in the good ol’ resolution. Because I am making all my apps “retina-aware”, I wanted to change this.
So here is my code snippet of how I save an UIView to an UIImage:
UIGraphicsBeginImageContextWithOptions(myView.bounds.size, NO, [[UIScreen mainScreen] scale]); [myView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
It automaticly takes care of any scaling, if there will be higher resolution iPhones/iPads in the future.










