【问题标题】:Divide elements on groups in RecyclerView or Grouping Recyclerview items ,say by date在 RecyclerView 或 Grouping Recyclerview 项目中按组划分元素,例如按日期
【发布时间】:2017-01-03 15:38:18
【问题描述】:

我想将我的 android RecyclerView 项目与基于日期制作的标题分组,如下所示:

    1 week ago
    - item
    - item
    - item
    - item
    2 weeks ago
    - item
    - item
    - item

那种东西或基于某些元素的分组。

【问题讨论】:

    标签: java android android-recyclerview


    【解决方案1】:

    这是我借助网络上的大量研究和此博客链接以及Kartikey Kuswhaha 得出的一个解决方案,因此这不是我的全部功劳,但我只是想更清楚地说明它。 下面是代码: 创建以下文件:PojoOfJsonArrayMainActivityListItemGeneralItemDateItem适配器

    PojoOfJsonArray.java - 此文件将代表您的 POJO 类或您在应用程序中进行的任何 pojo:

     public class PojoOfJsonArray  {
    
        public PojoOfJsonArray(String name, String date) {
            this.name = name;
            this.date = date;
        }
    
        private String name,date;
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getDate() {
            return date;
        }
    
        public void setDate(String date) {
            this.date = date;
        }
    }
    

    MainActivity.java 这是您将用于实现 recyclerview 的活动:

    public class MainActivity extends AppCompatActivity {
        private List<PojoOfJsonArray> myOptions = new ArrayList<>();
        List<ListItem> consolidatedList = new ArrayList<>();
    
        private RecyclerView mRecyclerView;
        private Adapter adapter;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
            mRecyclerView.setHasFixedSize(true);
    
            myOptions.add(new PojoOfJsonArray("name 1", "2016-06-21"));
            myOptions.add(new PojoOfJsonArray("name 2", "2016-06-05"));
            myOptions.add(new PojoOfJsonArray("name 2", "2016-06-05"));
            myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
            myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
            myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
            myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
            myOptions.add(new PojoOfJsonArray("name 2", "2016-06-05"));
            myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
    
            HashMap<String, List<PojoOfJsonArray>> groupedHashMap = groupDataIntoHashMap(myOptions);
    
    
            for (String date : groupedHashMap.keySet()) {
                DateItem dateItem = new DateItem();
                dateItem.setDate(date);
                consolidatedList.add(dateItem);
    
    
                for (PojoOfJsonArray pojoOfJsonArray : groupedHashMap.get(date)) {
                    GeneralItem generalItem = new GeneralItem();
                    generalItem.setPojoOfJsonArray(pojoOfJsonArray);//setBookingDataTabs(bookingDataTabs);
                    consolidatedList.add(generalItem);
                }
            }
    
    
            adapter = new Adapter(this, consolidatedList);
            LinearLayoutManager layoutManager = new LinearLayoutManager(this);
            layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            mRecyclerView.setLayoutManager(layoutManager);
            mRecyclerView.setAdapter(adapter);
    
    
        }
    
        private HashMap<String, List<PojoOfJsonArray>> groupDataIntoHashMap(List<PojoOfJsonArray> listOfPojosOfJsonArray) {
    
            HashMap<String, List<PojoOfJsonArray>> groupedHashMap = new HashMap<>();
    
            for (PojoOfJsonArray pojoOfJsonArray : listOfPojosOfJsonArray) {
    
                String hashMapKey = pojoOfJsonArray.getDate();
    
                if (groupedHashMap.containsKey(hashMapKey)) {
                    // The key is already in the HashMap; add the pojo object
                    // against the existing key.
                    groupedHashMap.get(hashMapKey).add(pojoOfJsonArray);
                } else {
                    // The key is not there in the HashMap; create a new key-value pair
                    List<PojoOfJsonArray> list = new ArrayList<>();
                    list.add(pojoOfJsonArray);
                    groupedHashMap.put(hashMapKey, list);
                }
            }
    
    
            return groupedHashMap;
        }
    
    }
    

    myOptions 是用来输入数据的地方。 列表项.java

    public abstract class ListItem {
    
        public static final int TYPE_DATE = 0;
        public static final int TYPE_GENERAL = 1;
    
        abstract public int getType();
    }
    

    GeneralItem.java

    public class GeneralItem extends ListItem {
        private PojoOfJsonArray pojoOfJsonArray;
    
        public PojoOfJsonArray getPojoOfJsonArray() {
            return pojoOfJsonArray;
        }
    
        public void setPojoOfJsonArray(PojoOfJsonArray pojoOfJsonArray) {
            this.pojoOfJsonArray = pojoOfJsonArray;
        }
    
        @Override
        public int getType() {
            return TYPE_GENERAL;
        }
    
    
    }
    

    日期项.java

    public class DateItem extends ListItem {
    
        private String date;
    
        public String getDate() {
            return date;
        }
    
        public void setDate(String date) {
            this.date = date;
        }
    
        @Override
        public int getType() {
            return TYPE_DATE;
        }
    }
    

    Adapter.java 这个适配器适用于 recyclerview 如果您不了解如何制作简单的分段 recyclerview,那么我建议您阅读这些内容并在该领域表现出色,因为这有点棘手无论如何:

    public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
    
        private Context mContext;
        List<ListItem> consolidatedList = new ArrayList<>();
    
        public Adapter(Context context, List<ListItem> consolidatedList) {
            this.consolidatedList = consolidatedList;
            this.mContext = context;
    
    
        }
    
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,  int viewType) {
    
            RecyclerView.ViewHolder viewHolder = null;
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    
            switch (viewType) {
    
                case ListItem.TYPE_GENERAL:
                    View v1 = inflater.inflate(R.layout.items, parent,
                            false);
                    viewHolder = new GeneralViewHolder(v1);
                    break;
    
                case ListItem.TYPE_DATE:
                    View v2 = inflater.inflate(R.layout.itemsh, parent, false);
                    viewHolder = new DateViewHolder(v2);
                    break;
            }
    
            return viewHolder;
        }
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    
            switch (viewHolder.getItemViewType()) {
    
                case ListItem.TYPE_GENERAL:
    
                    GeneralItem generalItem   = (GeneralItem) consolidatedList.get(position);
                    GeneralViewHolder generalViewHolder= (GeneralViewHolder) viewHolder;
                    generalViewHolder.txtTitle.setText(generalItem.getPojoOfJsonArray().getName());
    
                    break;
    
                case ListItem.TYPE_DATE:
                    DateItem dateItem = (DateItem) consolidatedList.get(position);
                    DateViewHolder dateViewHolder = (DateViewHolder) viewHolder;
    
                    dateViewHolder.txtTitle.setText(dateItem.getDate());
                    // Populate date item data here
    
                    break;
            }
        }
    
    
    
    
    
        // ViewHolder for date row item
        class DateViewHolder extends RecyclerView.ViewHolder {
            protected TextView txtTitle;
    
            public DateViewHolder(View v) {
                super(v);
                this.txtTitle = (TextView) v.findViewById(R.id.txt);
    
            }
        }
    
        // View holder for general row item
        class GeneralViewHolder extends RecyclerView.ViewHolder {
            protected TextView txtTitle;
    
            public GeneralViewHolder(View v) {
                super(v);
                this.txtTitle = (TextView) v.findViewById(R.id.txt);
    
            }
        }
    
        @Override
        public int getItemViewType(int position) {
            return consolidatedList.get(position).getType();
        }
    
        @Override
        public int getItemCount() {
            return consolidatedList != null ? consolidatedList.size() : 0;
        }
    
    }
    

    这有两个布局正在使用。因此所有的

    【讨论】:

    • 谢谢哥们......这是我一直在寻找的解决方案......在一个地方提供完整的解决方案......
    • 这个解决方案非常完美!非常感谢。
    • @SharpEdge 试试看,没想到,试着做一个分享一下
    • @kinsleykajiva 我想知道任何特定组的最后一项..有什么办法可以做到这一点?
    • 那个博客是我的;感谢@kinsleykajiva 的认可。一位朋友与我分享了此问题的链接。
    【解决方案2】:

    您可以使用库SectionedRecyclerViewAdapter 轻松将数据分组到各个部分,并为每个部分添加标题。

    首先创建一个Section类:

    class MySection extends StatelessSection {
    
        String title;
        List<String> list;
    
        public MySection(String title, List<String> list) {
            // call constructor with layout resources for this Section header, footer and items 
            super(R.layout.section_header, R.layout.section_item);
    
            this.title = title;
            this.list = list;
        }
    
        @Override
        public int getContentItemsTotal() {
            return list.size(); // number of items of this section
        }
    
        @Override
        public RecyclerView.ViewHolder getItemViewHolder(View view) {
            // return a custom instance of ViewHolder for the items of this section
            return new MyItemViewHolder(view);
        }
    
        @Override
        public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
            MyItemViewHolder itemHolder = (MyItemViewHolder) holder;
    
            // bind your view here
            itemHolder.tvItem.setText(list.get(position));
        }
    
        @Override
        public RecyclerView.ViewHolder getFooterViewHolder(View view) {
            return new MyFooterViewHolder(view);
        }
    
        @Override
        public void onBindFooterViewHolder(RecyclerView.ViewHolder holder) {
            MyFooterViewHolder footerHolder = (MyFooterViewHolder) holder;
    
            // bind your footer view here
            footerHolder.tvItem.setText(title);
        }
    }
    

    然后你用你的部分设置 RecyclerView:

    // Create an instance of SectionedRecyclerViewAdapter 
    SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();
    
    // Create your sections with the list of data for each year
    MySection section1 = new MySection("1 week ago", week1data);
    MySection section2 = new MySection("2 weeks ago", week2data);
    
    // Add your Sections to the adapter
    sectionAdapter.addSection(section1);
    sectionAdapter.addSection(section2);
    
    // Set up your RecyclerView with the SectionedRecyclerViewAdapter
    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
    recyclerView.setAdapter(sectionAdapter);
    

    【讨论】:

      【解决方案3】:

      我只是在这里报告一个 Kotlin 版本的kinsley kajiva 响应。

      注意:这个版本使用了data biding,所以记得在app build.gradle上启用它:

      android {
          ...
          buildFeatures {
              dataBinding true
          }
      }
      

      PojoOfJsonArray.kt

      data class PojoOfJsonArray(
          val name: String,
          val date: String
      )
      

      MainActivity.kt

      class MainActivity : AppCompatActivity() {
      
          private lateinit var binding: ActivityMainBinding
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
      
              binding.list.setHasFixedSize(true)
      
              val myOptions = listOf(
                  PojoOfJsonArray("name 1", "2016-06-21"),
                  PojoOfJsonArray("name 2", "2016-06-05"),
                  PojoOfJsonArray("name 2", "2016-06-05"),
                  PojoOfJsonArray("name 3", "2016-05-17"),
                  PojoOfJsonArray("name 3", "2016-05-17"),
                  PojoOfJsonArray("name 3", "2016-05-17"),
                  PojoOfJsonArray("name 3", "2016-05-17"),
                  PojoOfJsonArray("name 2", "2016-06-05"),
                  PojoOfJsonArray("name 3", "2016-05-17")
              )
      
              val groupedMapMap: Map<String, List<PojoOfJsonArray>> = myOptions.groupBy {
                  it.date
              }
      
              val consolidatedList = mutableListOf<ListItem>()
              for (date:String in groupedMapMap.keys){
                  consolidatedList.add(DateItem(date))
                  val groupItems: List<PojoOfJsonArray>? = groupedMapMap[date]
                  groupItems?.forEach {
                      consolidatedList.add(GeneralItem(it.name))
                  }
              }
      
              val adapter = Adapter(consolidatedList)
              val layoutManager = LinearLayoutManager(this)
              layoutManager.orientation = LinearLayoutManager.VERTICAL
              binding.list.layoutManager = layoutManager
              binding.list.adapter = adapter
          }
      }
      

      activity_main.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"
          xmlns:tools="http://schemas.android.com/tools">
      
          <androidx.constraintlayout.widget.ConstraintLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              tools:context=".MainActivity">
      
              <androidx.recyclerview.widget.RecyclerView
                  android:id="@+id/list"
                  android:layout_width="0dp"
                  android:layout_height="0dp"
                  app:layout_constraintBottom_toBottomOf="parent"
                  app:layout_constraintLeft_toLeftOf="parent"
                  app:layout_constraintRight_toRightOf="parent"
                  app:layout_constraintTop_toTopOf="parent"
                  tools:listitem="@layout/general_item"/>
      
          </androidx.constraintlayout.widget.ConstraintLayout>
      
      </layout>
      

      ListItem.kt

      open class ListItem(
          val type: Int
      ) {
          companion object {
              const val TYPE_DATE = 0
              const val TYPE_GENERAL = 1
          }
      }
      

      GeneralItem.kt

      class GeneralItem(
          var name: String,
      ) : ListItem(TYPE_GENERAL)
      

      DateItem.kt

      class DateItem(
          val date: String
      ) : ListItem(TYPE_DATE)
      

      Adapter.kt

      class Adapter(
          private val items: List<ListItem>,
      ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
      
          override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
              val layoutInflater = LayoutInflater.from(parent.context)
              return when (viewType) {
                  ListItem.TYPE_DATE ->
                      DateViewHolder(DateItemBinding.inflate(layoutInflater))
                  else ->
                      GeneralViewHolder(GeneralItemBinding.inflate(layoutInflater))
              }
          }
      
          override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
              when (holder.itemViewType) {
                  ListItem.TYPE_DATE -> (holder as DateViewHolder).bind(
                      item = items[position] as DateItem,
                  )
                  ListItem.TYPE_GENERAL -> (holder as GeneralViewHolder).bind(
                      item = items[position] as GeneralItem
                  )
              }
          }
      
          override fun getItemViewType(position: Int): Int {
              return items[position].type
          }
      
          override fun getItemCount(): Int {
              return items.size
          }
      
          inner class DateViewHolder(val binding: DateItemBinding) : RecyclerView.ViewHolder(binding.root) {
              fun bind(item: DateItem) {
                  binding.txtDate.text = item.date
              }
          }
      
          inner class GeneralViewHolder(val binding: GeneralItemBinding) : RecyclerView.ViewHolder(binding.root) {
              fun bind(item: GeneralItem) {
                  binding.txtTitle.text = item.name
              }
          }
      
      }
      

      date_item.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"
          xmlns:tools="http://schemas.android.com/tools">
      
          <androidx.constraintlayout.widget.ConstraintLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content">
      
              <TextView
                  android:id="@+id/txt_date"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_margin="8dp"
                  android:textStyle="bold"
                  app:layout_constraintBottom_toBottomOf="parent"
                  app:layout_constraintEnd_toEndOf="parent"
                  app:layout_constraintStart_toStartOf="parent"
                  app:layout_constraintTop_toTopOf="parent"
                  tools:text="01/01/2021"/>
      
          </androidx.constraintlayout.widget.ConstraintLayout>
      
      </layout>
      

      general_item.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"
          xmlns:tools="http://schemas.android.com/tools">
      
          <androidx.constraintlayout.widget.ConstraintLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content">
      
              <TextView
                  android:id="@+id/txt_title"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_margin="8dp"
                  app:layout_constraintBottom_toBottomOf="parent"
                  app:layout_constraintEnd_toEndOf="parent"
                  app:layout_constraintStart_toStartOf="parent"
                  app:layout_constraintTop_toTopOf="parent"
                  tools:text="Name"/>
      
          </androidx.constraintlayout.widget.ConstraintLayout>
      
      </layout>
      

      【讨论】:

        【解决方案4】:

        我在Section RecyclerView library 的帮助下解决了这个问题,并使用这些functions (Gist) 检查日期是否为“今天”、“昨天”等。

        我希望为此构建一个端到端的库。如果您有兴趣,请告诉我,然后我可以构建并开源它。

        下面的示例截图:

        【讨论】:

          猜你喜欢
          • 2016-04-23
          • 2020-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多