Use Custom View In A Recyclerview Adapter?
Solution 1:
Assuming a CustomView
class that looks something like this:
publicclassCustomViewextendsRelativeLayout {
private User user;
private ImageView profilePicture;
// override all constructors to ensure custom logic runs in all casespublicCustomView(Context context) {
this(context, null);
}
publicCustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
publicCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
publicCustomView(
Context context,
AttributeSet attrs,
int defStyleAttr,
int defStyleRes
) {
super(context, attrs, defStyleAttr, defStyleRes);
// put all custom logic in this constructor, which always runs
inflate(getContext(), R.layout.custom_layout, this);
profilePicture = (ImageView) findViewById(R.id.profilePicture);
}
publicvoidsetUser(User newUser) {
user = newUser;
// ACCESS USER MODEL HERE// e.g. user.getUsername()
}
}
Your RecyclerView.Adapter
and RecyclerView.ViewHolder
could look something like this:
publicclassMyAdapterextendsRecyclerView.Adapter<MyAdapter.ViewHolder> {
// no Context reference needed—can get it from a ViewGroup parameterprivate List<User> userData;
publicMyAdapter(List<User> userData) {
// make own copy of the list so it can't be edited externallythis.userData = newArrayList<User>(userData);
}
@OverridepublicintgetItemCount() {
return userData.size();
}
@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// no need for a LayoutInflater instance—// the custom view inflates itselfCustomViewitemView=newCustomView(parent.getContext());
// manually set the CustomView's size
itemView.setLayoutParams(newViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
returnnewViewHolder(itemView);
}
@OverridepublicvoidonBindViewHolder(final ViewHolder holder, int position) {
holder.getCustomView().setUser(userData.get(position));
}
publicclassViewHolderextendsRecyclerView.ViewHolder {
private CustomView customView;
publicViewHolder(View v) {
super(v);
customView = (CustomView) v;
}
public CustomView getCustomView() {
return customView;
}
}
}
- The
CustomView
manages its own setup, which occurs in its own constructor and in this case uses inflation of an XML file. (Alternatively, it could set up its child views programmatically.) - Because of this, the
RecyclerView.Adapter
doesn't need to perform any inflation—it just creates a newCustomView
instance, and lets theCustomView
worry about its own setup. - The
CustomView
can't get aUser
instance until itssetUser
method is called, so user access cannot occur in the constructor. In any case, over oneCustomView
lifetime, aRecyclerView
could ask it to show information for many different users at different times. TheCustomView
needs to be able to do this. Therefore, asetUser
method is introduced. - Because the
CustomView
is instantiated by code instead of by XML, attributes for size can't be defined in XML. Therefore, sizing is done programmatically after instantation. onBindViewHolder
simply callssetUser
on theCustomView
to link theCustomView
with the correctUser
instance.- The
ViewHolder
class is now just a link between aRecyclerView
item and aCustomView
.
Using pre-built custom views from another class within RecyclerView
s (i.e. not inflating XML within the RecyclerView.Adapter
) never seems to be discussed. I think it's an excellent idea even when the custom view is exclusively used within a RecyclerView
, because it promotes separation of concerns and adherence to the Single Responsibility Principle.
Solution 2:
CustomView extendsRelativeLayout {
You have a View already (well, a ViewGroup
)
HOW TO INFLATE THE CUSTOM VIEW?
You don't need to... The point of a Custom View object is to not need XML, therefore no inflation.
You can create new CustomView()
, but you need to set all the layout parameters, which looks cleaner in XML, I think.
Most RecyclerView
tutorials show inflating via XML though.
ViewcustomView= inflater.inflate(...);
ViewHolderviewHolder=newViewHolder(customView);
That should work because in the class chain, you have CustomView > RelativeLayout > ViewGroup > View
LayoutInflater inflater = LayoutInflater.from(context);
Like I said before, you don't need this if there is no XML file you want to inflate.
You also don't need the context
variable.
parent.getContext()
is a fine solution.
// ANYTHING HERE?
Well, yeah, you should "bind" the ViewHolder
with the data that the ViewHolder
should hold.
Again, most, if not all, tutorials cover this.
Solution 3:
list_content.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:text="TextView"android:layout_width="@dimen/_160sdp"android:textSize="@dimen/_14sdp"android:layout_gravity="center|bottom"android:layout_height="match_parent"android:layout_weight="1"android:paddingTop="@dimen/_10sdp"android:id="@+id/name"
/><ImageViewandroid:layout_width="@dimen/_20sdp"android:layout_gravity="center|right"android:layout_height="@dimen/_20sdp"app:srcCompat="@drawable/close"android:id="@+id/close"android:layout_weight="1" /></LinearLayout>
Adapter.java
publicclassyourAdapterextendsRecyclerView.Adapter<yourAdapter .SimpleViewHolder> {
private Context mContext;
ArrayList<String> mylist;
publicyourAdapter(Context context, ArrayList<String> checklist) {
mContext = context;
mylist = checklist;
}
@Overridepublic yourAdapter .SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Viewview= LayoutInflater.from(parent.getContext()).inflate(R.layout.list_content, parent, false);
returnnewyourAdapter .SimpleViewHolder(view);
}
@OverridepublicvoidonBindViewHolder(final yourAdapter .SimpleViewHolder holder, finalint position) {
holder.name.setText(adap.getName());
}
@OverridepubliclonggetItemId(int i) {
return0;
}
@OverridepublicintgetItemCount() {
return mylist.size();
}
@OverridepublicintgetItemViewType(int i) {
return0;
}
publicstaticclassSimpleViewHolderextendsRecyclerView.ViewHolder {
TextView name;
Imageview content;
publicSimpleViewHolder(View itemView) {
super(itemView);
name= (TextView) itemView.findViewById(R.id.name);
close= (Imageview) itemView.findViewById(R.id.close);
}
}
}
Then call the adapter class in activity where you want
https://developer.sonymobile.com/2010/05/20/android-tutorial-making-your-own-3d-list-part-1/
Post a Comment for "Use Custom View In A Recyclerview Adapter?"