Использовать пользовательский вид в адаптере 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,

Использование предварительно созданных пользовательских представлений из другого класса в RecyclerViews (т.е. не раздувать 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/

Другие вопросы по тегам