Jul 5 | 3:50 PM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Jul 5 | 4:00 PM |
Shay | has entered the room |
Shay |
Hello
|
Shay |
Good afternoon
|
Mark M. |
hello, Shay!
|
Mark M. |
how can I help you?
|
Shay |
Hi Mark, hope you're doing well
|
Mark M. |
trying to figure out why one of my servers is no longer accepting SSH connections :-(
|
Mark M. |
otherwise, I'm fine -- and you?
|
Mark M. |
quit
|
Mark M. |
er, sorry, wrong window...
|
Shay |
I am trying to achieve a RecyclerView that can have headers, and different layouts (with same Views), only mirrored for odd and even
|
Jul 5 | 4:05 PM |
Mark M. |
what do you mean by "mirrored"?
|
Shay |
I'm fine, thanks
|
Shay |
I have two layout containing views with the same IDs
|
Shay |
Only on one of them there's an icon on the right, and then on the other the icon is on the left
|
Shay |
basically for odd and even rows of the list
|
Shay |
In addition, I need headers, which have a different layout alltogehter
|
Shay |
I tried using a library called groupie, however it does not allow for layout changes based on position
|
Shay |
I know I need to implement an adapter and ViewHolder. The question is, is there a better way to go about it
|
Mark M. |
is there a better way to go about... what, exactly?
|
Shay |
I need a RecyclerView that supports headers, and that I can change layouts based on position
|
Mark M. |
and that will largely be the responsibility of your adapter
|
Mark M. |
it will need to know the difference between headers, detail-odd, and detail-even positions
|
Shay |
I got stuck a bit because of Kotlin
|
Jul 5 | 4:10 PM |
Shay |
in java I could make the ViewHolder take an object, then check what type it is
|
Shay |
I cannot seem to do that in Kotlin
|
Mark M. |
um, the same way that you do it in Java, though that overall approach isn't going to work, due to recycling
|
Mark M. |
well, I shouldn't say "isn't going to work", but it will make things kinda messy
|
Mark M. |
first: have you implemented getViewTypeCount() yet on your Adapter? if so, what value are you returning?
|
Shay |
no, I cannot see this function
|
Shay |
is it getItemViewType() in kotlin?
|
Mark M. |
oh, yeah, whoops, I had the wrong method name there, sorry
|
Mark M. |
are you implementing getItemViewType()?
|
Jul 5 | 4:15 PM |
Shay |
Not at the moment. I'll be honest and say I don't know this method
|
Mark M. |
OK
|
Shay |
I remember there used to be a function in Java getAdapaterPostion() or something like that
|
Shay |
but cannot find it now
|
Mark M. |
that's from ListAdapter with ListView (basically the same mistake that I was making earlier)
|
Mark M. |
I recommend you read my chapter on "Advanced RecyclerView" in *The Busy Coder's Guide to Android Development*
|
Mark M. |
in particular, I have a section on having a RecyclerView with headers + detail rows: https://wares.commonsware.com/app/internal/book...
|
Mark M. |
it's in Java, but the concepts still hold
|
Shay |
oh cool
|
Mark M. |
to make multiple row types work with a RecyclerView, your adapter first needs to implement getItemViewType(), returning a unique integer for each distinct type of row, so RecyclerView recycles things properly
|
Shay |
I actually tried to find something like that in the book, however I could only found the regular recycler view
|
Mark M. |
*Elements of Android Jetpack* does not get into the advanced stuff
|
Shay |
ah I see,
|
Shay |
I guess it will take time and some edition to get there
|
Mark M. |
well, not really, insofar as I don't intend *Elements of Android Jetpack* to cover the same scope as *The Busy Coder's Guide to Android Development* did
|
Mark M. |
it's possible that I'll do an *Elements of Android RecyclerView* at some point that covers all the RecyclerView stuff in second-generation style
|
Jul 5 | 4:20 PM |
Mark M. |
but, in simple terms, I ain't rewritin' everything from a 4400-page book
|
Mark M. |
but, that's why I added the full-text search to the sites, that span all books in the Warescription, to help you find the material that you need
|
Shay |
yes, rewriting 4400+ pages sounds insane
|
Mark M. |
anyway, getting back to your situation...
|
Mark M. |
in your case, you have three types of rows: header, detail-odd, and detail-even, so getItemViewType() will need to return three distinct integers, based on which row type you want for this position
|
Mark M. |
how you determine which row type you want for this position is part of your business logic, and it might get messy
|
Mark M. |
but, once that's done, onCreateViewHolder() is passed the view type integer from getItemViewType(), so you can decide what to inflate and what sort of ViewHolder to return
|
Mark M. |
and, onBindViewHolder() is passed the ViewHolder
|
Mark M. |
in your case, I can see arguments for using either two or three distinct ViewHolder classes
|
Mark M. |
headers definitely get their own
|
Mark M. |
whether you use a single ViewHolder or two for the detail rows depends a bit on their contents -- if they truly are identical with just different layout positions, a single ViewHolder could work
|
Shay |
yes, this is exactly the case
|
Shay |
completely identical with different layouts positions
|
Mark M. |
OK, so you can probably get by with a single ViewHolder class, where the Adapter inflates the proper layout based on the view type value
|
Shay |
So I should implement a ViewHolder I take it (well, two)
|
Mark M. |
yes
|
Jul 5 | 4:25 PM |
Mark M. |
one for the headers, and one for what I call the detail rows (you're welcome to use whatever term you want for those)
|
Jul 5 | 4:25 PM |
Shay |
so I basically need to implement a "parent" ViewHolder, then two that extends it I take it
|
Shay |
unless the Adapter can take two different ViewHolders
|
Mark M. |
you could have the adapter be an adapter of RecyclerView.ViewHolder, if you wanted
|
Mark M. |
or have a common base class that the two ViewHolder implementations extend from
|
Mark M. |
either way works
|
Shay |
but isn't RecyclerView.ViewHolder an abstract class?
|
Mark M. |
yes
|
Mark M. |
however, RecyclerView.Adapter doesn't care
|
Mark M. |
the reason you give RecyclerView.Adapter a data type for your ViewHolder is just to avoid casting in simpler scenarios
|
Shay |
so I could get away with not creating a ViewHolder class, and only use getItemViewType and inflate in accordance
|
Mark M. |
no
|
Mark M. |
you asked: "so I basically need to implement a "parent" ViewHolder, then two that extends it I take it"
|
Jul 5 | 4:30 PM |
Shay |
Well, I'll explain myself better
|
Shay |
You said I could also use RecyclerView.ViewHolder
|
Mark M. |
and that's not necessarily required -- you could have two independent ViewHolder implementations, without a custom common base class
|
Shay |
say I use RecyclerView.ViewHolder, can I just inflate the correct layout and be done?
|
Mark M. |
no
|
Mark M. |
let's back up a step
|
Mark M. |
when I wrote "RecyclerView.Adapter doesn't care", I meant from a declaration standpoint
|
Mark M. |
when you create your subclass, you need to tell it the type of ViewHolder that it manages
|
Mark M. |
in a simple, all-rows-are-the-same scenario, that would be your custom ViewHolder subclass
|
Mark M. |
you are not in that scenario
|
Mark M. |
and so you have two choices for what to use in the <> for your Adapter declaration:
|
Mark M. |
1. define a base class extending ViewHolder, use that in the <>, and have two subclasses of it, one for headers and one for detail rows
|
Mark M. |
2. use ViewHolder itself in the <>, and have two subclasses of ViewHolder, one for headers and one for detail rows
|
Mark M. |
you still need a ViewHolder class for your headers, and you still need a ViewHolder class for your detail rows
|
Shay |
I see
|
Mark M. |
the only variable is whether they directly extend ViewHolder or if they directly extend some other custom class of yours that extends ViewHolder
|
Mark M. |
go with whichever you are more comfortable with
|
Shay |
that does make much more sense. I didn't understand correctly before
|
Mark M. |
yeah, I was a bit glib in my comment, sorry
|
Shay |
It's fine
|
Jul 5 | 4:35 PM |
Shay |
It's close to midnight here, so I'm a bit slow
|
Shay |
Also, it has been 2 years since I coded android, so I am very rusty
|
Shay |
but it seems to me that extending RecyclerView.ViewHolder directly is less code and boilerplace
|
Shay |
*boilerplate
|
Mark M. |
agreed
|
Shay |
and in any case the "header" and "detail" view have nothing in common
|
Mark M. |
which would make a base class just a placeholder, which means it may not be worth it
|
Shay |
so your second approach seems better
|
Shay |
Exactly
|
Mark M. |
yes
|
Shay |
One thing though. When I use getItemViewType(), I should return the ID of the layout right? e.g. R.id as opposed to R.layout
|
Mark M. |
it needs to be a unique integer
|
Mark M. |
what the integer is does not really matter
|
Mark M. |
and, unlike the old ListAdapter stuff, you don't have to start counting from 0
|
Mark M. |
so, if you have distinct layout resources for each, and want to use R.layout values, that's fine
|
Jul 5 | 4:40 PM |
Shay |
So when I use getItemViewType(), the position parameter gives me the position in the current RecyclerView, as opposed to position in Adapter?
|
Mark M. |
it should be an adapter position
|
Shay |
Thats good. Only thing I'll need to do is remember the positions of the headers, because after each header odd and even starts anew
|
Mark M. |
yeah, like I said, getItemViewType() might get messy
|
Jul 5 | 4:45 PM |
Mark M. |
OTOH, since the view type integer gets passed into onCreateViewHolder(), and the ViewHolder gets passed into onBindViewHolder(), you may be able to "contain the mess", as it were
|
Shay |
Yes, it looks like it can get messy, true. But I think a simple boolean that knows if the count starts again can solve this
|
Shay |
I'll see how it goes when I start coding
|
Shay |
But in any case, thank you, you've helped me a lot and gave me the right direction, so I am grateful :)
|
Mark M. |
you're welcome!
|
Shay |
Well, I'll go to sleep a bit, I am a bit ahead of you (GMT+3 here). Going to write all your comments then code tomorrow when I'm fresh. Thanks again :)
|
Mark M. |
um, sleep well! :-)
|
Jul 5 | 4:50 PM |
Shay |
Have great weekend, and late happy 4th of July :)
|
Shay | has left the room |
Jul 5 | 4:55 PM |
Mark M. | turned off guest access |