Использовать пользовательский вид в адаптере RecyclerView?
У меня есть базовый пользовательский вид, который выглядит следующим образом:
public class CustomView extends RelativeLayout {
private User user;
private ImageView profilePicture;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
inflate(getContext(), R.layout.custom_layout, this);
profilePicture = (ImageView) findViewById(R.id.profilePicture);
// ACCESS USER MODEL HERE
// e.g. user.getUsername()
}
}
Как вы можете видеть, я хотел бы получить доступ к данным пользователя в представлении (т.е. user.getUsername()
).
Мне также нужно иметь возможность использовать пользовательский вид в RecyclerView
Адаптер.
Вот как выглядит мой адаптер:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private Context context;
private List<User> userData;
public MyAdapter(Context context, List<User> userData) {
this.context = context;
this.userData = userData;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View v) {
super(v);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
// HOW TO INFLATE THE CUSTOM VIEW?
// ViewHolder viewHolder = new ViewHolder(customView);
return viewHolder;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
// ANYTHING HERE?
}
@Override
public int getItemCount() {
return userData.size();
}
}
Как я могу раздуть пользовательский вид в адаптере?
Кроме того, я должен положить что-нибудь в onBindViewHolder()
?
Примечание: я должен использовать пользовательский вид, так как я использую этот вид под разными адаптерами (то есть: не только этот RecyclerView
Адаптер).
3 ответа
Предполагая CustomView
класс, который выглядит примерно так:
public class CustomView extends RelativeLayout {
private User user;
private ImageView profilePicture;
// override all constructors to ensure custom logic runs in all cases
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CustomView(
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);
}
public void setUser(User newUser) {
user = newUser;
// ACCESS USER MODEL HERE
// e.g. user.getUsername()
}
}
Ваш RecyclerView.Adapter
а также RecyclerView.ViewHolder
может выглядеть примерно так:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
// no Context reference needed—can get it from a ViewGroup parameter
private List<User> userData;
public MyAdapter(List<User> userData) {
// make own copy of the list so it can't be edited externally
this.userData = new ArrayList<User>(userData);
}
@Override
public int getItemCount() {
return userData.size();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// no need for a LayoutInflater instance—
// the custom view inflates itself
CustomView itemView = new CustomView(parent.getContext());
// manually set the CustomView's size
itemView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.getCustomView().setUser(userData.get(position));
}
public class ViewHolder extends RecyclerView.ViewHolder {
private CustomView customView;
public ViewHolder(View v) {
super(v);
customView = (CustomView) v;
}
public CustomView getCustomView() {
return customView;
}
}
}
CustomView
управляет своей собственной установкой, которая происходит в его собственном конструкторе и в этом случае использует инфляцию файла XML. (В качестве альтернативы он может настроить свои дочерние представления программно.)- Из-за этого
RecyclerView.Adapter
не нужно выполнять какую-либо инфляцию - он просто создает новыйCustomView
экземпляр, и позволяетCustomView
беспокоиться о собственной настройке. CustomView
не могу получитьUser
экземпляр до егоsetUser
метод вызывается, поэтому доступ пользователя не может возникнуть в конструкторе. В любом случае, более одногоCustomView
время жизниRecyclerView
может попросить показать информацию для разных пользователей в разное время.CustomView
должен быть в состоянии сделать это. Следовательно,setUser
метод введен.- Поскольку
CustomView
создается кодом, а не XML, атрибуты для размера не могут быть определены в XML. Следовательно, определение размера производится программно после создания экземпляра. onBindViewHolder
просто звонитsetUser
наCustomView
связатьCustomView
с правильнымUser
пример.ViewHolder
класс теперь просто связь междуRecyclerView
пункт иCustomView
,
Использование предварительно созданных пользовательских представлений из другого класса в RecyclerView
s (т.е. не раздувать XML внутри RecyclerView.Adapter
никогда не обсуждается. Я думаю, что это отличная идея, даже если пользовательский вид используется исключительно в RecyclerView
потому что это способствует разделению интересов и соблюдению принципа единой ответственности.
CustomView extends RelativeLayout {
У вас уже есть вид (ну, ViewGroup
)
КАК НАДВЕТИТЬ ТАМОЖЕННЫЙ ВИД?
Вам не нужно... Смысл объекта Custom View в том, что он не нуждается в XML, поэтому нет инфляции.
Вы можете создать new CustomView()
, но вам нужно установить все параметры макета, которые в XML выглядят чище, я думаю.
Наиболее RecyclerView
учебники показывают раздувание через XML, хотя.
View customView = inflater.inflate(...); ViewHolder viewHolder = new ViewHolder(customView);
Это должно работать, потому что в цепочке классов у вас есть CustomView > RelativeLayout > ViewGroup > View
LayoutInflater inflater = LayoutInflater.from(context);
Как я уже говорил, вам это не нужно, если нет файла XML, который вы хотите наполнить.
Вам также не нужно context
переменная.
parent.getContext()
это хорошее решение.
// ANYTHING HERE?
Ну, да, вы должны "связать" ViewHolder
с данными о том, что ViewHolder
должен держать.
Опять же, большинство, если не все учебники охватывают это.
list_content.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns: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">
<TextView
android: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"
/>
<ImageView
android: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
public class yourAdapter extends RecyclerView.Adapter<yourAdapter .SimpleViewHolder> {
private Context mContext;
ArrayList<String> mylist;
public yourAdapter (Context context, ArrayList<String> checklist) {
mContext = context;
mylist = checklist;
}
@Override
public yourAdapter .SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_content, parent, false);
return new yourAdapter .SimpleViewHolder(view);
}
@Override
public void onBindViewHolder(final yourAdapter .SimpleViewHolder holder, final int position) {
holder.name.setText(adap.getName());
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public int getItemCount() {
return mylist.size();
}
@Override
public int getItemViewType(int i) {
return 0;
}
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
TextView name;
Imageview content;
public SimpleViewHolder(View itemView) {
super(itemView);
name= (TextView) itemView.findViewById(R.id.name);
close= (Imageview) itemView.findViewById(R.id.close);
}
}
}
Затем вызовите класс адаптера в деятельности, где вы хотите
https://developer.sonymobile.com/2010/05/20/android-tutorial-making-your-own-3d-list-part-1/