【译】Android中的Recycler View

328 阅读5分钟

原文地址:magdamiu.com/2020/12/29/…

作者:MAGDA MIU

Recycler View是一个View Group,它帮助我们显示可滚动的元素列表。它是Android应用程序中最常用的UI组件之一,它包括数据源、适配器和Recycler View。除了显示内容,Recycler View还通过回收视图有效地重用从屏幕上滚动下来的视图。

img

组件概述

  • 数据源–可以从本地数据库获得的对象列表,或者作为超文本传输协议请求的结果,甚至可以是具有一些预定义值的列表。

  • Recycler View是列表项的滚动列表,要访问它,我们必须在gradle文件中添加一些依赖项

  • 一项数据的布局–XML文件

  • 布局管理器处理视图中UI组件的组织(有3种预定义的方式来显示项目)

  • 视图持有者具有用于显示一个项目的视图信息

  • 适配器将数据连接到Recycler View

  • 将适配器设置为Recycler View,我们就完成了

img

布局管理器

img

适配器

  • 我们正在讨论应用适配器设计模式作为我们想要显示的源数据和视图之间的中介

  • 适配器是一种结构设计模式,允许具有不兼容接口的对象进行协作

  • 负责从列表中创建、更新、添加和删除项目

  • 它假设实现抽象类Recycler View。适配器

视图持有人

  • 适配器用于为数据源中的每个元素准备一个项视图

  • 项目的布局在一个XML资源文件中指定,它就像视图和作为数据源提供的对象列表中的元素之间的1:1关系

  • 可以有可点击的元素,并由布局管理器放置

  • 我们必须实现抽象类Recycler View。视图持有

实施步骤

  1. 通过创建新的对象类(数据源)获取数据

  2. 将Recycler View依赖项添加到app/build.gradle文件并将Recycler View添加到布局

  3. 为项目创建XML布局

  4. 在活动中定义Layout Manager

  5. 扩展Recycler View。分离类中的视图持有者

  6. 扩展Recycler View。分离类中的适配器

  7. 在on Create的活动中,使用适配器和布局管理器创建Recycler View

为了涵盖实施步骤,我们将显示电子邮件列表。数据源是硬编码的,现在我们专注于学习如何使用Recycler View。

步骤1:通过创建一个新的对象类(数据源)来获取数据

public class Email { private int id; private String fromName; private String subject; private String shortBody;


    public Email(int id, String fromName, String subject, String shortBody) {
        this.id = id;
        this.fromName = fromName;
        this.subject = subject;
        this.shortBody = shortBody;
    }


    public int getId() {
        return id;
    }


    public void setId(int id) {
        this.id = id;
    }


    public String getFromName() {
        return fromName;
    }


    public void setFromName(String fromName) {
        this.fromName = fromName;
    }


    public String getSubject() {
        return subject;
    }


    public void setSubject(String subject) {
        this.subject = subject;
    }


    public String getShortBody() {
        return shortBody;
    }


    public void setShortBody(String shortBody) {
        this.shortBody = shortBody;
    }


    @Override
    public String toString() {
        return "Email{" +
                "id='" + id + '\'' +
                ", fromName='" + fromName + '\'' +
                ", title='" + subject + '\'' +
                ", shortBody='" + shortBody + '\'' +
                '}';
    }
}
private void inbox() {
    emails = new ArrayList<>();
    Email email = null;
    for (int i = 0; i < 25; i++) {
        email = new Email(0, "Magda " + i, "Hello Android " + i, "This is an intro about Android");
        emails.add(email);
    }
}

步骤2:将Recycler View依赖项添加到app/build.gradle文件中,并将Recycler View添加到布局中

implementation 'androidx.recyclerview:recyclerview:1.2.0-beta01'
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewEmails"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

步骤3:为项目创建XML布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:id="@+id/linearLayoutEmail"
    android:padding="@dimen/small_padding">

    <TextView
        android:id="@+id/textViewFrom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        tools:text="Magda" />

    <TextView
        android:id="@+id/textViewSubject"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/extra_small_padding"
        android:textColor="@color/purple_700"
        tools:text="Android Fundamentals" />

    <TextView
        android:id="@+id/textViewBody"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/extra_small_padding"
        tools:text="this is a welcome email …." />

</LinearLayout>

步骤4:在活动中定义Layout Manager

private void setEmailsLayoutManager() {
      recyclerViewEmails.setLayoutManager(new LinearLayoutManager(this));
}

步骤5:扩展Recycler View。分离类中的视图持有者

public class EmailViewHolder extends RecyclerView.ViewHolder{

    private final TextView textViewFrom, textViewSubject, textViewBody;
    private final LinearLayout linearLayoutEmail;

    public EmailViewHolder(@NonNull View itemView) {
        super(itemView);

        textViewFrom = itemView.findViewById(R.id.textViewFrom);
        textViewSubject = itemView.findViewById(R.id.textViewSubject);
        textViewBody = itemView.findViewById(R.id.textViewBody);
        linearLayoutEmail = itemView.findViewById(R.id.linearLayoutEmail);
    }

    public TextView getTextViewFrom() {
        return textViewFrom;
    }

    public TextView getTextViewSubject() {
        return textViewSubject;
    }

    public TextView getTextViewBody() {
        return textViewBody;
    }

    public LinearLayout getLinearLayoutEmail() {
        return linearLayoutEmail;
    }
}

步骤6:扩展Recycler View**。分离类中的适配器**

public class EmailAdapter extends RecyclerView.Adapter<EmailViewHolder> {
    private List<Email> emails;
    private Context context;

    public EmailAdapter(Context context, List<Email> emails) {
        this.emails = emails;
        this.context = context;
    }

    // creates the items and add them to the RecyclerView, just the layout
    @NonNull
    @Override
    public EmailViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(context).inflate(R.layout.email_item, parent, false);
        return new EmailViewHolder(itemView);
    }

    // binds (displays) the content from the list of emails for each item
    @Override
    public void onBindViewHolder(@NonNull EmailViewHolder holder, int position) {
        Email currentEmail = emails.get(position);
        holder.getTextViewFrom().setText(currentEmail.getFromName());
        holder.getTextViewSubject().setText(currentEmail.getSubject());
        holder.getTextViewBody().setText(currentEmail.getShortBody());
    }

    // we tell to the Recycler View how many items to display
    @Override
    public int getItemCount() {
        return emails.size();
    }
}

步骤7:在on Create的活动中,创建一个带有适配器和布局管理器的Recycler View

private void setEmailsAdapter() {
    recyclerViewEmails.setAdapter(new EmailAdapter(this, emails));
}

private void displayEmailsList() {
    // data source – checked
    inbox();

    // layout manager – checked
    setEmailsLayoutManager();

    // adapter – checked
    setEmailsAdapter();
}

通知适配器

为了不影响Recycler View的用户界面元素渲染速度,请确保您没有为小更新调用通知数据集变更()、设置适配器(适配器)或交换适配器(适配器,布尔)。[官方建议]解决方案是在数据源发生变化时使用[Sorted List或]

public class EmailDiffCallback extends DiffUtil.Callback {

    private List<Email> oldList;
    private List<Email> newList;

    public EmailDiffCallback(List<Email> oldList, List<Email> newList) {
        this.oldList = oldList;
        this.newList = newList;
    }

    @Override
    public int getOldListSize() {
        return oldList.size();
    }

    @Override
    public int getNewListSize() {
        return newList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        // add a unique ID property on Email and expose a getId() method
        return oldList.get(oldItemPosition).getId() == newList.get(newItemPosition).getId();
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        Email oldEmail = oldList.get(oldItemPosition);
        Email newEmail = newList.get(newItemPosition);

        if (oldEmail.getFromName() == newEmail.getFromName() && oldEmail.getSubject() == newEmail.getSubject() && oldEmail.getShortBody() == newEmail.getShortBody()) {
            return true;
        }
        return false;
    }
}
// NOT OK
void onNewEmailsArrivedNotRecommended(List<Email> newEmails) {
    emailAdapter.setEmails(newEmails);
    emailAdapter.notifyDataSetChanged();
}

// OK
void onNewDataArrivedFastRendering(List<Email> newEmails) {
    List<Email> oldEmails = emailAdapter.getEmails();
    DiffUtil.DiffResult result = DiffUtil.calculateDiff(new EmailDiffCallback(oldEmails, newEmails));
    emailAdapter.setEmails(newEmails);
    result.dispatchUpdatesTo(emailAdapter);
}

项目装饰

我们可以使用Divider Item Decation在项目之间设置分隔符

private void setItemDecorator() {
    RecyclerView.ItemDecoration itemDecoration = new
            DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
    recyclerViewEmails.addItemDecoration(itemDecoration);
}

img

img

滑动刷新

步骤1:在gradle文件中添加新的依赖项

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

步骤2:将Recycler View包装在Swipe ReFresh Layout中

<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipeContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewEmails"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

步骤3:更新适配器中的代码

// Clean all elements of the recycler
public void clear() {
    emails.clear();
    notifyDataSetChanged();
}

// Add a list of items
public void addAll(List<Email> list) {
    emails.addAll(list);
    notifyDataSetChanged();
}

步骤4:设置Swipe RecreLayout

private void setupSwipeToRefresh() {
    swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            // Make sure you call swipeRefreshLayout.setRefreshing(false)
            // once the network request has completed successfully.
            inbox();
        }
    });
    // Configure the refreshing colors
    swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
            android.R.color.holo_green_light,
            android.R.color.holo_orange_light,
            android.R.color.holo_red_light);
}

img

你可以在这里查看完整的源代码。

了解更多

如果有什么不清楚或有问题,请随时留下评论。如果你喜欢它,请分享!

感谢您的阅读!

关注我: Twitter|媒体|****Dev.to