【问题标题】:Simple Android RecyclerView example简单的 Android RecyclerView 示例
【发布时间】:2017-03-27 20:02:50
【问题描述】:

我用 Android 的RecyclerView 做了几次项目列表,但这是一个相当复杂的过程。浏览众多在线教程之一(thisthisthis 很好),但我正在寻找一个可以复制和粘贴以快速启动和运行的简单示例。只需要以下功能:

  • 垂直布局
  • 每行有一个 TextView
  • 响应点击事件

因为这个愿望我已经好几次了,所以我最终决定做出下面的答案,以供我和你的参考。

【问题讨论】:

标签: android android-recyclerview


【解决方案1】:

以下是一个类似于下图的最小示例。

从一个空的活动开始。您将执行以下任务来添加 RecyclerView。您需要做的就是复制并粘贴每个部分的代码。稍后您可以对其进行自定义以满足您的需求。

  • 向 gradle 添加依赖项
  • 为 Activity 和 RecyclerView 行添加 xml 布局文件
  • 制作 RecyclerView 适配器
  • 在您的活动中初始化 RecyclerView

更新 Gradle 依赖项

确保您的应用程序gradle.build 文件中有以下依赖项:

implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'

您可以将版本号更新为the most current。如果您仍在使用 Android Studio 2.x,请使用 compile 而不是 implementation

创建活动布局

RecyclerView 添加到您的 xml 布局中。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rvAnimals"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

创建行布局

RecyclerView 中的每一行只有一个 TextView。创建一个新的布局资源文件。

recyclerview_row.xml

<?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="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp">

    <TextView
        android:id="@+id/tvAnimalName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"/>

</LinearLayout>

创建适配器

RecyclerView 需要一个适配器来用您的数据填充每一行中的视图。创建一个新的 java 文件。

MyRecyclerViewAdapter.java

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {

    private List<String> mData;
    private LayoutInflater mInflater;
    private ItemClickListener mClickListener;

    // data is passed into the constructor
    MyRecyclerViewAdapter(Context context, List<String> data) {
        this.mInflater = LayoutInflater.from(context);
        this.mData = data;
    }

    // inflates the row layout from xml when needed
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
        return new ViewHolder(view);
    }

    // binds the data to the TextView in each row
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String animal = mData.get(position);
        holder.myTextView.setText(animal);
    }

    // total number of rows
    @Override
    public int getItemCount() {
        return mData.size();
    }


    // stores and recycles views as they are scrolled off screen
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView myTextView;

        ViewHolder(View itemView) {
            super(itemView);
            myTextView = itemView.findViewById(R.id.tvAnimalName);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
        }
    }

    // convenience method for getting data at click position
    String getItem(int id) {
        return mData.get(id);
    }

    // allows clicks events to be caught
    void setClickListener(ItemClickListener itemClickListener) {
        this.mClickListener = itemClickListener;
    }

    // parent activity will implement this method to respond to click events
    public interface ItemClickListener {
        void onItemClick(View view, int position);
    }
}

注意事项

  • 虽然不是绝对必要的,但我包含了侦听行上的点击事件的功能。这在旧的ListViews 中可用,是一种常见的需求。如果不需要,可以删除此代码。

在Activity中初始化RecyclerView

将以下代码添加到您的主要活动中。

MainActivity.java

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {

    MyRecyclerViewAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // data to populate the RecyclerView with
        ArrayList<String> animalNames = new ArrayList<>();
        animalNames.add("Horse");
        animalNames.add("Cow");
        animalNames.add("Camel");
        animalNames.add("Sheep");
        animalNames.add("Goat");

        // set up the RecyclerView
        RecyclerView recyclerView = findViewById(R.id.rvAnimals);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new MyRecyclerViewAdapter(this, animalNames);
        adapter.setClickListener(this);
        recyclerView.setAdapter(adapter);
    }

    @Override
    public void onItemClick(View view, int position) {
        Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
    }
}

注意事项

  • 请注意,该活动实现了我们在适配器中定义的ItemClickListener。这使我们能够处理onItemClick 中的行点击事件。

完成

就是这样。您现在应该能够运行您的项目并获得类似于顶部图像的内容。

进行中

在行之间添加分隔符

你可以像这样添加一个简单的分隔符

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
    layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);

如果您想要更复杂一点的东西,请查看以下答案:

点击时更改行颜色

请参阅this answer,了解如何更改背景颜色并在单击一行时添加波纹效果。

更新行

请参阅this answer,了解如何添加、删除和更新行。

进一步阅读

【讨论】:

  • 非常好。这一直有效,直到我添加一个按钮并尝试设置它的点击监听器。有什么想法可能会干扰吗?
  • @johnktejik,从您在此处提供的信息中很难确切知道您在说什么。这可能最好作为一个新问题提出。我的猜测是您的按钮正在处理动作事件,因此其他事情不会得到它。
  • 抱歉.. 添加动物描述?例如:新 TextView 中的骆驼:是动物 // 新 TextVire 中的羊:是动物。我需要帮助..T_T
  • @coder,不客气。是的,我已经将它用于水平输出,并且效果相同。
  • 这个答案需要对 androidx 进行一些更新。
【解决方案2】:

准备好使用 Kotlin 模板的最小回收器视图:

  • 垂直布局
  • 每行有一个 TextView
  • 响应点击事件(Single 和 LongPress)

我知道这是一个旧线程,所以在这里回答。添加此答案以供将来参考:

在构建依赖中添加回收视图

  implementation 'com.google.android.material:material:1.4.0-alpha02'
    // RecyclerView
    implementation "androidx.recyclerview:recyclerview:1.2.0"

在布局中添加回收视图

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

创建布局以显示列表项 (list_item.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:padding="5dp"
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/ssid"
            android:text="@string/app_name"
            android:layout_width="match_parent"
            android:textSize="17sp"
            android:layout_height="wrap_content" />
        
    </LinearLayout>

</androidx.cardview.widget.CardView>

现在创建一个最小的适配器来保存数据,这里的代码是不言自明的

 class WifiAdapter(private val wifiList: ArrayList<ScanResult>) : RecyclerView.Adapter<WifiAdapter.ViewHolder>() {

     // holder class to hold reference
    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        //get view reference
        var ssid: TextView = view.findViewById(R.id.ssid) as TextView
    }

     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
         // create view holder to hold reference
         return ViewHolder( LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false))
     }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        //set values
        holder.ssid.text =  wifiList[position].SSID
    }

    override fun getItemCount(): Int {
        return wifiList.size
    }
      // update your data
     fun updateData(scanResult: ArrayList<ScanResult>) {
         wifiList.clear()
         notifyDataSetChanged()
         wifiList.addAll(scanResult)
         notifyDataSetChanged()

     }
 }

添加此类以处理列表项上的单击和长按事件

import android.content.Context;
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {

    public interface ClickListener {
        void onClick(View view, int position);

        void onLongClick(View view, RecyclerView recyclerView, int position);

    }
    private GestureDetector gestureDetector;
    private ClickListener clickListener;

    public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
        this.clickListener = clickListener;
        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                if (child != null && clickListener != null) {
                    clickListener.onLongClick(child,recyclerView,  recyclerView.getChildPosition(child));
                }
            }
        });
    }


    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        View child = rv.findChildViewUnder(e.getX(), e.getY());
        if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
            clickListener.onClick(child, rv.getChildPosition(child));
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }

最后将您的适配器设置为 Recycler View 并添加 Touch Listener 以开始拦截单击或双击列表项的触摸事件

    wifiAdapter = WifiAdapter(ArrayList())

    wifiList.apply {
        // vertical layout
        layoutManager = LinearLayoutManager(applicationContext)
        // set adapter
        adapter = wifiAdapter

        // Touch handling
        wifiList.addOnItemTouchListener(RecyclerTouchListener(applicationContext, wifiList, object : RecyclerTouchListener.ClickListener {
            override fun onClick(view: View?, position: Int) {
                Toast.makeText(applicationContext, "RV OnCLickj " + position, Toast.LENGTH_SHORT).show()
            }

            override fun onLongClick(view: View, recyclerView: RecyclerView, position: Int) {
                Toast.makeText(applicationContext, "RV OnLongCLickj " + position, Toast.LENGTH_SHORT).show()
            }
        }
        ))
    }

奖励:更新数据

wifiAdapter.updateData(mScanResults as ArrayList<ScanResult>)

结果:

【讨论】:

    【解决方案3】:

    这将是 RecyclerView 实现的最简单版本。

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/recycler_view"/>
    
    </FrameLayout>
    

    list_item_view.xml

    <?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="46dp">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textview"
            android:text="TextView"
            android:textSize="16dp" />
    
    </LinearLayout>
    

    CustomAdapter.java

    public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
      private List<String> data;
      public CustomAdapter (List<String> data){
        this.data = data;
      }
    
      @Override
      public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_view, parent, false);
        return new ViewHolder(rowItem);
      }
    
      @Override
      public void onBindViewHolder(CustomAdapter.ViewHolder holder, int position) {
        holder.textView.setText(this.data.get(position));
      }
    
      @Override
      public int getItemCount() {
        return this.data.size();
      }
    
      public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private TextView textView;
    
        public ViewHolder(View view) {
          super(view);
          view.setOnClickListener(this);
          this.textView = view.findViewById(R.id.textview);
        }
    
        @Override
        public void onClick(View view) {
          Toast.makeText(view.getContext(), "position : " + getLayoutPosition() + " text : " + this.textView.getText(), Toast.LENGTH_SHORT).show();
        }
      }
    }
    

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(new CustomAdapter(generateData()));
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
      }
    
      private List<String> generateData() {
        List<String> data = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
          data.add(String.valueOf(i) + "th Element");
        }
        return data;
      }
    
    }
    

    【讨论】:

      【解决方案4】:

      从添加 recyclerview 库开始。

      implementation 'androidx.recyclerview:recyclerview:1.1.0'
      

      创建模型类。

           public class UserModel implements Serializable {
      
          private String userName;
      
      
          public UserModel(String userName) {
              this.userName = userName;
          }
      
          public String getUserName() {
              return userName;
          }
      
          public void setUserName(String userName) {
              this.userName = userName;
          }
         }
      

      创建适配器类。

      public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UsersAdapterVh> implements Filterable {
      
          private List<UserModel> userModelList;
          private List<UserModel> getUserModelListFiltered;
          private Context context;
          private SelectedUser selectedUser;
      
          public UsersAdapter(List<UserModel> userModelList,SelectedUser selectedUser) {
              this.userModelList = userModelList;
              this.getUserModelListFiltered = userModelList;
              this.selectedUser = selectedUser;
          }
      
          @NonNull
          @Override
          public UsersAdapter.UsersAdapterVh onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
              context = parent.getContext();
      
              return new UsersAdapterVh(LayoutInflater.from(context).inflate(R.layout.row_users,null));
          }
      
          @Override
          public void onBindViewHolder(@NonNull UsersAdapter.UsersAdapterVh holder, int position) {
      
              UserModel userModel = userModelList.get(position);
      
              String username = userModel.getUserName();
              String prefix = userModel.getUserName().substring(0,1);
      
              holder.tvUsername.setText(username);
              holder.tvPrefix.setText(prefix);
      
          }
      
          @Override
          public int getItemCount() {
              return userModelList.size();
          }
      
          @Override
          public Filter getFilter() {
      
              Filter filter = new Filter() {
                  @Override
                  protected FilterResults performFiltering(CharSequence charSequence) {
                      FilterResults filterResults = new FilterResults();
      
                      if(charSequence == null | charSequence.length() == 0){
                          filterResults.count = getUserModelListFiltered.size();
                          filterResults.values = getUserModelListFiltered;
      
                      }else{
                          String searchChr = charSequence.toString().toLowerCase();
      
                          List<UserModel> resultData = new ArrayList<>();
      
                          for(UserModel userModel: getUserModelListFiltered){
                              if(userModel.getUserName().toLowerCase().contains(searchChr)){
                                  resultData.add(userModel);
                              }
                          }
                          filterResults.count = resultData.size();
                          filterResults.values = resultData;
      
                      }
      
                      return filterResults;
                  }
      
                  @Override
                  protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
      
                      userModelList = (List<UserModel>) filterResults.values;
                      notifyDataSetChanged();
      
                  }
              };
              return filter;
          }
      
      
          public interface SelectedUser{
      
              void selectedUser(UserModel userModel);
      
          }
      
          public class UsersAdapterVh extends RecyclerView.ViewHolder {
      
              TextView tvPrefix;
              TextView tvUsername;
              ImageView imIcon;
              public UsersAdapterVh(@NonNull View itemView) {
                  super(itemView);
                  tvPrefix = itemView.findViewById(R.id.prefix);
                  tvUsername = itemView.findViewById(R.id.username);
                  imIcon = itemView.findViewById(R.id.imageView);
      
                  itemView.setOnClickListener(new View.OnClickListener() {
                      @Override
                      public void onClick(View view) {
                          selectedUser.selectedUser(userModelList.get(getAdapterPosition()));
                      }
                  });
      
      
              }
          }
      }
      

      创建布局 row_uses.xml

          <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical" android:layout_width="match_parent"
          android:layout_height="match_parent">
      
          <RelativeLayout
              android:layout_width="match_parent"
              android:padding="10dp"
              android:layout_height="wrap_content">
      
              <RelativeLayout
                  android:layout_width="50dp"
                  android:background="@drawable/users_bg"
                  android:layout_height="50dp">
                  <TextView
                      android:id="@+id/prefix"
                      android:layout_width="wrap_content"
                      android:textSize="16sp"
                      android:textColor="@color/headerColor"
                      android:text="T"
                      android:layout_centerInParent="true"
                      android:layout_height="wrap_content"/>
      
              </RelativeLayout>
              <TextView
                  android:id="@+id/username"
                  android:layout_width="wrap_content"
                  android:textSize="16sp"
                  android:textColor="@color/headerColor"
                  android:text="username"
                  android:layout_marginStart="90dp"
                  android:layout_centerVertical="true"
                  android:layout_height="wrap_content"/>
              <ImageView
                  android:layout_width="wrap_content"
                  android:id="@+id/imageView"
                  android:layout_margin="10dp"
                  android:layout_alignParentEnd="true"
                  android:src="@drawable/ic_navigate_next_black_24dp"
                  android:layout_height="wrap_content"/>
          </RelativeLayout>
      
      </LinearLayout>
      

      查找 recyclerview 并填充数据。

      Toolbar toolbar;
      RecyclerView recyclerView;
      
      List<UserModel> userModelList = new ArrayList<>();
      
      String[] names = {"Richard","Alice","Hannah","David"};
      
      UsersAdapter usersAdapter;
      
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
      
          recyclerView = findViewById(R.id.recyclerview);
          toolbar = findViewById(R.id.toolbar);
      
          this.setSupportActionBar(toolbar);
          this.getSupportActionBar().setTitle("");
      
          recyclerView.setLayoutManager(new LinearLayoutManager(this));
          recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
      
          for(String s:names){
              UserModel userModel = new UserModel(s);
      
              userModelList.add(userModel);
          }
      
          usersAdapter = new UsersAdapter(userModelList,this);
      
          recyclerView.setAdapter(usersAdapter);
      
      }
      

      在这里找到完整的教程和源代码:

      Android RecyclerView

      【讨论】:

      • 为什么要将上下文发送给用户适配器类usersAdapter = new UsersAdapter(userModelList,this); ?.
      • @OmarBoshra this 指的是SelectedUser接口的实现。
      【解决方案5】:

      这是一个更新的 Kotlin 解决方案,它比这里写的许多答案简单得多,它使用匿名类。

      val items = mutableListOf<String>()
      
      inner class ItemHolder(view: View): RecyclerView.ViewHolder(view) {
          var textField: TextView = view.findViewById(android.R.id.text1) as TextView
      }
      
      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
          rvitems.layoutManager = LinearLayoutManager(context)
          rvitems.adapter = object : RecyclerView.Adapter<ItemHolder>() {
      
              override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder {
                  return ItemHolder(LayoutInflater.from(parent.context).inflate(android.R.layout.simple_list_item_1, parent, false))
              }
      
              override fun getItemCount(): Int {
                  return items.size
              }
      
              override fun onBindViewHolder(holder: ItemHolder, position: Int) {
                  holder.textField.text = items[position]
                  holder.textField.setOnClickListener {
                      Toast.makeText(context, "Clicked $position", Toast.LENGTH_SHORT).show()
                  }
              }
          }
      }
      

      我冒昧地使用了 android.R.layout.simple_list_item_1,因为它更简单。我想进一步简化它并将 ItemHolder 作为内部类,但无法完全弄清楚如何在外部类参数的类型中引用它。

      【讨论】:

      • 我几乎放弃了 kotlin 和 android 开发,因为没有简单的解决方案,直到我看到你的。谢谢!
      • 有趣。您如何响应点击?
      • @SMBiggs 你是什么意思?处理点击的代码也出现在 onBindViewHolder 内的这个示例中。
      • 我现在看到了——我的错。我不知何故跳过了 onBindViewHolder 的那部分。
      【解决方案6】:

      基于不同的来源,我使用简单库创建了 RecyclerView 的简单实现。

      build.gradle中添加这一行

      implementation 'com.hereshem.lib:awesomelib:2.0.1'
      

      添加通过在activity_main.xml中添加MyRecyclerView来创建一个RecyclerView

      <com.hereshem.lib.recycler.MyRecyclerView
              android:id="@+id/recycler"
              app:layoutManager="LinearLayoutManager"
              android:layout_width="match_parent"
              android:layout_height="match_parent"/>
      

      现在在 MainActivity 中,通过传递需要绑定的 Class 的名称来创建一个 ViewHolder

      public static class EVHolder extends MyViewHolder<Events> {
          TextView date, title, summary;
          public EVHolder(View v) {
              super(v);
              date = v.findViewById(R.id.date);
              title = v.findViewById(R.id.title);
              summary = v.findViewById(R.id.summary);
          }
          @Override
          public void bindView(Events c) {
              date.setText(c.date);
              title.setText(c.title);
              summary.setText(c.summary);
          }
      }
      

      通过在适配器中传递项目、类和布局来创建项目列表变量和适配器

      List<Events> items = new ArrayList<>();
      MyRecyclerView recycler = findViewById(R.id.recycler);
      RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, items, EVHolder.class, R.layout.row_event);
      recycler.setAdapter(adapter);
      

      ClickListener 可以通过以下几行添加

      recycler.setOnItemClickListener(new MyRecyclerView.OnItemClickListener() {
          @Override
          public void onItemClick(int position) {
              Toast.makeText(MainActivity.this, "Recycler Item Clicked " + position, Toast.LENGTH_SHORT).show();
          }
      });
      

      一切都搞定了。

      更多示例和实现可以在here 找到。 希望这会有所帮助!!!

      【讨论】:

      • 什么是单一活动
      • :错误:找不到符号摘要 = v.findViewById(R.id.summary); ^ 符号:变量摘要位置:类 id EVHolder.java:15:错误:方法未覆盖或实现超类型 @Override 的方法 ^ EVHolder.java:17:错误:找不到符号 date.setText(c.date) ;
      • @johnktejik R.id.summary 是为布局资源文件提供的 ID。请查看此布局文件github.com/hereshem/Easy-RecyclerView-Library/blob/master/app/…
      【解决方案7】:

      开始,只是在 Recycler 视图中查看一些东西

      recycler view adapter 可以是这样的。

      class CustomAdapter: RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
          var data =  listOf<String>()
              set(value) {
                  field = value
                  notifyDataSetChanged()
              }
          override fun getItemCount() =data.size
      
          override fun onBindViewHolder(holder: ViewHolder, position: Int) {
              holder.txt.text= data[position]
          }
          override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
              return ViewHolder(
                  LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false)
              )
          }
      
      
          class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
              val txt: TextView = itemView.findViewById(R.id.item_text_view)
          }
      }
      

      并将适配器附加到回收器视图并将数据附加到适配器

      val view = findViewById<RecyclerView>(R.id.recycler_view)                                              
      val adapter = CustomAdapter()                                                                          
      val data = listOf("text1", "text2", "text3")
      adapter.data = data                                                                             
      view.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
      view.adapter = adapter       
                  
      

      【讨论】:

        【解决方案8】:

        现在你需要1 adapter 来代表所有RecyclerView

        • 一个适配器可用于所有 RecyclerView。所以 NO onBindViewHolder, No onCreateViewHolder 处理。
        • 没有用于从 Java/Kotlin 类设置适配器的代码。检查sample class
        • 您可以使用Binding Adapters为每个列表设置事件和自定义数据。

        我在这里展示了通过 1 个适配器设置两个不同的 RecyclerView -

        activity_home.xml

        <?xml version="1.0" encoding="utf-8"?>
        <layout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto">
        
            <data>
        
                <variable
                    name="listOne"
                    type="java.util.List"/>
        
                <variable
                    name="listTwo"
                    type="java.util.List"/>
        
                <variable
                    name="onItemClickListenerOne"
                    type="com.ks.nestedrecyclerbindingexample.callbacks.OnItemClickListener"/>
        
                <variable
                    name="onItemClickListenerTwo"
                    type="com.ks.nestedrecyclerbindingexample.callbacks.OnItemClickListener"/>
        
            </data>
        
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
        
                <android.support.v7.widget.RecyclerView
                    rvItemLayout="@{@layout/row_one}"
                    rvList="@{listOne}"
                    rvOnItemClick="@{onItemClickListenerOne}"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layoutManager="android.support.v7.widget.LinearLayoutManager"
                    />
        
                <android.support.v7.widget.RecyclerView
                    rvItemLayout="@{@layout/row_two}"
                    rvList="@{listTwo}"
                    rvOnItemClick="@{onItemClickListenerTwo}"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layoutManager="android.support.v7.widget.LinearLayoutManager"
                    />
        
            </LinearLayout>
        
        </layout>
        

        你可以看到我从布局中传递了列表、项目布局id和点击监听器。

        rvItemLayout="@{@layout/row_one}"
        rvList="@{listOne}"
        rvOnItemClick="@{onItemClickListenerOne}"
        

        此自定义属性由 BindingAdapter 创建。

        public class BindingAdapters {
            @BindingAdapter(value = {"rvItemLayout", "rvList", "rvOnItemClick"}, requireAll = false)
            public static void setRvAdapter(RecyclerView recyclerView, int rvItemLayout, List rvList, @Nullable OnItemClickListener onItemClickListener) {
                if (rvItemLayout != 0 && rvList != null && rvList.size() > 0)
                    recyclerView.setAdapter(new GeneralAdapter(rvItemLayout, rvList, onItemClickListener));
            }
        }
        

        现在从Activity,你传递列表,点击监听器

        HomeActivity.java

        public class HomeActivity extends AppCompatActivity {
            ActivityHomeBinding binding;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                binding = DataBindingUtil.setContentView(this, R.layout.activity_home);
                binding.setListOne(new ArrayList()); // pass your list or set list from response of API
                binding.setListTwo(new ArrayList());
                binding.setOnItemClickListenerOne(new OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, Object object) {
                        if (object instanceof ModelParent) {
                            // TODO: your action here
                        }
                    }
                });
                binding.setOnItemClickListenerTwo(new OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, Object object) {
                        if (object instanceof ModelChild) {
                            // TODO: your action here  
                        }
                    }
                });
            }
        }
        

        你不想读太多,直接从我的github repo克隆/下载full example。自己试试吧。

        你可以在上面的 repo 中看到GeneralAdapter.java

        如果您在设置数据绑定时遇到问题,请参阅this answer

        【讨论】:

          【解决方案9】:

          依赖关系

          compile 'com.android.support:appcompat-v7:25.3.1'
          compile 'com.android.support:design:25.3.1'
          compile 'com.android.support:multidex:1.0.1'
          compile 'com.android.support:cardview-v7:25.3.1'
          compile 'com.android.support:support-v4:25.3.1'
          compile 'com.lguipeng.bubbleview:library:1.0.0'
          compile 'com.larswerkman:HoloColorPicker:1.5'
          compile 'com.mcxiaoke.volley:library-aar:1.0.0'
          

          点击项的一个类

          import android.content.Context;
          import android.support.v7.widget.RecyclerView;
          import android.view.GestureDetector;
          import android.view.MotionEvent;
          import android.view.View;
          
          public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
              private OnItemClickListener mListener;
          
              public interface OnItemClickListener {
                  public void onItemClick(View view, int position);
              }
          
              GestureDetector mGestureDetector;
          
              public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
                  mListener = listener;
                  mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                      @Override
                      public boolean onSingleTapUp(MotionEvent e) {
                          return true;
                      }
                  });
              }
          
              @Override
              public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
                  View childView = view.findChildViewUnder(e.getX(), e.getY());
                  if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
                      mListener.onItemClick(childView, view.getChildPosition(childView));
                      return true;
                  }
                  return false;
              }
          
              @Override
              public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }
          
              @Override
              public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
          
              }
          
          
          }
          

          二等 RecyclerView

          import android.annotation.SuppressLint;
          import android.app.ProgressDialog;
          import android.content.BroadcastReceiver;
          import android.content.Context;
          import android.content.Intent;
          import android.content.IntentFilter;
          import android.net.Uri;
          import android.os.Bundle;
          import android.support.annotation.Nullable;
          import android.support.v4.app.Fragment;
          import android.support.v4.app.FragmentTransaction;
          import android.support.v4.content.LocalBroadcastManager;
          import android.support.v7.widget.LinearLayoutManager;
          import android.support.v7.widget.RecyclerView;
          import android.util.Log;
          import android.view.LayoutInflater;
          import android.view.View;
          import android.view.ViewGroup;
          import android.widget.Toast;
          
          import com.android.volley.DefaultRetryPolicy;
          import com.android.volley.Request;
          import com.android.volley.RequestQueue;
          import com.android.volley.Response;
          import com.android.volley.VolleyError;
          import com.android.volley.toolbox.StringRequest;
          import com.android.volley.toolbox.Volley;
          
          import org.json.JSONArray;
          import org.json.JSONException;
          import org.json.JSONObject;
          import java.util.ArrayList;
          
          public class SLByTopics extends Fragment {
          
          
              public static ArrayList<MByTopics> byTopicsMainArrayList=new ArrayList<>();
          
          
              TabRefreshReceiver tabRefreshReceiver;
              RecyclerView recyclerView;
              SAdpByTopics sAdpByTopics;
              public ArrayList<MByTopics> mByTopicsArrayList=new ArrayList<>();
              ProgressDialog progressDialog;
          
              public SLByTopics(){
              }
          
              @Override
              public void onCreate(@Nullable Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
              }
          
              @Override
              public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                  View view = inflater.inflate(R.layout.sl_fragment_by_topics, container, false);
          
                  progressDialog = new ProgressDialog(getActivity());
                  if (IsOnline.isNetworkAvailable(getActivity())) {
                      getCategoryTree();
                  } else{
                      IsOnline.showNoInterNetMessage(getActivity());
                  }
                  tabRefreshReceiver = new TabRefreshReceiver();
                 LocalBroadcastManager.getInstance(getContext()).registerReceiver(tabRefreshReceiver, new IntentFilter("BY_TOPICS"));
          
                  setUpView(view);
                  return view;
              }
          
              private void setUpView(View view) {
          
                  recyclerView=(RecyclerView)view.findViewById(R.id.by_topics_list_recyclerView);
                  LinearLayoutManager linearLayoutManager=new LinearLayoutManager(getActivity());
                  linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
                  recyclerView.setLayoutManager(linearLayoutManager);
              }
          
              @Override
              public void onResume() {
                  super.onResume();
          
                  recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
                      @Override
                      public void onItemClick(View view, final int position) {
          
                          if (mByTopicsArrayList.get(position).getChild().size()>0){
                              Intent intent = new Intent(getActivity(), SByTopicCategory.class);
                              intent.putExtra("selectedCategoryName",mByTopicsArrayList.get(position).getCatname());
                              intent.putExtra("jsonData",mByTopicsArrayList.get(position).getMainTopicJson());
                              startActivity(intent);
                              getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
                          }else {
                              Intent intent = new Intent(getActivity(), SByCategoryQuestionList.class);
                              intent.putExtra("selectedSubCategoryName",mByTopicsArrayList.get(position).getCatname());
                              intent.putExtra("catID",mByTopicsArrayList.get(position).getId());
                              startActivity(intent);
                              getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
                          }
                      }
                  }));
          
              }
          
              private class TabRefreshReceiver extends BroadcastReceiver {
                  @Override
                  public void onReceive(Context context, Intent intent) {
                      try {
                          FragmentTransaction ft = getFragmentManager().beginTransaction();
                          ft.detach(SLByTopics.this).attach(SLByTopics.this).commit();
                          LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(tabRefreshReceiver);
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
          
                  }
              }
          
              private void getCategoryTree() {
                  progressDialog.setMessage("Please Wait...");
                  progressDialog.setCancelable(false);
                  progressDialog.show();
          
                  StringRequest stringRequest = new StringRequest(Request.Method.POST, Const.HOSTNAME + Const.STUDENT_GET_CATEGORY_TREE,
                          new Response.Listener<String>() {
                              @SuppressLint("LongLogTag")
                              @Override
                              public void onResponse(String response) {
                                  try {
                                      JSONObject object = new JSONObject(response);
                                      String status = object.getString("status");
                                      int i = Integer.parseInt(status);
          
                                      switch (i) {
          
                                          case 0:
                                              progressDialog.dismiss();
          //                                    Toast.makeText(getActivity(), "getCategorySuccess", Toast.LENGTH_SHORT).show();
                                              Log.e("getCategoryTree Response", "getCategoryTree Response : " + response);
          
                                              try {    
                                                  byTopicsMainArrayList.clear();
                                                  JSONArray info = object.getJSONArray("info");
                                                  if (info.length() > 0) {
                                                      for (i = 0; i < info.length(); i++) {
                                                          JSONObject data = info.getJSONObject(i);
                                                          MByTopics mByTopics = new MByTopics();
                                                          mByTopics.setId(data.getString("id"));
                                                          mByTopics.setCatname(data.getString("catname"));
                                                          mByTopics.setMainTopicJson(data.toString());
          
                                                          JSONArray topicChildren = data.getJSONArray("children");
                                                          ArrayList<SMByTopicCategory> byChildrenArrayList = new ArrayList<>();
          
                                                          for (int j = 0; j < topicChildren.length(); j++) {
                                                              JSONObject topicChildrenData = topicChildren.getJSONObject(j);
                                                              SMByTopicCategory smByTopicCategory = new SMByTopicCategory();
                                                              smByTopicCategory.setId(topicChildrenData.getString("id"));
                                                              smByTopicCategory.setCatname(topicChildrenData.getString("catname"));
                                                              smByTopicCategory.setChildTopicJson(topicChildrenData.toString());
          
                                                              JSONArray topicChildrenQuestion = topicChildrenData.getJSONArray("children");
                                                              ArrayList<SMByTopicSubCategory> byChildrenSubArrayList = new ArrayList<>();
          
                                                              for (int k = 0; k < topicChildrenQuestion.length(); k++) {
                                                                  JSONObject topicChildrenSubData = topicChildrenQuestion.getJSONObject(k);
                                                                  SMByTopicSubCategory smByTopicSubCategory = new SMByTopicSubCategory();
                                                                  smByTopicSubCategory.setId(topicChildrenSubData.getString("id"));
                                                                  smByTopicSubCategory.setCatname(topicChildrenSubData.getString("catname"));
                                                                  smByTopicSubCategory.setChildSubTopicJson(topicChildrenSubData.toString());
          
                                                                  byChildrenSubArrayList.add(smByTopicSubCategory);
                                                              }
          
                                                              smByTopicCategory.setQuestions(byChildrenSubArrayList);
          
                                                              byChildrenArrayList.add(smByTopicCategory);
                                                          }
                                                          mByTopics.setChild(byChildrenArrayList);
                                                          byTopicsMainArrayList.add(mByTopics);
                                                      }
          
          
                                                      mByTopicsArrayList.clear();
                                                      mByTopicsArrayList=byTopicsMainArrayList;
                                                      sAdpByTopics=new SAdpByTopics(mByTopicsArrayList,getActivity());
                                                      recyclerView.setAdapter(sAdpByTopics);
                                                      sAdpByTopics.notifyDataSetChanged();
          
                                                  }
          
                                              }catch (Exception e){
                                                  e.printStackTrace();
                                              }
                                              break;
          
                                          default:
                                              progressDialog.dismiss();
          //                                    Toast.makeText(getActivity(), "getCategoryError : " + response, Toast.LENGTH_SHORT).show();
                                              Log.e("getCategoryTree Not Response", "getCategoryTree Uploading Not Response : " + response);
                                      }
          
                                  } catch (JSONException e) {
                                      e.printStackTrace();
                                  }
                              }
                          },
                          new Response.ErrorListener() {
                              @Override
                              public void onErrorResponse(VolleyError error) {
                                  progressDialog.dismiss();
                                  Log.e("getCategoryTree Error :","getCategoryTree Error :"+error.getMessage());
          //                        Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_LONG).show();
                              }
                          }){
          
                  };/* {
                      @Override
                      protected Map<String, String> getParams() throws AuthFailureError {
          
                          Map<String, String> map = new HashMap<String, String>();
          //                map.put("uid", String.valueOf(ConfigManager.getUserId()));
                          return map;
                      }
                  };*/
          
                  stringRequest.setRetryPolicy(new DefaultRetryPolicy(
                          0,
                          DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                          DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
          
                  RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
                  requestQueue.add(stringRequest);
              }
          }
          

          回收站项目的适配器类

          import android.app.Activity;
          import android.support.v7.widget.RecyclerView;
          import android.view.LayoutInflater;
          import android.view.View;
          import android.view.ViewGroup;
          import android.widget.TextView;
          import java.util.ArrayList;
          
          public class SAdpByTopics extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
                  ArrayList<MByTopics> topicsArrayList=new ArrayList<>();
                  Activity activity;
          
               public SAdpByTopics(ArrayList<MByTopics> topicsArrayList,Activity activity){
                  this.topicsArrayList=topicsArrayList;
                  this.activity=activity;
               }
          
               @Override
               public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                  View itemeView= LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_by_topic_list,parent,false);
                  RecyclerView.ViewHolder holder=new Holder(itemeView);
                  holder.setIsRecyclable(false);
                  return holder;
               }
          
               @Override
               public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
                   final Holder classHolder = (Holder) holder;
                   try{
                       classHolder.txt_topic_name.setText(topicsArrayList.get(position).getCatname());
                   }catch (Exception e){
                       e.printStackTrace();
                   }
               }
          
               @Override
               public int getItemCount() {
                  return topicsArrayList.size();
               }
          
          
          class Holder extends RecyclerView.ViewHolder implements View.OnClickListener {
              TextView txt_topic_name;
          
              public Holder(View itemView) {
                  super(itemView);
                  txt_topic_name = (TextView) itemView.findViewById(R.id.txt_topic_name);
              }
          
              @Override
              public void onClick(View v) {
          
              }
          }
          }
          

          模块类

          public class MByTopics {
          
              String id;
              String topicName;
              String catname;
              String MainTopicJson;
              ArrayList<SMByTopicCategory> child;
              ArrayList<SMByTopicSubCategory> questions;
          
              public void setId(String id){
                  this.id=id;
              }
              public String getId(){
                  return  id;
              }
          
              public void setCatname(String catname) {
                  this.catname = catname;
              }
          
              public String getCatname() {
                  return catname;
              }
          
              public void setTopicName(String topicName) {
                  this.topicName = topicName;
              }
              public String getTopicName() {
                  return topicName;
              }
          
              public void setChild(ArrayList<SMByTopicCategory> child) {
                  this.child = child;
              }
          
              public String getMainTopicJson() {
                  return MainTopicJson;
              }
          
              public void setMainTopicJson(String mainTopicJson) {
                  MainTopicJson = mainTopicJson;
              }
          
              public ArrayList<SMByTopicCategory> getChild() {
                  return child;
              }
          
              public void setQuestions(ArrayList<SMByTopicSubCategory> questions) {
                  this.questions = questions;
              }
          
              public ArrayList<SMByTopicSubCategory> getQuestions() {
                  return questions;
              }
          
              public ArrayList<MByTopics> getByTopicList() {
                  ArrayList<MByTopics> mByTopicsArrayList = new ArrayList<>();
          
                  for (int i=0;i<11;i++){
                      MByTopics mQuestionBankCategory=new MByTopics();
          
                      if (i==1 || i== 5|| i==9){
                          mQuestionBankCategory.setTopicName("Microeconomics");
                      }else  if (i==2 || i== 10|| i==6) {
                          mQuestionBankCategory.setTopicName("Macroeconomics");
                      }else {
                          mQuestionBankCategory.setTopicName("Current Isssues");
                      }
          
                      mByTopicsArrayList.add(mQuestionBankCategory);
                  }
          
                  return mByTopicsArrayList;
              }
          
          }
          

          【讨论】:

          • 解释会很好
          • 代码不干净,没有解释!
          【解决方案10】:

          由于我无法发表评论,但我将发布链接作为答案。我在 recyclerview 上找到了一个简单、组织良好的教程 http://www.androiddeft.com/2017/10/01/recyclerview-android/

          除此之外,当您要在活动中添加回收站视图时,您想要执行的操作如下,链接中已经描述了您应该如何执行此操作

          • 将 RecyclerView 组件添加到您的布局文件中
          • 创建一个要显示为列表行的类
          • 制作一个布局文件,它是你列表中一行的布局
          • 现在我们需要一个自定义适配器,所以通过扩展创建一个自定义适配器 来自父类 RecyclerView.Adapter
          • 将 recyclerview 添加到您的 mainActivity oncreate
          • 添加分隔符
          • 添加触摸监听器

          【讨论】:

            【解决方案11】:

            您可以将抽象适配器与差异工具和过滤器一起使用

            SimpleAbstractAdapter.kt

            abstract class SimpleAbstractAdapter<T>(private var items: ArrayList<T> = arrayListOf()) : RecyclerView.Adapter<SimpleAbstractAdapter.VH>() {
               protected var listener: OnViewHolderListener<T>? = null
               private val filter = ArrayFilter()
               private val lock = Any()
               protected abstract fun getLayout(): Int
               protected abstract fun bindView(item: T, viewHolder: VH)
               protected abstract fun getDiffCallback(): DiffCallback<T>?
               private var onFilterObjectCallback: OnFilterObjectCallback? = null
               private var constraint: CharSequence? = ""
            
            override fun onBindViewHolder(vh: VH, position: Int) {
                getItem(position)?.let { bindView(it, vh) }
            }
            
            override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
                return VH(parent, getLayout())
            }
            
            override fun getItemCount(): Int = items.size
            
            protected abstract class DiffCallback<T> : DiffUtil.Callback() {
                private val mOldItems = ArrayList<T>()
                private val mNewItems = ArrayList<T>()
            
                fun setItems(oldItems: List<T>, newItems: List<T>) {
                    mOldItems.clear()
                    mOldItems.addAll(oldItems)
                    mNewItems.clear()
                    mNewItems.addAll(newItems)
                }
            
                override fun getOldListSize(): Int {
                    return mOldItems.size
                }
            
                override fun getNewListSize(): Int {
                    return mNewItems.size
                }
            
                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                    return areItemsTheSame(
                            mOldItems[oldItemPosition],
                            mNewItems[newItemPosition]
                    )
                }
            
                abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean
            
                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                    return areContentsTheSame(
                            mOldItems[oldItemPosition],
                            mNewItems[newItemPosition]
                    )
                }
            
                abstract fun areContentsTheSame(oldItem: T, newItem: T): Boolean
            }
            
            class VH(parent: ViewGroup, @LayoutRes layout: Int) : RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(layout, parent, false))
            
            interface OnViewHolderListener<T> {
                fun onItemClick(position: Int, item: T)
            }
            
            fun getItem(position: Int): T? {
                return items.getOrNull(position)
            }
            
            fun getItems(): ArrayList<T> {
                return items
            }
            
            fun setViewHolderListener(listener: OnViewHolderListener<T>) {
                this.listener = listener
            }
            
            fun addAll(list: List<T>) {
                val diffCallback = getDiffCallback()
                when {
                    diffCallback != null && !items.isEmpty() -> {
                        diffCallback.setItems(items, list)
                        val diffResult = DiffUtil.calculateDiff(diffCallback)
                        items.clear()
                        items.addAll(list)
                        diffResult.dispatchUpdatesTo(this)
                    }
                    diffCallback == null && !items.isEmpty() -> {
                        items.clear()
                        items.addAll(list)
                        notifyDataSetChanged()
                    }
                    else -> {
                        items.addAll(list)
                        notifyDataSetChanged()
                    }
                }
            }
            
            fun add(item: T) {
                items.add(item)
                notifyDataSetChanged()
            }
            
            fun add(position:Int, item: T) {
                items.add(position,item)
                notifyItemInserted(position)
            }
            
            fun remove(position: Int) {
                items.removeAt(position)
                notifyItemRemoved(position)
            }
            
            fun remove(item: T) {
                items.remove(item)
                notifyDataSetChanged()
            }
            
            fun clear(notify: Boolean=false) {
                items.clear()
                if (notify) {
                    notifyDataSetChanged()
                }
            }
            
            fun setFilter(filter: SimpleAdapterFilter<T>): ArrayFilter {
                return this.filter.setFilter(filter)
            }
            
            interface SimpleAdapterFilter<T> {
                fun onFilterItem(contains: CharSequence, item: T): Boolean
            }
            
            fun convertResultToString(resultValue: Any): CharSequence {
                return filter.convertResultToString(resultValue)
            }
            
            fun filter(constraint: CharSequence) {
                this.constraint = constraint
                filter.filter(constraint)
            }
            
            fun filter(constraint: CharSequence, listener: Filter.FilterListener) {
                this.constraint = constraint
                filter.filter(constraint, listener)
            }
            
            fun getFilter(): Filter {
                return filter
            }
            
            interface OnFilterObjectCallback {
                fun handle(countFilterObject: Int)
            }
            
            fun setOnFilterObjectCallback(objectCallback: OnFilterObjectCallback) {
                onFilterObjectCallback = objectCallback
            }
            
            inner class ArrayFilter : Filter() {
                private var original: ArrayList<T> = arrayListOf()
                private var filter: SimpleAdapterFilter<T> = DefaultFilter()
                private var list: ArrayList<T> = arrayListOf()
                private var values: ArrayList<T> = arrayListOf()
            
            
                fun setFilter(filter: SimpleAdapterFilter<T>): ArrayFilter {
                    original = items
                    this.filter = filter
                    return this
                }
            
                override fun performFiltering(constraint: CharSequence?): Filter.FilterResults {
                    val results = Filter.FilterResults()
                    if (constraint == null || constraint.isBlank()) {
                        synchronized(lock) {
                            list = original
                        }
                        results.values = list
                        results.count = list.size
                    } else {
                        synchronized(lock) {
                            values = original
                        }
                        val result = ArrayList<T>()
                        for (value in values) {
                            if (constraint!=null && constraint.trim().isNotEmpty() && value != null) {
                                if (filter.onFilterItem(constraint, value)) {
                                    result.add(value)
                                }
                            } else {
                                value?.let { result.add(it) }
                            }
                        }
                        results.values = result
                        results.count = result.size
                    }
                    return results
                }
            
                override fun publishResults(constraint: CharSequence, results: Filter.FilterResults) {
                    items = results.values as? ArrayList<T> ?: arrayListOf()
                    notifyDataSetChanged()
                    onFilterObjectCallback?.handle(results.count)
                }
            
            }
            
            class DefaultFilter<T> : SimpleAdapterFilter<T> {
                override fun onFilterItem(contains: CharSequence, item: T): Boolean {
                    val valueText = item.toString().toLowerCase()
                    if (valueText.startsWith(contains.toString())) {
                        return true
                    } else {
                        val words = valueText.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                        for (word in words) {
                            if (word.contains(contains)) {
                                return true
                            }
                        }
                    }
                    return false
                }
              }
            }
            

            并通过实现方法扩展抽象适配器

            TasksAdapter.kt

            import android.annotation.SuppressLint
              import kotlinx.android.synthetic.main.task_item_layout.view.*
            
            class TasksAdapter(private val listener:TasksListener? = null) : SimpleAbstractAdapter<Task>() {
            override fun getLayout(): Int {
                return R.layout.task_item_layout
            }
            
            override fun getDiffCallback(): DiffCallback<Task>? {
                return object : DiffCallback<Task>() {
                    override fun areItemsTheSame(oldItem: Task, newItem: Task): Boolean {
                        return oldItem.id == newItem.id
                    }
            
                    override fun areContentsTheSame(oldItem: Task, newItem: Task): Boolean {
                        return oldItem.items == newItem.items
                    }
                }
            }
            
            @SuppressLint("SetTextI18n")
            override fun bindView(item: Task, viewHolder: VH) {
                viewHolder.itemView.apply {
                    val position = viewHolder.adapterPosition
                    val customer = item.customer
                    val customerName = if (customer != null) customer.name else ""
                    tvTaskCommentTitle.text = customerName + ", #" + item.id
                    tvCommentContent.text = item.taskAddress
                    ivCall.setOnClickListener {
                        listener?.onCallClick(position, item)
                    }
                    setOnClickListener {
                        listener?.onItemClick(position, item)
                    }
                }
            }
            
             interface TasksListener : SimpleAbstractAdapter.OnViewHolderListener<Task> {
                fun onCallClick(position: Int, item: Task)
             }
            }
            

            初始化适配器

            mAdapter = TasksAdapter(object : TasksAdapter.TasksListener {
                        override fun onCallClick(position: Int, item:Task) {
                        }
            
                        override fun onItemClick(position: Int, item:Task) {
            
                        }
                    })
            rvTasks.adapter = mAdapter
            

            填充

            mAdapter?.addAll(tasks)
            

            添加自定义过滤器

            mAdapter?.setFilter(object : SimpleAbstractAdapter.SimpleAdapterFilter<MoveTask> {
                        override fun onFilterItem(contains: CharSequence, item:Task): Boolean {
                            return contains.toString().toLowerCase().contains(item.id?.toLowerCase().toString())
                        }
                })
            

            过滤数据

            mAdapter?.filter("test")
            

            【讨论】:

            【解决方案12】:

            实现 androidx.recyclerview:recyclerview:.... 建议更新到这里的 androidx 库:

            https://developer.android.com/jetpack/androidx/releases/recyclerview

            然后必须将布局文件 Widget XML 标签更新为: androidx.recyclerview.widget.RecyclerView

            【讨论】:

            • 你是对的。我需要用 AndroidX 更新我的答案。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-06-21
            • 2017-03-27
            • 2011-03-13
            • 2016-02-19
            • 2016-02-02
            • 2018-06-13
            • 1970-01-01
            相关资源
            最近更新 更多