Android

Divide elements on groups in RecyclerView or Grouping Recyclerview items ,say by date

Разделите элементы на группы в RecyclerView или сгруппируйте элементы Recyclerview, скажем, по дате

я хочу сгруппировать мой Android RecyclerView элементы с заголовком, созданным на основе даты, вот так:

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

что-то в этом роде или группировать на основе какого-то элемента.

Переведено автоматически
Ответ 1

Вот решение, к которому я пришел с помощью большого количества исследований в сети, а также ссылки на этот блог Kartikey Kuswhaha так что это не вся моя заслуга, но я просто хочу внести в него больше ясности. ниже приведен код: создайте следующие файлы:PojoOfJsonArray,MainActivity, ListItem ,GeneralItem ,DateItem , Adapter

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 - это то место, куда можно было бы вводить ваши данные.
ListItem.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;
}


}

DateItem.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;
}
}

Адаптер.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;
}

}

и здесь используются два макета . таким образом, все

Ответ 2

Я просто сообщаю здесь об ответах Kotlin версии кинсли кадживы.

Примечание: В этой версии используется ожидание данных, поэтому не забудьте включить его в 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>

Конечный результат

Ответ 3

Вы можете использовать библиотеку 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);
Ответ 4

Я решил эту проблему с помощью раздела RecyclerView library и используя эти функции (Gist), чтобы проверить, является ли дата "Сегодня", "Вчера" и так далее.

Я надеюсь создать для этого сквозную библиотеку. Дайте мне знать, если вам интересно, тогда я смогу создать ее с открытым исходным кодом.

Пример скриншота ниже:

Скриншот пользовательского интерфейса, показывающий разделы с датой

2024-01-08 14:48 java android android-recyclerview