1 00:00:05,620 --> 00:00:10,960 Our flickr browser app's coming along nicely, and in the process we've covered a lot of techniques that 2 00:00:10,960 --> 00:00:13,300 you'll find useful in your own apps. 3 00:00:13,520 --> 00:00:19,240 It's time now to extend the flickr browser to display a photo full screen when the user taps it. 4 00:00:19,540 --> 00:00:25,020 Now we're going to need some way to detect that an item in the recycler view was tapped. 5 00:00:25,060 --> 00:00:27,650 We also need to know which item was tapped. 6 00:00:27,660 --> 00:00:33,040 Now one consequence of Google's simplification of the recycler view, is that it no longer has an easy 7 00:00:33,040 --> 00:00:35,610 way to set an on click listener. 8 00:00:35,620 --> 00:00:40,630 Now there are a number of methods for detecting when an item in the list is tapped, and a common method 9 00:00:40,930 --> 00:00:42,320 is to implement the recycler 10 00:00:42,320 --> 00:00:46,460 view, that on item touch listener interface, in a class. 11 00:00:46,540 --> 00:00:48,270 Now we're going to do something similar, 12 00:00:48,470 --> 00:00:53,870 but we're going to extend the recycler view dot simple on item touch listener class instead. 13 00:00:53,870 --> 00:00:58,930 Now Google have created this class so that we don't have to implement methods of the interface that 14 00:00:58,930 --> 00:01:00,020 we won't use, 15 00:01:00,020 --> 00:01:03,890 and also to future proof our apps against changes to the recycler view. 16 00:01:03,950 --> 00:01:07,210 Now there's two interesting links I want to share with you. 17 00:01:07,210 --> 00:01:12,940 Firstly is the Google documentation on the on item touch listener interface. Let's have a look at that. 18 00:01:15,070 --> 00:01:20,760 So if you decide to implement the interface that's a good starting point, and that page contains a link 19 00:01:20,760 --> 00:01:27,770 to the simple onItemTouchListener, which is this one here. You can click on that and check that out as well. 20 00:01:27,800 --> 00:01:29,730 So both of those are well worth reading. 21 00:01:29,870 --> 00:01:34,940 And they mentioned at the start that extending this class is useful, if you don't want to implement all 22 00:01:34,940 --> 00:01:36,840 the methods of the interface. 23 00:01:37,130 --> 00:01:42,860 Now they also guarantee to always provide a default implementation in this class if things do change, 24 00:01:43,030 --> 00:01:45,620 so that existing code won't break. 25 00:01:45,620 --> 00:01:52,010 So for that reason alone it's worth considering extending the simple on item touch listener class, rather 26 00:01:52,010 --> 00:01:55,040 than implementing the on item touch listener interface, 27 00:01:55,250 --> 00:01:56,960 and that's what I'm going to do here. 28 00:01:57,320 --> 00:02:03,510 Now if you want to use an interface, the approach is very similar to what we're going to do. 29 00:02:03,860 --> 00:02:08,820 In fact the class constructor and functions we defined can be used and changed. 30 00:02:08,870 --> 00:02:13,580 You just have to override another couple of functions, even if you don't use them. 31 00:02:13,580 --> 00:02:16,940 Now before we get into the code, there's also another way to do this 32 00:02:16,950 --> 00:02:18,630 that's actually pretty neat. 33 00:02:18,650 --> 00:02:22,880 Now I just want to draw your attention to a pretty cool article. I'm just going to bring that up on the 34 00:02:22,880 --> 00:02:24,510 screen. 35 00:02:25,730 --> 00:02:29,740 All these links as normal, are in the resources section of this video. 36 00:02:31,260 --> 00:02:36,570 And that actually gives you another way to do it, so it could be cool if you want to investigate another 37 00:02:36,600 --> 00:02:37,810 approach. 38 00:02:37,860 --> 00:02:43,910 Now the first bit of code on this page shows what adding the listener looks like, and you can see that down here. 39 00:02:44,080 --> 00:02:49,930 And once you've created the class it's actually quite easy to add the listener to the recycler view. 40 00:02:50,310 --> 00:02:52,160 So you may want to look into that further, 41 00:02:52,410 --> 00:02:58,410 if you're using a lot of recycler views in the same app, but for this app we're going to extend this simple class, 42 00:02:58,500 --> 00:03:00,200 so let's get started with that. 43 00:03:00,530 --> 00:03:02,580 Alright so back to Android Studio. 44 00:03:02,880 --> 00:03:08,470 We need to create a new class, so as per normal we're going to right click the package name, 45 00:03:10,890 --> 00:03:18,380 New, Kotlin File/Class, I'm going to select Class as the kind, and we're going to go with the name Recycler 46 00:03:18,800 --> 00:03:20,280 ItemClickListener. 47 00:03:29,890 --> 00:03:34,300 That's RecyclerItemClickListener and we're doing, calling it that name because that's 48 00:03:34,300 --> 00:03:36,180 essentially what it is. 49 00:03:36,330 --> 00:03:38,590 Alright so for starters we'll 50 00:03:38,740 --> 00:03:51,860 start with the usual tag for logging, private val TAG equals two double quotes, RecyclerItemClickListen. 51 00:03:51,860 --> 00:03:54,570 Now once again be very careful with the length of the tag. 52 00:03:54,730 --> 00:03:58,690 Remember that you're actually only allowed 23 characters, 53 00:03:58,700 --> 00:04:00,550 so that's why I'm abbreviating that at the end. 54 00:04:01,430 --> 00:04:07,970 Now all the approaches to implement a recycler listener use a callback mechanism, which is the usual way 55 00:04:07,970 --> 00:04:12,050 of notifying an activity that something's being clicked. 56 00:04:12,050 --> 00:04:19,070 So consequently we need to find an interface that we can call back on. We're going to call ours the on recycler click listener, 57 00:04:19,170 --> 00:04:26,280 so let's implement that, or create that rather, so interface onRecyclerClickListener, then 58 00:04:30,140 --> 00:04:40,340 we want left and right curly brace's, and the two functions will be fun onItem, click, then in parentheses 59 00:04:40,390 --> 00:04:50,800 view colon View comma position colon int, and the second function will be fun 60 00:04:50,840 --> 00:04:58,100 onItemLongClick parentheses, and the same, so view colon View position 61 00:04:58,420 --> 00:04:59,940 colon int. 62 00:05:00,060 --> 00:05:07,050 So that's our interface. So basically these two functions that we've defined are for callbacks. onItemClick 63 00:05:07,050 --> 00:05:13,670 to respond to a normal tap on an item, and onItemLongClick if the item's long tapped. 64 00:05:13,740 --> 00:05:19,640 Now our class is going to need to know what to callback, which we do by providing a listener in the primary 65 00:05:19,650 --> 00:05:20,590 constructor, 66 00:05:20,700 --> 00:05:22,200 and we've done that a few times now. 67 00:05:22,590 --> 00:05:28,850 And we also need a context for the gesture detector to work, and a reference to the recycler view that we're 68 00:05:28,860 --> 00:05:30,470 detecting the taps on. 69 00:05:30,480 --> 00:05:34,800 So we're going to add those parameters to the constructor as well. Lets go up and do that. 70 00:05:34,970 --> 00:05:41,100 So we're going to change that now to print parentheses after the RecyclerItemClickListener, context 71 00:05:41,660 --> 00:05:51,460 colon Context comma recyclerView colon, RecyclerView, and obviously capitalisation's important here, 72 00:05:51,830 --> 00:05:55,120 comma private 73 00:05:55,850 --> 00:06:03,010 val listener colon OnRecyclerClickListener. 74 00:06:03,640 --> 00:06:07,410 And on the next line just to make a big of space here, I'm going to put colon, 75 00:06:07,590 --> 00:06:09,670 then we're going to return a RecyclerView 76 00:06:12,360 --> 00:06:17,800 dot SimpleOnItemTouchListener parentheses. 77 00:06:19,750 --> 00:06:21,110 OK. 78 00:06:21,530 --> 00:06:25,800 So we've seen the listener used a few times to store the object that we'll be calling back, 79 00:06:25,970 --> 00:06:28,830 but what's this gesture detector all about. 80 00:06:29,120 --> 00:06:34,210 So far we've responded to simple taps on widgets, such as buttons or the list view. 81 00:06:34,490 --> 00:06:39,480 Now Android provides a load of ways that a user can interact with apps, including things like long 82 00:06:39,500 --> 00:06:42,420 tapping, swiping and drawing patterns. 83 00:06:42,420 --> 00:06:45,460 Now these are all handled by a gesture detector. 84 00:06:45,890 --> 00:06:52,310 So I'm going to use the gesture detector compat class so that our app's compatible with earlier Android 85 00:06:52,310 --> 00:06:59,240 versions. Now you can find the reference documentation on the gesture detector class by googling the class name. Now Google 86 00:06:59,240 --> 00:07:03,320 also provide a training document which will come up in the search results. 87 00:07:03,710 --> 00:07:10,790 If we go over and just have a quick look at that. Go to Google and we'll do a search for a 88 00:07:16,410 --> 00:07:22,020 gesture detector. You can see this first option up here, we'll click on into that. So if you want to know more when you come to write 89 00:07:22,020 --> 00:07:28,150 apps that use more complex gestures, then you'll find what you need to get started in these links. And I'm pushing 90 00:07:28,170 --> 00:07:34,860 the documentation a lot, because frankly you can't be a successful developer without taking full advantage 91 00:07:34,860 --> 00:07:37,830 of all the resources available on the internet. 92 00:07:37,830 --> 00:07:43,570 Things are changing so fast, and there's just so much that Android can do that you just can't learn all 93 00:07:43,570 --> 00:07:44,330 of it. 94 00:07:44,340 --> 00:07:47,380 The trick is to learn what you need when you need it, 95 00:07:47,430 --> 00:07:53,380 building on what you know about how the Android classes work, and how Android itself handles things. 96 00:07:53,490 --> 00:07:58,620 Now we started writing the Java version of this course, which was based on Android Nougat, at around 97 00:07:58,620 --> 00:08:03,650 the same time that Samsung started deploying Marshmallow on their devices. 98 00:08:03,690 --> 00:08:06,980 Most devices out there were still on Lollipop or earlier. 99 00:08:07,260 --> 00:08:11,910 So that means that we were using a version of Android that was two versions further on than most 100 00:08:11,910 --> 00:08:12,720 devices. 101 00:08:13,110 --> 00:08:18,570 So working in an environment that's changing so rapidly, frankly we'd be completely lost without access 102 00:08:18,570 --> 00:08:22,150 to all the information that Google and others make available. 103 00:08:22,530 --> 00:08:24,270 Alright so back to Android Studio. 104 00:08:24,660 --> 00:08:30,770 So this RecyclerItemClickListener class extends the SimpleOnItemTouchListener. 105 00:08:30,960 --> 00:08:36,070 I think I said earlier that it actually returns it but it's basically extending it, the RecyclerView.Simple 106 00:08:36,179 --> 00:08:43,809 OnItemTouchListener, and we can override the on interrupt touch event function to intercept or touch events 107 00:08:43,809 --> 00:08:49,840 that happen on the recycler view. So the function will be called whenever any sort of touch happens, whether 108 00:08:49,840 --> 00:08:52,580 it's a tap, a double tap, a swipe or whatever. 109 00:08:52,870 --> 00:08:59,710 So I'm going to get the code generator to override the on intercept touch event function, after our interface 110 00:08:59,710 --> 00:09:05,050 declaration and then log the method call. And we're extending a class here by the way, not implementing an interface. 111 00:09:05,250 --> 00:09:11,570 So I'm going to come down here after the interface declaration and do a control o. 112 00:09:12,340 --> 00:09:18,670 So we want to override the onInterceptTouchEvent, which is this one here. 113 00:09:18,800 --> 00:09:26,440 So as I mentioned I'm going to add some logging, so we'll do that, so Log.d parentheses TAG comma double quotes dot on 114 00:09:26,450 --> 00:09:27,890 Intercept 115 00:09:28,370 --> 00:09:37,980 TouchEvent colon starts dollar e. So let's leave it at that for now, 116 00:09:38,070 --> 00:09:43,170 and connect this listener to the recycler view in main activity's onCreate method. 117 00:09:43,210 --> 00:09:49,960 So I'm going to go ahead and open that up, there's our onCcreate. So first we're going to make MainActivity 118 00:09:50,300 --> 00:09:57,380 implement the onRecyclerClickListener interface so that we can pass the activity rather than using anonymous 119 00:09:57,380 --> 00:09:58,310 classes. 120 00:09:58,380 --> 00:10:03,610 Now we did that before when we used the MainActivity as the listener for the buttons in the YouTube app. 121 00:10:04,070 --> 00:10:06,460 So this line is going to get a little bit long now, 122 00:10:06,470 --> 00:10:08,160 so I'm going to split it up. 123 00:10:08,220 --> 00:10:11,330 So we've class main activity and we've got our appcompat activity. 124 00:10:11,540 --> 00:10:13,200 We've got our on download complete. 125 00:10:13,250 --> 00:10:13,610 So let's go to a new line 126 00:10:13,610 --> 00:10:18,100 there, and put on GetFlickrJsonData dot 127 00:10:18,290 --> 00:10:19,580 OnDataAvailable. 128 00:10:19,650 --> 00:10:20,650 We need to add the next one now, 129 00:10:20,660 --> 00:10:31,520 so put a comma, then go onto the next line, and it's going to be RecyclerItemClickListener dot OnRecycler 130 00:10:31,880 --> 00:10:32,840 ClickListener. 131 00:10:35,850 --> 00:10:40,630 Now we need to implement the two functions and obviously main activity wants us to do that now, 132 00:10:40,660 --> 00:10:42,260 and that's what it's complaining about. 133 00:10:42,720 --> 00:10:47,870 So let's get the generator to create the stubs for those two functions after the onCreate method, so we'll just 134 00:10:47,900 --> 00:10:48,420 draw 135 00:10:48,480 --> 00:10:48,750 down here, 136 00:10:51,830 --> 00:10:58,720 control i, and we're going to select both of those and click on OK. Let's also add some logging to both, 137 00:10:58,910 --> 00:11:01,630 and we'll also add a Toast message as well so we can see what's going on. 138 00:11:01,690 --> 00:11:04,130 So firstly onItemClick Log.d 139 00:11:04,130 --> 00:11:13,320 parentheses TAG comma double quotes dot onItemClick colon starts. 140 00:11:13,980 --> 00:11:28,250 Then we want Toast dot makeText parentheses this comma Normal tap at position dollar position, and then we want 141 00:11:28,910 --> 00:11:42,920 to put a comma after the double quote, Toast dot Length Short parentheses dot show. And for the long 142 00:11:43,220 --> 00:11:52,240 click we're going to put Log.d parentheses TAG comma dot onItemLongClick 143 00:11:56,090 --> 00:12:00,300 starts, and then we'll do a Toast dot 144 00:12:00,320 --> 00:12:10,880 makeText parentheses, and it's going to be this again, double quotes Long tap at position dollar position, 145 00:12:12,220 --> 00:12:19,120 then we'll do a comma Toast dot length short closing parentheses dot show. 146 00:12:19,640 --> 00:12:20,560 OK. 147 00:12:21,410 --> 00:12:26,030 And obviously now Android Studio's happy we've implemented those two functions. 148 00:12:26,030 --> 00:12:31,660 So all that's left to do now to see our click events, is to create a new instance of our RecyclerItemClickListener 149 00:12:31,670 --> 00:12:36,240 class and add it as a touch listener to the recycler view. 150 00:12:36,660 --> 00:12:39,880 So let's do that and we'll do that up here. 151 00:12:40,500 --> 00:12:48,200 Actually what we'll do, we'll just do it immediately after the linear layout and before we actually set the adapter. 152 00:12:48,290 --> 00:12:59,300 So I'll put it on here, so it's recycler underscore view dot addOnItemTouchListener parentheses RecyclerItem 153 00:12:59,300 --> 00:13:01,810 ClickListener parentheses, 154 00:13:02,000 --> 00:13:10,740 this comma recycler underscore view comma this, and the two closing right parentheses. 155 00:13:11,670 --> 00:13:17,040 And in case you're wondering with the two this's here, we're passing it as both the context, because 156 00:13:17,040 --> 00:13:23,460 it's an activity, and the listener, because we've implemented the required interface. Now before running 157 00:13:23,820 --> 00:13:29,040 the program, I'm going to comment out the logging of get item count in the FlickrRecyclerView 158 00:13:29,060 --> 00:13:30,070 Adapter, 159 00:13:30,830 --> 00:13:32,700 just to keep the log cat a little bit clearer. 160 00:13:32,940 --> 00:13:35,780 We know that's working now way anyway so there's no need to continue logging it. 161 00:13:36,060 --> 00:13:37,370 So let's comment that out, 162 00:13:41,090 --> 00:13:42,090 like so. 163 00:13:42,870 --> 00:13:47,930 And also we don't need to log the photo details either, your onBindViewHolder, 164 00:13:47,990 --> 00:13:49,090 so let's actually 165 00:13:49,280 --> 00:13:51,800 comment that out as well, that's this line 166 00:13:51,800 --> 00:13:59,010 here. Alright so let's open up log cat, and I'll clear it, and let's run our app. 167 00:14:08,900 --> 00:14:16,940 Alright so I'll just let it start, and making sure now that you can actually see log cat, which we can. I'm going to click once on the app 168 00:14:16,940 --> 00:14:17,880 in the emulator. 169 00:14:18,050 --> 00:14:24,260 When we do that you should actually see the onInterceptTouchEvent method being called twice, and you can 170 00:14:24,260 --> 00:14:27,650 see that onInterceptTouchEvent was called twice there. 171 00:14:27,740 --> 00:14:30,340 Now whenever you interact with an android screen, 172 00:14:30,350 --> 00:14:34,970 there's actually quite a few events generated. Now here the function's being called when it detects 173 00:14:34,970 --> 00:14:41,050 the touch, but also when the quote unquote finger is lifted off the screen, or mouse in my case. 174 00:14:41,090 --> 00:14:44,460 So in other words we're getting two touch events for each tap. 175 00:14:44,630 --> 00:14:48,650 Now let's try clicking and holding the mouse button down for a long tap. 176 00:14:49,000 --> 00:14:50,460 So I'm going to do that on another one, and I'll just 177 00:14:55,130 --> 00:15:00,080 do that again. So hold it down and you can notice that there was one, and then when I released the button it 178 00:15:00,290 --> 00:15:01,710 went again, so I'm going to do it again, do a long tap 179 00:15:01,970 --> 00:15:07,110 this time - there's the one event. I'm holding the mouse button down, and when I release the mouse button, 180 00:15:07,250 --> 00:15:12,130 we see the second event. It's also interesting to see what happens when I scroll and fling the list. 181 00:15:12,130 --> 00:15:17,660 So when I scroll, notice that we're getting an action down. I'll just move this over a little bit more so we can see that a little bit 182 00:15:17,660 --> 00:15:18,630 more clearer. 183 00:15:18,960 --> 00:15:25,120 And I'll just do it again so we can see. So notice that we're getting some action down, we've got an action down, followed 184 00:15:25,120 --> 00:15:30,250 by a series of action moves, and finally there's an action up when I release the mouse, 185 00:15:30,250 --> 00:15:33,780 and that's the equivalent of lifting my finger off the screen on a real phone. 186 00:15:33,860 --> 00:15:35,690 So if I do a bit of a fling here, 187 00:15:35,810 --> 00:15:39,290 well that should result in the same sequence of events, just much faster, 188 00:15:42,680 --> 00:15:43,650 like so. 189 00:15:44,240 --> 00:15:50,060 So when I scroll we get an action underscore down action, followed by a series of action underscore 190 00:15:50,230 --> 00:15:53,020 move events as I scroll. 191 00:15:53,150 --> 00:15:57,170 And you can see that happening as I'm slowly scrolling, then I release the mouse button and we get the action 192 00:15:57,170 --> 00:15:57,970 up again. 193 00:15:58,760 --> 00:16:03,390 So there's loads of touch events being generated as we interact with the screen. 194 00:16:03,800 --> 00:16:08,130 Now obviously we can't go trying to display a full screen picture on all of them. 195 00:16:08,150 --> 00:16:10,180 In fact it's quite easy to break things. 196 00:16:10,490 --> 00:16:18,190 So let's make a change to the function in the listener to see how. Now in the onInterceptTouchEvent in the Recycler 197 00:16:18,190 --> 00:16:19,540 ItemClickListener class, 198 00:16:23,480 --> 00:16:25,240 I'm going to return true, 199 00:16:25,460 --> 00:16:30,590 instead of returning the result of the call to the Super Method. So in other words I want to comment that 200 00:16:30,590 --> 00:16:33,230 out, and on the next line 201 00:16:33,230 --> 00:16:37,810 I'm just going to put return true. 202 00:16:37,940 --> 00:16:44,110 So if I stop that and run it again, and I'll open up the log cat as well, 203 00:16:49,550 --> 00:16:57,520 and now when I click, we still get two method calls logged - action down and action up. Now if I hold the mouse 204 00:16:57,520 --> 00:17:04,130 button down, we still get a single call, then the other, when I release it. Now I'm not sure if you'll be 205 00:17:04,130 --> 00:17:06,680 able to see this too well on the video. 206 00:17:06,849 --> 00:17:14,150 But if I try to scroll, I'm trying to scroll as I did earlier in this video. Nothing's actually happening. 207 00:17:14,150 --> 00:17:20,810 I can't actually scroll, and we're getting those event actions as you can see over here, so we're still getting the action move after 208 00:17:20,810 --> 00:17:25,550 the download event, just a single one as you can see, but the recycler view is no longer scrolling through 209 00:17:25,550 --> 00:17:26,130 the list. 210 00:17:26,270 --> 00:17:31,340 So in other words we're not getting any more action moves either, as we got previously, just a single 211 00:17:31,340 --> 00:17:32,200 one. 212 00:17:32,210 --> 00:17:38,480 So what I've done here by using this return TRUE, is intercepted the touch event, then told the system 213 00:17:38,480 --> 00:17:40,810 that we've handled every single event. 214 00:17:40,840 --> 00:17:45,530 So in other words that tells Android that nothing else needs to handle these events, which is what happens when 215 00:17:45,530 --> 00:17:46,690 we return true. 216 00:17:47,030 --> 00:17:52,730 So if we handle a particular touch event, then we can return true so that nothing else tries to 217 00:17:52,730 --> 00:17:53,610 handle it. 218 00:17:53,720 --> 00:17:59,000 But if we don't handle it, then we have to return false so that whatever else is listening can do its 219 00:17:59,020 --> 00:18:00,120 stuff. 220 00:18:00,140 --> 00:18:05,870 In fact if we don't return false, we should return the result of calling the super method, because that 221 00:18:05,870 --> 00:18:10,940 gives anything else that's listening for events a chance to respond. 222 00:18:11,000 --> 00:18:15,980 So as you can see this is far more complex than responding to simple clicks, like we did with buttons 223 00:18:15,980 --> 00:18:19,320 or the list view widget, but it's starting to make sense. 224 00:18:19,400 --> 00:18:25,450 This approach that the Android framework's taking makes the recycler view far more flexible than the simpler 225 00:18:25,450 --> 00:18:26,300 list view. 226 00:18:26,510 --> 00:18:31,100 So we can now intercept touch events, and we can let the system handle the ones we don't want to deal 227 00:18:31,100 --> 00:18:32,210 with. 228 00:18:32,210 --> 00:18:36,420 So that just leaves us with one more question. How do we decide which ones to deal with? 229 00:18:36,650 --> 00:18:39,360 Well that's where the gesture detector comes in. 230 00:18:39,440 --> 00:18:41,910 So I'm going to stop the video here. In the next video, 231 00:18:42,020 --> 00:18:44,400 we'll see how to use a gesture detector. 232 00:18:44,570 --> 00:18:45,930 See you in the next video.