在 RecyclerView 适配器中使用自定义视图? [英] Use custom View in a RecyclerView Adapter?

查看:39
本文介绍了在 RecyclerView 适配器中使用自定义视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基本的自定义视图,如下所示:

I have a basic custom View which looks like this:

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()).

As you can see, I'd like to access user data in the View (i.e.: user.getUsername()).

我还需要能够在 RecyclerView 适配器中使用自定义视图.

I also need to be able to use the custom View in a RecyclerView Adapter.

这是我的适配器目前的​​样子:

Here is what my Adapter currently looks like:

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();
    }

}

如何在 Adapter 中扩展自定义 View?
另外,我应该在 onBindViewHolder() 中放任何东西吗?

How can I inflate the custom View in the Adapter?
Also, should I put anything in onBindViewHolder()?

注意:我必须使用自定义视图,因为我在不同的适配器下使用此视图(即:不仅仅是这个 RecyclerView 适配器).

Note: I must use a custom View, as I use this View under different Adapters (i.e.: not just this RecyclerView Adapter).

推荐答案

假设一个 CustomView 类看起来像这样:

Assuming a CustomView class that looks something like this:

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.AdapterRecyclerView.ViewHolder 可能如下所示:

Your RecyclerView.Adapter and RecyclerView.ViewHolder could look something like this:

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 只需调用 CustomView 上的 setUserCustomView 与正确的 User<链接起来/code> 实例.
  • ViewHolder 类现在只是 RecyclerView 项和 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 new CustomView instance, and lets the CustomView worry about its own setup.
    • The CustomView can't get a User instance until its setUser method is called, so user access cannot occur in the constructor. In any case, over one CustomView lifetime, a RecyclerView could ask it to show information for many different users at different times. The CustomView needs to be able to do this. Therefore, a setUser 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 calls setUser on the CustomView to link the CustomView with the correct User instance.
    • The ViewHolder class is now just a link between a RecyclerView item and a CustomView.
    • RecyclerView 中使用来自另一个类的预构建自定义视图(即不在 RecyclerView.Adapter 中膨胀 XML)似乎从未被讨论过.我认为即使自定义视图仅在 RecyclerView 中使用,这也是一个好主意,因为它 促进关注点分离遵守单一职责原则.

      Using pre-built custom views from another class within RecyclerViews (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.

      这篇关于在 RecyclerView 适配器中使用自定义视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆