Our flickr browser app's coming along nicely, and in the process we've covered a lot of techniques that
you'll find useful in your own apps.
It's time now to extend the flickr browser to display a photo full screen when the user taps it.
Now we're going to need some way to detect that an item in the recycler view was tapped.
We also need to know which item was tapped.
Now one consequence of Google's simplification of the recycler view, is that it no longer has an easy
way to set an on click listener.
Now there are a number of methods for detecting when an item in the list is tapped, and a common method
is to implement the recycler
view, that on item touch listener interface, in a class.
Now we're going to do something similar,
but we're going to extend the recycler view dot simple on item touch listener class instead.
Now Google have created this class so that we don't have to implement methods of the interface that
we won't use,
and also to future proof our apps against changes to the recycler view.
Now there's two interesting links I want to share with you.
Firstly is the Google documentation on the on item touch listener interface. Let's have a look at that.
So if you decide to implement the interface that's a good starting point, and that page contains a link
to the simple onItemTouchListener, which is this one here. You can click on that and check that out as well.
So both of those are well worth reading.
And they mentioned at the start that extending this class is useful, if you don't want to implement all
the methods of the interface.
Now they also guarantee to always provide a default implementation in this class if things do change,
so that existing code won't break.
So for that reason alone it's worth considering extending the simple on item touch listener class, rather
than implementing the on item touch listener interface,
and that's what I'm going to do here.
Now if you want to use an interface, the approach is very similar to what we're going to do.
In fact the class constructor and functions we defined can be used and changed.
You just have to override another couple of functions, even if you don't use them.
Now before we get into the code, there's also another way to do this
that's actually pretty neat.
Now I just want to draw your attention to a pretty cool article. I'm just going to bring that up on the
screen.
All these links as normal, are in the resources section of this video.
And that actually gives you another way to do it, so it could be cool if you want to investigate another
approach.
Now the first bit of code on this page shows what adding the listener looks like, and you can see that down here.
And once you've created the class it's actually quite easy to add the listener to the recycler view.
So you may want to look into that further,
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,
so let's get started with that.
Alright so back to Android Studio.
We need to create a new class, so as per normal we're going to right click the package name,
New, Kotlin File/Class, I'm going to select Class as the kind, and we're going to go with the name Recycler
ItemClickListener.
That's RecyclerItemClickListener and we're doing, calling it that name because that's
essentially what it is.
Alright so for starters we'll
start with the usual tag for logging, private val TAG equals two double quotes, RecyclerItemClickListen.
Now once again be very careful with the length of the tag.
Remember that you're actually only allowed 23 characters,
so that's why I'm abbreviating that at the end.
Now all the approaches to implement a recycler listener use a callback mechanism, which is the usual way
of notifying an activity that something's being clicked.
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,
so let's implement that, or create that rather, so interface onRecyclerClickListener, then
we want left and right curly brace's, and the two functions will be fun onItem, click, then in parentheses
view colon View comma position colon int, and the second function will be fun
onItemLongClick parentheses, and the same, so view colon View position
colon int.
So that's our interface. So basically these two functions that we've defined are for callbacks. onItemClick
to respond to a normal tap on an item, and onItemLongClick if the item's long tapped.
Now our class is going to need to know what to callback, which we do by providing a listener in the primary
constructor,
and we've done that a few times now.
And we also need a context for the gesture detector to work, and a reference to the recycler view that we're
detecting the taps on.
So we're going to add those parameters to the constructor as well. Lets go up and do that.
So we're going to change that now to print parentheses after the RecyclerItemClickListener, context
colon Context comma recyclerView colon, RecyclerView, and obviously capitalisation's important here,
comma private
val listener colon OnRecyclerClickListener.
And on the next line just to make a big of space here, I'm going to put colon,
then we're going to return a RecyclerView
dot SimpleOnItemTouchListener parentheses.
OK.
So we've seen the listener used a few times to store the object that we'll be calling back,
but what's this gesture detector all about.
So far we've responded to simple taps on widgets, such as buttons or the list view.
Now Android provides a load of ways that a user can interact with apps, including things like long
tapping, swiping and drawing patterns.
Now these are all handled by a gesture detector.
So I'm going to use the gesture detector compat class so that our app's compatible with earlier Android
versions. Now you can find the reference documentation on the gesture detector class by googling the class name. Now Google
also provide a training document which will come up in the search results.
If we go over and just have a quick look at that. Go to Google and we'll do a search for a
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
apps that use more complex gestures, then you'll find what you need to get started in these links. And I'm pushing
the documentation a lot, because frankly you can't be a successful developer without taking full advantage
of all the resources available on the internet.
Things are changing so fast, and there's just so much that Android can do that you just can't learn all
of it.
The trick is to learn what you need when you need it,
building on what you know about how the Android classes work, and how Android itself handles things.
Now we started writing the Java version of this course, which was based on Android Nougat, at around
the same time that Samsung started deploying Marshmallow on their devices.
Most devices out there were still on Lollipop or earlier.
So that means that we were using a version of Android that was two versions further on than most
devices.
So working in an environment that's changing so rapidly, frankly we'd be completely lost without access
to all the information that Google and others make available.
Alright so back to Android Studio.
So this RecyclerItemClickListener class extends the SimpleOnItemTouchListener.
I think I said earlier that it actually returns it but it's basically extending it, the RecyclerView.Simple
OnItemTouchListener, and we can override the on interrupt touch event function to intercept or touch events
that happen on the recycler view. So the function will be called whenever any sort of touch happens, whether
it's a tap, a double tap, a swipe or whatever.
So I'm going to get the code generator to override the on intercept touch event function, after our interface
declaration and then log the method call. And we're extending a class here by the way, not implementing an interface.
So I'm going to come down here after the interface declaration and do a control o.
So we want to override the onInterceptTouchEvent, which is this one here.
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
Intercept
TouchEvent colon starts dollar e. So let's leave it at that for now,
and connect this listener to the recycler view in main activity's onCreate method.
So I'm going to go ahead and open that up, there's our onCcreate. So first we're going to make MainActivity
implement the onRecyclerClickListener interface so that we can pass the activity rather than using anonymous
classes.
Now we did that before when we used the MainActivity as the listener for the buttons in the YouTube app.
So this line is going to get a little bit long now,
so I'm going to split it up.
So we've class main activity and we've got our appcompat activity.
We've got our on download complete.
So let's go to a new line
there, and put on GetFlickrJsonData dot
OnDataAvailable.
We need to add the next one now,
so put a comma, then go onto the next line, and it's going to be RecyclerItemClickListener dot OnRecycler
ClickListener.
Now we need to implement the two functions and obviously main activity wants us to do that now,
and that's what it's complaining about.
So let's get the generator to create the stubs for those two functions after the onCreate method, so we'll just
draw
down here,
control i, and we're going to select both of those and click on OK. Let's also add some logging to both,
and we'll also add a Toast message as well so we can see what's going on.
So firstly onItemClick Log.d
parentheses TAG comma double quotes dot onItemClick colon starts.
Then we want Toast dot makeText parentheses this comma Normal tap at position dollar position, and then we want
to put a comma after the double quote, Toast dot Length Short parentheses dot show. And for the long
click we're going to put Log.d parentheses TAG comma dot onItemLongClick
starts, and then we'll do a Toast dot
makeText parentheses, and it's going to be this again, double quotes Long tap at position dollar position,
then we'll do a comma Toast dot length short closing parentheses dot show.
OK.
And obviously now Android Studio's happy we've implemented those two functions.
So all that's left to do now to see our click events, is to create a new instance of our RecyclerItemClickListener
class and add it as a touch listener to the recycler view.
So let's do that and we'll do that up here.
Actually what we'll do, we'll just do it immediately after the linear layout and before we actually set the adapter.
So I'll put it on here, so it's recycler underscore view dot addOnItemTouchListener parentheses RecyclerItem
ClickListener parentheses,
this comma recycler underscore view comma this, and the two closing right parentheses.
And in case you're wondering with the two this's here, we're passing it as both the context, because
it's an activity, and the listener, because we've implemented the required interface. Now before running
the program, I'm going to comment out the logging of get item count in the FlickrRecyclerView
Adapter,
just to keep the log cat a little bit clearer.
We know that's working now way anyway so there's no need to continue logging it.
So let's comment that out,
like so.
And also we don't need to log the photo details either, your onBindViewHolder,
so let's actually
comment that out as well, that's this line
here. Alright so let's open up log cat, and I'll clear it, and let's run our app.
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
in the emulator.
When we do that you should actually see the onInterceptTouchEvent method being called twice, and you can
see that onInterceptTouchEvent was called twice there.
Now whenever you interact with an android screen,
there's actually quite a few events generated. Now here the function's being called when it detects
the touch, but also when the quote unquote finger is lifted off the screen, or mouse in my case.
So in other words we're getting two touch events for each tap.
Now let's try clicking and holding the mouse button down for a long tap.
So I'm going to do that on another one, and I'll just
do that again. So hold it down and you can notice that there was one, and then when I released the button it
went again, so I'm going to do it again, do a long tap
this time - there's the one event. I'm holding the mouse button down, and when I release the mouse button,
we see the second event. It's also interesting to see what happens when I scroll and fling the list.
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
more clearer.
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
by a series of action moves, and finally there's an action up when I release the mouse,
and that's the equivalent of lifting my finger off the screen on a real phone.
So if I do a bit of a fling here,
well that should result in the same sequence of events, just much faster,
like so.
So when I scroll we get an action underscore down action, followed by a series of action underscore
move events as I scroll.
And you can see that happening as I'm slowly scrolling, then I release the mouse button and we get the action
up again.
So there's loads of touch events being generated as we interact with the screen.
Now obviously we can't go trying to display a full screen picture on all of them.
In fact it's quite easy to break things.
So let's make a change to the function in the listener to see how. Now in the onInterceptTouchEvent in the Recycler
ItemClickListener class,
I'm going to return true,
instead of returning the result of the call to the Super Method. So in other words I want to comment that
out, and on the next line
I'm just going to put return true.
So if I stop that and run it again, and I'll open up the log cat as well,
and now when I click, we still get two method calls logged - action down and action up. Now if I hold the mouse
button down, we still get a single call, then the other, when I release it. Now I'm not sure if you'll be
able to see this too well on the video.
But if I try to scroll, I'm trying to scroll as I did earlier in this video. Nothing's actually happening.
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
the download event, just a single one as you can see, but the recycler view is no longer scrolling through
the list.
So in other words we're not getting any more action moves either, as we got previously, just a single
one.
So what I've done here by using this return TRUE, is intercepted the touch event, then told the system
that we've handled every single event.
So in other words that tells Android that nothing else needs to handle these events, which is what happens when
we return true.
So if we handle a particular touch event, then we can return true so that nothing else tries to
handle it.
But if we don't handle it, then we have to return false so that whatever else is listening can do its
stuff.
In fact if we don't return false, we should return the result of calling the super method, because that
gives anything else that's listening for events a chance to respond.
So as you can see this is far more complex than responding to simple clicks, like we did with buttons
or the list view widget, but it's starting to make sense.
This approach that the Android framework's taking makes the recycler view far more flexible than the simpler
list view.
So we can now intercept touch events, and we can let the system handle the ones we don't want to deal
with.
So that just leaves us with one more question. How do we decide which ones to deal with?
Well that's where the gesture detector comes in.
So I'm going to stop the video here. In the next video,
we'll see how to use a gesture detector.
See you in the next video.