In iOS a “picker” is a user interface that lets the user choose something from a predetermined set. You used the image picker in your MyStuff to choose a picture from the photo library, and a media picker to choose a songfrom the iTunes library in DrumDub. These are both big interfaces that take over the entire user experience.
iOS also supplies a couple of smaller picker view objects. There’s the specialty UIDatePicker, for choosing dates and times, and the customizable UIPickerView, for anything else. Both present a view containing a number ofvertical “wheels” that the user spins to choose the value or item they want, as shown in Figure 10-11.
Figure 10-11. Picker views
Date Picker
Use the date picker when you want the user to choose a date, time, or duration. The date picker has four different interfaces, controlled by its datePickerMode property. This can be set to one of the four values listed in Table 10-4.The four different modes are shown in Figure 10-12.
Table 10-4. Date picker modes
Mode Description
Choose a calendar date
UIDatePickerModeDateAndTiz Choose a date and time
UIDatePickerModeCountDownTimer Choose a duration (hours and minutes)
Figure 10-12. Date picker modes
The picker’s date property reports the value the user has selected. Setting it changes the date/time in the view. If you want to set the date and have the “wheels” spin to their new positions, send
-setDate:animated:. The time portion of the date property is 0:00 when using the date-only interface. Similarly, the calendar day of the date property is meaningless when using the time-only or duration interface.
If you want to limit the range of values the user can choose from, set the minimumDate and/or maximumDate properties. For example, to force the user to choose a day in the future, set the minimumDate to tomorrow.
You can also reduce the granularity of time choices with the minuteInterval property. When set
to 1, the user can choose any time or duration in one-minute increments (2:30, 2:31, 2:32, and so on). Setting minuteInterval to 5 narrows the user’s choices to 5-minute intervals (2:30, 2:35, 2:40, 2:45, and so on).
If you plan on using date picker, and your interface leaves the picker visible while time progresses, Apple recommends updating the picker in real time. For example, if your interface uses a duration picker and a start button,pressing the start button will probably cause some timer in your app to begin counting down. During that time, your app should periodically update the picker so it slowly (once a minute) changes as the time counts down tozero.
Anything Picker
What if you don’t need to pick a date or a time? What if you need to pick an ice cream flavor, a model of car, or an arch nemesis? The UIPicker object is the catchall picker view. It looks and functions just like the datepicker, except that you define the wheels and the content of each (see Figure 10-11).
A UIPicker uses a delegate and data source arrangement that’s eerily similar to a table view (Chapter 5). A UIPicker needs a delegate object (UIPickerDelegate) and a data source object (UIPickerDataSource). The picker’s datasource determines the number of wheels (called components) and the number of choices (called rows) on each wheel. The delegate object provides the label for each choice. At a minimum, you must implement theseUIPickerDataSource methods:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
And one of these UIPickerDelegate methods:
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
- (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
The first data source method tells your picker how many wheels it has. The second method is then received once for each wheel; it returns the number of rows in that wheel.
Finally (much like the table view data source) a delegate method returns the label for each row in each wheel. You have three choices for which method you implement, depending on how sophisticated you want to be withthe content of each row:
n Implement -pickerView:titleForRow:forComponent: to show plain text labels.
Your method returns a simple string value for each row. This is the most common. See the middle of Figure 10-11.
n Implement -pickerView:attributedTitleForRow:forComponent: to display labels containing special fonts or styles. Your method returns an attributed string for each row. UICatalog doesn’t include an attributedstring example, but it just means that label could have a mixture of fonts, sizes, and styles.
n Implement -pickerView:viewForRow:forComponent:reusingView: to display anything you want in a row. Your method returns a UIView object, which is then used to draw that row. See the right of Figure 10-11.
The last method is the most like the table view’s use of cell objects. For a picker, you can supply a different UIView objects for each row or reuse a single UIView object over and over again. There’s no row cell object cache, asin the table view. Instead, the last UIView returned is passed back to your delegate the next time -pickerView:viewForRow:forComponent:reusingView: is sent. If you’re
reusing a single UIView object, alter that view and return it again. If not (or the view parameter is nil), return a new view object.
If you want to control the width of each wheel or the height of the rows in a wheel, implement the optional - pickerView:widthForComponent: or -pickerView:rowHeightForComponent: methods, respectively.
Look at the code that implements the simple picker view in the UICatalog app (in the middle of Figure 10-11).
You’ll find it in the PickerViewController.m file. The code that implements the picker using custom view objects(on the right in Figure 10-11) can be found in the
CustomPickerDataSource.m file. The view object used as the rubber stamp for each row is defined in
CustomView.m.
UIPickerView objects are not control objects; they are not subclasses of UIControl and they don’t send action messages. Instead, the picker’s delegate receives a -pickerView:didSelectRow:inComponent: message when the userchanges one of the wheels.
Image Views
You’ve already used
enough image views to know your way around them. There are, however, a couple of properties that I’d like to mention.
The first is the contentMode. This property controls how the image
(which may
not bethe same size as the view) gets arranged. The choices are listed in Table 10-5.
Table 10-5. View content mode
Mode Description
UIViewContentModeScaleToFill Stretches or squeezes the image
to exactly fill the view.
It may distort the image if the aspect ratio of the view is not the same as the image.
UIViewContentModeScaleAspectFit Scales the image, without distorting it, so it just fits inside the view. Some parts of the view many not contain any image (think letterboxing).
UIViewContentModeScaleAspectFill Scales the image, without distorting it, so it completely fills the view.
Some parts of the image
may get clipped.
UIViewContentModeCenter Centers the image without scaling it.
UIViewContentModeTop, UIViewContentModeBottom, UIViewContentModeLeft, or UIViewContentModeRight
UIViewContentModeTopLeft, UIViewContentModeTopRight, UIViewContentModeBottomLeft, or UIViewContentModeBottomRight
The middle of one edge of the image is aligned with the corresponding edge of the view. The image
is not scaled. The image
may not fill, or be clipped, in the other three directions.
One corner of the image
is aligned with the same corner of the view. The image
is not scaled. The image
may not fill the entire view, or will be clipped if it overfills it.
UIImageView also has a quirky talent: it can show a sequence of images either quickly (like a flipbook or a really short movie), or slowly (like a slideshow). Put the images you want to display into an array (NSArray) and use thatarray to set the animationImages property. Set the animationDuration and, optionally, the animationRepeatCount to control the speed of each frame and how many times the entire sequence plays. (Set animationRepeatCount to 0 toplay forever.)
Once set up, send the view -startAnimation to begin the show and -stopAnimation to stop it again.
Code that demonstrates this is in the ImagesViewController.m file of the UICatalog project.
Grouped Tables
Chapter 5 mentioned that you can create grouped table views, like those used in the Settings app.
I didn’t, however, actually show you how to do that. You already have all of the basics, but if you want a concrete example, look no further than the UICatalog project. Most of the sample views (buttons, controls, text fields, andsegments) are presented in a group table view. Each group is a single example.
Start with the sample buttons. Its view controller is the ButtonsViewController class, which is subclass of UITableViewController. A table view controller is a UIViewController designed specifically to manage a table view. AUITableViewController is both a UITableViewDelegate
and a UITableViewDataSource. Find these delegate methods, which define the table contents, and see how they work:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
The View You Never See
That wraps up most of the important view objects in iOS. I’ll talk about toolbars a little in Chapter 12 and a lot more about UIView in Chapter 11. But I want to mention a very special view—one that’s used a lot, but you neversee.
It's the UIScollView class. A scroll view adds the dynamics of scrolling to your interface. You never see the scroll view; you see its effects. A scroll view works by presenting a larger view inside a smaller view. The effect is like having a window into that larger view.
When you drag inside the window, you are “sliding” the view behind it around so you can see different
portions of it, as illustrated in Figure 10-13.
Figure 10-13. Conceptual arrangement a scroll view
It’s easiest to think about a scroll view as being two views in one. For most view objects, the size of its content (called its bounds) and the size it occupies in your interface (called its frame) are the same. So a view, say abutton, that’s 30 by 100 pixels will occupy a region of 30 by 100 pixels in your interface.
A scroll view breaks this relationship. A scroll view has a special contentSize property that’s divorced from its frame size. It’s frame becomes the “window” that appears in your interface.
The contentSize defines the logical size of the view, only a portion of which is visible through the window.
The contentOffset property determines exactly what portion is visible. This property is the point in the content area that appears at the upper-left corner of the frame—the portion visible to the user. contentOffset is initially 0,0. Thisplaces the upper-left corner of the content at the upper-left corner of the frame. As the contentOffset moves down, the content appears to scroll up, keeping the contentOffset point at the upper-left corner of the frame.
Table views, web views, and text views all provide scrolling and are all subclasses of UIScrollView. You can subclass UIScrollView yourself to create a custom view that supports scrolling, or you can use a UIScrollView object onits own by simply populating its content view with whatever subviews you like. You can even have a scroll view inside another scroll view; it’s weird but there are notes in the Scroll View Programming Guide for iOS on how to doit.
A great place to get started with scroll views is the PhotoScroller example project. Search Xcode’s Documentation and API Reference for the PhotoScroller sample code project and click on the Open Project button. ThePhotoScroller project defines a subclass of UIScrollView used to display, pan, and zoom an image. This project demonstrates two of scroll view’s three major talents:
n Scrolling a larger content view around inside a smaller view
n Pinching and zooming the content view
n Scrolling by “page”
The first is its basic function. It’s for this ability that scroll views are most often used, which includes table views, web views, and text views. To use a scroll view in this fashion, you don’t have to subclass it or use a delegate. Simply populate and size its content view with the views you want to display, and the scroll view will let the user drag it around.
The scroll view’s second talent is pinching and zooming its content view, so it not only scrolls it, but magnifies and shrinks it as well, as shown in Figure 10-14.
This feature requires the use of a scroll view delegate(UIScrollViewDelegate) object. In the PhotoScroll project, the custom ImageScrollView is a UIScrollView subclass that’s also its own delegate—an arrangement that’s perfectly legitimate, if a little unusual. UIScrollView processes the touch events and handles the most of the panning and zooming details for you.
Figure 10-14. PhotoScroller app
You can also cause the view to scroll programmatically by setting its contentOffset property to any point in the content view you want. If you want to make the view animate its journey to the new position, send it the -setContentOffset:animate: message.
SCROLL VIEWS AND THE KEYBOARD
Scroll views can contain text fields—usually indirectly, by placing a text field in a table view, which you now know is a scroll view. When the keyboard appears, it can cover up the very text field the user wants to edit. Thesolution is to cause the scroll view to scroll up so the text field is visible above the keyboard.
To do that, your controller will need to observe keyboard notifications (such as UIKeyboardDidShowNotification).
These notifications contain the coordinates of the virtual keyboard on the screen. You use this information todetermine if the keyboard is covering your text field. If it is, send the scroll view a -setContentOffset:animate: message that will cause the text field to scroll to a position above the virtual
keyboard.
The mechanics of this is described in the Text, Web, and Editing Programming Guide for iOS, which you’ll find in Xcode’s documentation. Look for the aptly named section “Moving Content That Is Located Under theKeyboard” in the “Managing the Keyboard” chapter.
The PhotoScroller project also demonstrates an advanced technique called tiling. In the beginning of
Chapter 5, I explained that an iOS device doesn’t have enough memory or CPU power to create thousands of individual rowobjects for a table. Instead, it draws just the portion of the table that is visible to the user, as the user scrolls through the list.
The contents of an exceptionally large content view may fall into the same category. The PhotoScroller project demonstrates how to dynamically prepare only those view objects that are currently visible through the scrollview’s “window.” The table view—which, as you remember, is based on UIScrollView—already does this for you, only preparing the view objects for those rows that are visible in the table.
A much less common use of scroll views is to view content in “pages.” This is enabled by setting the pagingEnabled property to YES. When you do that, the scroll view forces the content view (technically, its contentOffsetproperty) to move in discrete distances, exact multiples of its frame size. Conceptually, it divides your content view into a grid (the exact size of the window) and any scrolling eventually settles on one segment. There’s aPageControl sample project that demonstrates this feature.
Advanced use of scroll views is not for the faint of heart. This can be really complex stuff, but it’s the stuff of really cool apps.
The now famous “drag to update” gesture that has become the mainstay of iOS apps is all done with scroll views and scroll view delegates. If you need this feature in a table view, most of the work is already done for you: create a UIRefreshControl object and connect it
to the table view controller’s refreshControl property. Now the user can drag down to update the
table. To dive into the power of scroll views, start with the Scroll View Programming Guide for iOS.
Summary
Your command of the “language” of iOS is growing. You started out with the syntax and grammar of iOS, learning to create objects, connect them, and send messages. In this chapter you’ve expanded your vocabulary,acquiring an impressive number of view and control objects you can add and customize. You also saw how grouped tables are made, and got a glimpse of the magic behind scrolling. In the process, you learned how to downloadsample code and unlock its secrets.
You can go a long way using pre-made view and control objects. But there are limits, and at some point you’re going to want a view that no one has created yet. Creating your own views is the next step of your journey, andthe next chapter in this book.




No comments:
Post a Comment