Tài liệu Lập trình ứng dụng cho iPhone part 14 docx

24 318 0
Tài liệu Lập trình ứng dụng cho iPhone part 14 docx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

240 Monitoring events and actions In the previous chapter you learned how to create the basic view controllers that fulfill the controller role of an MVC architectural model. You’re now ready to start accepting user input, since you can now send users off to the correct object. Users can interact with your program in two ways: by using the low-level event model or by using event-driven actions. In this chapter, you’ll learn the difference between the two types of interactions. Then we’ll look at notifications, a third way that your program can learn about user actions. Of these three models, it’s the events that provide the lowest-level detail (and which ultimately underlie everything else), and so we’ll begin with events. 14.1 An introduction to events We briefly touched on the basics of event management in chapter 10, but as we said at the time, we wanted to put off a complete discussion until we could cover them in depth; we’re now ready to tackle that job. This chapter covers ■ The SDK’s event modeling ■ How events and actions differ ■ Creating simple event- and action-driven apps 241An introduction to events Part 1 of this book, dealing with web design, outlined how events tend to work on the iPhone. The fundamental unit of user input is the touch: a user puts his finger on the screen. This could be built into a multi-touch or a gesture, but the touch remains the building block on which everything else is constructed. It’s thus the basic unit that we’re going to be examining in this chapter. 14.1.1 The responder chain When a touch occurs in an SDK program, you have to worry about something you didn’t have to think about on the web: who responds to the event. That’s because SDK pro- grams are built of tens—perhaps hundreds—of different objects. Almost all of these objects are subclasses of the UIResponder class, which means they contain all the func- tionality required to respond to an event. So who gets to respond? The answer is embedded in the concept of the responder chain. This is a hierarchy of different objects that are each given the opportunity, in turn, to answer an event message. Figure 14.1 shows an example of how an event moves up the responder chain. It starts out at the first responder of the key window, which is typically the view where the event occurred—in other words, where the user touched the screen. As we’ve already noted, this first responder is prob- ably a subclass of UIResponder —which is the class reference you’ll want to look to for a lot of responder functionality. Any object in the chain may accept an event and resolve it, but whenever that doesn’t occur the event moves further up the list of responders. From a view, an event will go to its superview, then its superview, until it eventually reaches the UIWindow object, which is the superview of everything in your application. It’s useful to note that from the UIWindow downward, the responder chain is the view hierarchy turned on its head, so when you’re building your hierarchies, they’ll be doing double duty. Although figure 14.1 shows a direct connection from the first responder to the window, there could be any number of objects in this gap in a real-world program. Often the normal flow of the responder chain will be interrupted by delegation. A specific object (usually a view) delegates another object (usually a view controller) to act for it. We already saw this put to use in our table view in chapter 13, but we now understand that a delegation occurs as part of the normal movement up the responder chain. If an event gets all the way up through the responder chain to the window and it can’t deal with an event, then it moves up to the UIApplication itself, which most fre- quently punts the event to its own delegate: the application delegate, an object that we’ve been using in every program to date. App Delegate The Application The Window First Responder Figure 14.1 Events on the iPhone are initially sent to the first responder, but then travel up the responder chain until someone accepts them. 242 CHAPTER 14 Monitoring events and actions Ultimately you, the programmer, will be the person who decides what in the re- sponder chain will respond to events in your program. You should keep two factors in mind when you make this decision: how classes of events can be abstracted together at higher levels in your chain, and how you can build your event management using the concepts of MVC. At the end of this section we’ll address how you can subvert this responder chain by further regulating events, but for now let’s build on its standard setup. 14.1.2 Touches and events Now that you know a bit about how events find their way to the appropriate object, we can dig into how they’re encoded by the SDK. First we want to offer a caveat: usually you won’t need to worry about this level of detail because the standard UIKit objects will generally convert low-level events into higher-level actions for you, as we discuss in the second half of this chapter. With that said, let’s look at the nuts and bolts of event encoding. The SDK abstracts events by combining a number of touches (which are repre- sented by UITouch objects) into an event (which is represented by a UIEvent object). An event typically begins when the first finger touches the screen and ends when the last finger leaves the screen. In addition, it should generally only include those touches that happened in the same view. In this chapter we’ll work mainly with UITouch es (which make it easy to parse sin- gle-touch events) and not with UIEvent s (which are more important for parsing multi- touch events). Let’s lead off with a more in-depth look at each. First responders and keyboards Before we leave this topic of responders behind, we’d like to mention that the first responder is a very important concept. Because this first responder is the object that can accept input, it’ll sometimes take a special action to show its readiness for input. This is particularly true for text objects like UITextField and UITextView , which (if editable) will pop up a keyboard when they become the first responder. This has two immediate consequences. If you want to pop up a keyboard for the text object, you can do so by turning it into the first responder: [myText becomeFirstResponder]; Similarly, if you want to get rid of a keyboard, you must tell your text object to stop being the first responder: [myText resignFirstResponder]; We’ll discuss these ideas more when we encounter our first editable text object to- ward the end of this chapter. 243An introduction to events UITOUCH REFERENCE A UITouch object is created when a finger is placed on the screen, moves on the screen, or is removed from the screen. A handful of properties and instance methods can give you additional information on the touch, as detailed in table 14.1. Together the methods and properties shown in table 14.1 offer considerable informa- tion on a touch, including when and how it occurred. Only the phase property requires additional explanation. It returns a constant that can be set to one of five values: UITouchPhaseBegan , UITouchPhaseMoved , UITouch- PhaseStationary , UITouchedPhaseEnded , or UITouchPhaseCancelled . You’ll often want to have different event responses based on exactly which phase a touch occurred in, as you’ll see in our event example. UIEVENT REFERENCE To make it easy to see how individual touches occur as part of more complex gestures, the iPhone SDK organizes UITouch es into UIEvent s. Figure 14.2 shows how these two sorts of objects interrelate. Just as with the UITouch object, the UIEvent object contains a number of properties and methods that you can use to figure out more information about your event, as described in table 14.2. Table 14.1 Additional properties and methods can tell you precisely what happened during a touch event. Method or property Type Summary phase Property Returns a touch phase constant, which indicates whether touch began, moved, ended, or was canceled tapCount Property The number of times the screen was tapped timestamp Property When the touch occurred or changed view Property The view where the touch began window Property The window where the touch began locationInView: Method Gives the current location of the touch in the specified view previousLocationInView: Method Gives the previous location of the touch in the specified view UITouch phase: UITouchPhaseBegan locationInView: (10,15) UITouch phase: UITouchPhaseEnded locationInView: (28,32) UITouch phase: UITouchPhaseMoved locationInView: (28,32) UIEvent Figure 14.2 UIEvent objects contain a set of related UITouch objects. 244 CHAPTER 14 Monitoring events and actions The main use of a UIEvent method is to give you a list of related touches that you can break down by several means. If you want to get a list of every touch in an event, or if you want to specify just gestures on a certain part of the screen, then you can do that with UIEvent methods. This ends our discussion of event containers in this chapter. Note that all of these methods compact their touches into an NSSet , which is an object defined in the Foundation framework. You can find a good reference for the NSSet at Apple’s developer resources site. THE RESPONDER METHODS So, how do you actually access these touches and/or events? You do so through a series of four different UIResponder methods, which are summarized in table 14.3. Each of these methods has two arguments: an NSSet of touches that occurred during the phase in question and a UIEvent that provides a link to the entire event’s worth of touches. You can choose to access either one, as you prefer; as we’ve said, we’re going to be playing with the bare touches. With that said, we’re now ready to dive into an actual example that demonstrates how to capture touches in a real-life program. 14.2 A touching example: the event reporter Our sample application for events is something we call the event reporter, which will offer a variety of responses depending on how and when the iPhone screen is touched. We have two goals with our sample program. Table 14.2 The encapsulating event object has a number of methods and properties that let you access its data. Method or property Type Summary timestamp Property The time of the event allTouches Method All event touches associated with the receiver touchesForView: Method All event touches associated with a view touchesForWindow: Method All event touches associated with a window Table 14.3 The UIResponder methods are the heart of capturing events. Method Summary touchesBegan:withEvent: Reports UITouchPhaseBegan events, for when fingers touch the screen touchesMoved:withEvent: Reports UITouchPhaseMoved events, for when fingers move across the screen touchesEnded:withEvent: Reports UITouchPhaseEnded events, for when fingers leave the screen touchesCancelled:withEvent: Reports UITouchPhaseCancelled events, for when the phone is put up to your head, or other events that might cause an external cancellation 245A touching example: the event reporter First, we want to show you a cool and simple application that you can write using events, one that should get you thinking about everything you can do. Second, we want to show some of the low-level details of how events work in a visual form. Therefore, if you actually take the trouble to code and compile this program, you’ll gain a better understanding of how the various phases work as well as how tap- ping works. You’ll kick off this development process by creating a project named eventreporter that uses the View-Based Application template. That means you’ll start with a view con- troller already in place. We’ll also use this example to show how an MVC program can be structured. 14.2.1 Setting things up in Interface Builder By now you should be comfortable enough with Interface Builder that you can set up all of your basic objects using it. For this program we’ve decided that we want to create three new objects: two button-shaped objects that will float around the screen to mark the beginning and end of touches, plus a status bar to go at the bottom of the screen and describe a few other events when they occur. Because you want all of our new objects to lie beneath the view controller in the view hier- archy, you call up the view controller’s own .xib file, eventreporterViewController.xib. As usual, you’ll add your new objects to the Main Display window that represents the view con- troller’s view. All of your work in Interface Builder is, of course, graphical, so we can’t show the code of this programming process. However, we have included a quick summary of the actions you should take. The results are shown in fig- ure 14.3. ■ Set the background color of the UIView to an attractive aluminum color. You do this on the Attributes tab of the Inspector window, as you would with most of your work in this project. ■ Create a UILabel , stretch it across the bottom of the screen, and set the color to be steel. Also, clear out its text so that it doesn’t display anything at startup. ■ Create two UITextField s. This class of objects is generally used to accept input, but we opted to use the objects for our pure display purposes because we liked their look. (Don’t worry; we’ll show how to use the full functionality of a UIText- Field toward the end of this chapter.) Figure 14.3 Two UITextFields (one of them hidden) and one UILabel, all set against an aluminum-colored background, complete the object creation we’ll need for our eventreporter project. 246 CHAPTER 14 Monitoring events and actions ■ Center each UITextField at the center of the screen using Interface Builder’s handy positioning icons. This location’s coordinates will be 159, 230. ■ For each UITextField , input text that lists its starting position; this will later be updated by the program as the text field moves. Deselect the user interac- tion–enabled option for each UITextField so that users can’t manipulate them. The process takes longer to explain than it takes to accomplish. You’ll have a working interface in just a couple of minutes. CREATING IBOUTLETS Because you’ll modify all three of these objects during the course of your program’s runtime, you need to link them to variables inside Xcode. You’ll want to link every- thing to your controller, since it’ll be taking care of updates, as is appropriate under the MVC model. The tricky thing here is that the view controller doesn’t seem to appear in our eventreporterViewController.xib file—at least not by that name. Fortunately, there’s a proxy for it. Since the view controller is what loads up the .xib, it appears as the file’s owner in the nib document window. You can therefore connect objects to the view controller by linking them to the file’s owner proxy. This is a common situation, since view controllers frequently load additional .xib files for you. Listing 14.1 shows your view controller’s header file, eventreportViewController.h, following the addition of these IBOutlet s. The listing also contains a declaration of a method that you’ll use later in this project. @interface eventreporterViewController : UIViewController { IBOutlet UITextField *startField; IBOutlet UITextField *endField; IBOutlet UILabel *bottomLabel; } - (void)manageTouches:(NSSet *)touches; @end To finish up this process, you connect your Interface Builder objects to the IBOutlet s, using the procedures described in chapter 12. 14.2.2 Preparing a view for touches Touch events can only be captured by UIView objects. Unfortunately, as of this writing, there’s no way to automatically delegate those touches to a view controller. Therefore, in order to manage touch events using the MVC model, you’ll typically need to sub- class a UIView, capture the events there, and then send messages to the view control- ler. In your project you’ll create a new object class, reportView , which is a subclass of UIView . You then link that new class into the view controller’s existing view through Interface Builder. You open up eventreporterViewController.xib, go to the Identity tab Listing 14.1 An IB-linked header 247A touching example: the event reporter for the view object that you’ve been using, and change its name from UIView to reportView , just as you did in chap- ter 13 when you created a table view controller subview. Any new methods that you write into reportView , including methods that capture touch events, will be now reflected in your view. To clarify this setup, figure 14.4 shows the view hierarchy that you’ve built for your even- treporter project. With a brand-new UIView subclass in hand, you can now write methods into it to capture touch events and forward them on to its controller. This code, which appears in reportView.m , is shown in listing 14.2. - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.nextResponder manageTouches:touches]; } - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self.nextResponder manageTouches:touches]; } - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [self.nextResponder manageTouches:touches]; } The code in listing 14.2 is pretty simple. You’re just filling in standard methods so that your program will have the responses you want when those messages are sent. The overall structure of these methods reminds us of several important facts about events. First, as promised, there are a variety of responder methods. Each of them reports only the events for their specific phase. So, for example, the touchesBegan:with- Event: method would only have UITouchPhaseBegan touches in it. In forwarding on these touches we could have kept the different phases distinct, but we’ve instead decided to throw everything together and sort it out on our own on the other side. Second, we’ll comment one final time that these methods send us two pieces of information: a set of touches and an event. They are partially redundant, and which one you work with will probably depend on the work you’re doing. If you’re not doing complex multi-touch events, then the NSSet of touches will probably be sufficient. Third, note that you’re sending the touches to the view controller by way of the nextResponder method. As you’ll recall, the responder chain is the opposite of the view hierarchy at its lower levels, which means in this case the nextResponder of reportView is the UIViewController . We would have preferred to have the UIView- Controller just naturally respond to the touches messages, but we made use of our responder chain in the next best way. As of this writing, the compiler warns that next- Responder may not know about the manageTouches method, but it will; this warning can be ignored. Listing 14.2 A collection of methods report touches in UIViews UIViewController UIWindow reportView UILabel UITextFieldUITextField Figure 14.4 Working primarily in Interface Builder, we’ve connected up six objects that we’ll be using to report iPhone events. 248 CHAPTER 14 Monitoring events and actions We’ll see some other ways to use the nextResponder method toward the end of our discussion of events. AN ASIDE ON THE TEXT FIELDS AND LABEL If you were to actually code in this example, you’d discover that this program correctly responds to touch events even when the touches occurred atop one of the text fields or the label at the bottom of the page. How does your program manage that when you only built event response into the reportView ? The answer is this: it uses the responder chain. The text fields and the label don’t respond to the event methods themselves. As a result, the events get passed up the responder chain to the reportView , which does leap on those events, using the code we’ve just seen. 14.2.3 Controlling your events Intercepting touches and forwarding them up to the view controller may be the toughest part of this code. Once the events get to the view controller, they run through a simple method called manageTouches: , as shown in listing 14.3. ::eventreporterViewController.m:: - (void)manageTouches:(NSSet *)touches { for (UITouch *touch in touches) { if (touch.phase == UITouchPhaseBegan) { CGPoint touchPos = [touch locationInView:self.view]; startField.center = touchPos; startField.text = [NSString stringWithFormat: @"Begin: %3.0f,%3.0f",touchPos.x,touchPos.y]; } else if (touch.phase == UITouchPhaseMoved) { bottomLabel.text = @"Touch is moving "; } else if (touch.phase == UITouchPhaseEnded) { if (touch.tapCount > 1) { bottomLabel.text = [NSString stringWithFormat: @"Taps: %2i",touch.tapCount]; } else { bottomLabel.text = [NSString string]; } CGPoint touchPos = [touch locationInView:self.view]; endField.center = touchPos; endField.text = [NSString stringWithFormat: @"End: %3.0f,%3.0f",touchPos.x,touchPos.y]; } } } Touches are sent as an NSSet , which can be broken apart in a number of ways, as described in the NSSet class reference. Here, you’ll use a simple for … in construc- tion B that lets you look at each touch in turn. Listing 14.3 manageTouches, which accepts inputs and changes views B C D E C C F 249A touching example: the event reporter Once you get a touch, the first thing you do is determine what phase it arrived in. Originally you could have determined this information based on which method a touch arrived through, but since we combined everything you have to fall back on the phase property. Fortunately, it’s easy to use. You just match it up to one of three con- stants C , and that determines which individual actions your program undertakes. Having different responses based on the phase in which a touch arrive is com- mon—which is in fact why the event methods are split up in the first place. Our exam- ple demonstrates this with some distinct responses: you move your start field when touches begin, you move your end field when touches end, and you update the bot- tom label in both the moved and ended phases. In your UITouchPhaseBegan response, you delve further into your touch’s data by using the locationInView: method to figure out the precise coordinates where a touch occurred D . You’re then able to use that data to reposition your text field and to report the coordinates in the text field E . You later do the same thing in the UITouchPhaseEnded response. Finally, you take a look at the tapCount in the UITouchPhaseEnded response F . This is generally the best place to look at taps since the iPhone now knows that the user’s finger has actually come off the screen. As you can see, it’s easy to both run a command based on the number of taps and to report that information. Figure 14.5 shows what your event responder looks like in action. You should imagine a finger that set down on the space where the begin text field is sit- ting and that is currently moving across the screen. And with that, your event reporter is complete. Besides illustrating how a program can respond to touches, we have highlighted how the MVC model can be used in a real application. Your project contained four views: a reportView , a UILabel , and two UITextField s. It was tempting to process events in the reportView itself, especially since you had to create a subclass anyway, but instead you pushed the events up to the view controller, and in doing so revealed why you’d want to do MVC modeling. Since it takes on the controller role, you gave the view controller access to all of its individual objects, and therefore you didn’t have to try to remember what object knew about what other object. Tying things into the view controller, rather than scattering them randomly across your code, made your project that much more readable and reusable, which is what most architectural and design patterns are about. Figure 14.5 Your event responder uses a few graphical elements to report events as they occur. [...]... that, we point you, as usual, to the Apple iPhone developer website There’s a good tutorial on multi-touch events available as part of the iPhone OS Programming Guide that you should read if you’re one of that smaller percentage of developers—such as programmers creating games and novelties—who might need access to multi-touches and more complex gestures 14. 4 An introduction to actions So if you’re... NSNotification, and NSNotificationQueue 14. 8 Summary The iPhone OS includes an extensive set of frameworks that takes care of lots of the details for you, making your iPhone programming as painless as possible We’ve seen this to date in everything we’ve done, as sophisticated objects appear on our screens with almost no work Summary 263 The same applies to the iPhone s event system There is a complex...250 CHAPTER 14 Monitoring events and actions 14. 3 Other event functionality Before we complete our discussion of events entirely, we’d like to cover a few more topics of interest We’re going to explore how to regulate the report of events in a variety of ways and then describe some deficiencies in the event model 14. 3.1 Regulating events As we mentioned earlier,... thing about using a UITextField is getting it to relinquish control of your iPhone after you call up a keyboard Listing 14. 6 shows the two steps needed to resolve this problem We’re assuming that you’re working with a myText UITextField object created inside Interface Builder and instantiated inside a view controller Listing 14. 6 A few commands required to get a UITextField working - (void)viewDidLoad... references, including lots of methods and properties that we didn’t talk about 14. 6.4 Actions made easy Throughout the latter half of this chapter we’ve seen controls that were tied to the fully fledged targetFigure 14. 9 A text field and a action mechanism In the next chapter, that’s going slider conspire to set the color of the iPhone s background to change a bit when we see the same idea in a somewhat... We’ll point this technique out when we encounter it as part of the navigation controller 14. 6.5 Actions in use There are numerous control objects that we’ve opted not to cover here, mainly because they use the same general principles as those we’ve already talked about Nonetheless, they’ll remain an important factor throughout the rest of this book In particular, controls represent one of the main ways... expect once you know the secret to accessing them 14. 3.2 Other event methods and properties We’ve spent a lot of time on events, but at the same time we’ve only scratched the surface We have mixed feelings on the subject On the one hand, events give you low-level access to the unique user input allowed by the iPhone Since much of this book is about how the iPhone is unique, we’d like to delve into it much... UIControlEventValueChanged A slider (or other similar) object changed its value UIControlEventEditingDidBegin Editing began in a UITextField UIControlEventEditingChanged Editing changed in a UITextField 254 CHAPTER 14 Table 14. 5 Monitoring events and actions UIControl objects recognize a number of special events (continued) Value Summary UIControlEventEditingDidEnd Editing ended in a UITextField due to a touch outside... aware that a UIControl object turns a touch event first into a control event and then into an action with a specific recipient Even better, it’s only the last part of that conversion, from control event into targeted action, that you need to code 14. 4.3 The addTarget:action:forControlEvents: method A UIControl object maintains an internal dispatch table that correlates control events with target-action... forControlEvents:, is a bitmasked list of possible control events, taken from table 14. 5 With all these puzzle pieces in place, you’re now ready to write some code that will make actual use of actions (and this method) As a simple example, you’re going to expand the functionality to your event reporter by adding a “reset” button 14. 5 Adding a button to an application The simplest use of an action is probably . how individual touches occur as part of more complex gestures, the iPhone SDK organizes UITouch es into UIEvent s. Figure 14. 2 shows how these two sorts. about. Figure 14. 5 Your event responder uses a few graphical elements to report events as they occur. 250 CHAPTER 14 Monitoring events and actions 14. 3 Other

Ngày đăng: 26/01/2014, 18:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan