如何在 RecyclerView 中设置粘性 headers? (有或没有外部库)
How can I make sticky headers in RecyclerView? (with or without external lib)
我正在使用房间数据库,我有一个 table 从那里我得到了一个 LiveData 列表。
在 table 中有一列日期,我在其中存储当前日期。默认选择当前日期,但用户也可以在向数据库中插入数据时更改日期。
我想以这种方式在 recyclerview 中显示此数据
https://imgur.com/RYegFpG
我想根据 header 月份和年份以及它下面那个月份年份的所有条目来划分此数据。
例如,用户在2019年10月插入数据,我希望这个"October 2019"作为recyclerview中的header,以及它下面这个月的所有条目。就像这样,所有月份的条目都应该以相同的方式显示,因为每个下个月都变成 header 并且那个月的条目在它下面。
我试图通过
来实现这一点
if (!thisDate.equals(dBDate))
{
holder.transMonthWrapper.setVisibility(View.VISIBLE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
thisDate = dBDate;
holder.tvTransMonth.setText(thisDate);
}
else
{
holder.transMonthWrapper.setVisibility(View.GONE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
}
但是此代码中的问题是,当用户从设置中更改月份并将一些条目放入数据库时,那一年的月份条目已经存在于 recyclerview 中。它在 recyclerview 中创建该现有月份的另一个 header。但我希望将这些条目放入现有月份 header,而不是创建该月份的新 header。
在不使用外部库的情况下实现此目标的最佳方法是什么,因为在这种情况下我不想依赖外部库。
我是编程新手。
已更新
在activity
public void getTransactionData()
{
adapter = new TransactionAdapter();
recyclerView.setAdapter(adapter);
incomeExpenseModel = ViewModelProviders.of(AllTransaction.this).get(IncomeExpenseViewModel.class);
incomeExpenseModel.getIncomeExpenseData().observe(this, new Observer<List<IncomeExpense>>() {
@Override
public void onChanged(List<IncomeExpense> incomeExpenses) {
adapter.setIncomeExpenseList(incomeExpenses);
}
});
在回收适配器中
public void onBindViewHolder(@NonNull TransactionViewHolder holder, int position) {
IncomeExpense IEList = incomeExpenseList.get(position);
preferences = context.getSharedPreferences(settingPref, Context.MODE_PRIVATE);
String dateFormat = preferences.getString("Date_Format", "MM.dd.yy");
int lastIndex = incomeExpenseList.size() - 1;
IncomeExpense IELastIndex = incomeExpenseList.get(lastIndex);
String dateFrmDb= IELastIndex.getDate();
DateFormat df=new SimpleDateFormat(dateFormat);
Date d;
try {
d = df.parse(dateFrmDb);
df=new SimpleDateFormat("MMMM yyyy");
if (d != null) {
dBDate = df.format(d);
}
} catch (ParseException e) {
Toast.makeText(context, "Error" +e, Toast.LENGTH_SHORT).show();
}
if (!thisDate.equals(dBDate))
{
holder.transMonthWrapper.setVisibility(View.VISIBLE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
thisDate = dBDate;
holder.tvTransMonth.setText(thisDate);
}
else
{
holder.transMonthWrapper.setVisibility(View.GONE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
}
}
@Override
public int getItemCount() {
return incomeExpenseList.size();
}
public void setIncomeExpenseList(List<IncomeExpense> incomeExpenseList)
{
this.incomeExpenseList = incomeExpenseList;
notifyDataSetChanged();
}
您不需要使用任何第三方库。您可以使用 ExpandableListView
而无需实际使用 "expand and collapse" 来做您需要的完全相同的事情。 See my answer for this post。这里的优点是您可以像处理 ExpandableListView
一样轻松地处理它,而无需自定义代码。您只需向标准 ExpandableListView
适配器添加一行。
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
...
((ExpandableListView) parent).expandGroup(groupPosition);
...
}
您的部分 headers,您可以将其设置为群组视图并将列表项设置为 children。您的数据结构需要在传递给适配器之前进行更新。它需要是分组数据,而不是必须传递给可扩展适配器的普通列表(例如 类 的数组,每个实例包含一个 String
属性 组header 和 IncomeExpense
objects 的 ArrayList
)。并且当你更新数据时,在相应的组中进行更新,而不是整个数据。
父回收者视图
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.PhotoFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:clipToPadding="false"
android:paddingBottom="170dp">
</androidx.recyclerview.widget.RecyclerView>
</FrameLayout>
它的适配器
public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.ViewHolder> {
private static final String TAG = "PhotoAdapter";
private Map<String, List<Photo>> photoMap;
private Context context;
private PhotoCategoryAdapter photoCategoryAdapter;
private List<String> keysList;
public PhotoAdapter(Map<String, List<Photo>> photoMap, Context context, List<String> keysList) {
this.photoMap = photoMap;
this.context = context;
this.keysList = keysList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_photo, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String date = keysList.get(position);
holder.lblTakenDate.setText(date);
List<Photo> photoList = photoMap.get(date);
String size = ("( "+ photoList.size() + " )");
holder.lblCountPhotos.setText(size);
setRecyclerView(holder, context, photoList);
}
@Override
public int getItemCount() {
return photoMap.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.rv_photo_category) RecyclerView recyclerView;
@BindView(R.id.lbl_taken_date_photo) TextView lblTakenDate;
@BindView(R.id.lbl_count_images_photo) TextView lblCountPhotos;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
Recyclerview 内的 Reyclerview
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<TextView
android:id="@+id/lbl_taken_date_photo"
android:textColor="@android:color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:textSize="14dp"
android:hint="23-Aug-2018" />
<TextView
android:id="@+id/lbl_count_images_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_toRightOf="@id/lbl_taken_date_photo"
android:hint="(2)"
android:textSize="12sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_photo_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/lbl_taken_date_photo"
android:layout_marginTop="10dp"
android:background="@color/light_grey" />
</RelativeLayout>
它的适配器
public class PhotoCategoryAdapter extends RecyclerView.Adapter<PhotoCategoryAdapter.ViewHolder> {
private static final String TAG = "PhotoCategoryAdapter";
private List<Photo> photoList;
private Context context;
public PhotoCategoryAdapter(List<Photo> photoList, Context context) {
this.photoList = photoList;
this.context = context;
}
@NonNull
@Override
public PhotoCategoryAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.row_category_photo, parent, false));
}
@Override
public void onBindViewHolder(@NonNull PhotoCategoryAdapter.ViewHolder holder, int position) {
Photo photo = photoList.get(position);
RequestOptions myOptions = new RequestOptions() .format(DecodeFormat.PREFER_ARGB_8888).
fitCenter().override(100, 100).placeholderOf(R.drawable.ic_image);
Glide.with(context)
.applyDefaultRequestOptions(myOptions)
.asBitmap()
.load(photo.getImage())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(holder.imgVImages);
}
@Override
public int getItemCount() {
return photoList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.imgv_images_category_photo)
ImageView imgVImages;
@BindView(R.id.imgv_selected_icon_photo) ImageView imgVSelectedPhoto;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
内部回收视图行
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_margin="5dp"
android:layout_width="80dp"
android:layout_height="80dp">
<ImageView
android:id="@+id/imgv_images_category_photo"
android:scaleType="fitXY"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/imgv_selected_icon_photo"
android:visibility="gone"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_margin="10dp"
android:src="@drawable/ic_select"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
Activity 或将数据发送到适配器的片段
public class PhotoFragment extends Fragment {
@BindView(R.id.rv_photo) RecyclerView recyclerView;
private PhotoAdapter photoAdapter;
private ArrayList<Photo> photoList;
private ArrayList<String> keyList;
private Map<String,List<Photo>> map;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_photo, container, false);
ButterKnife.bind(this, view);
init();
setRecyclerViewAdapter();
new PhotoAsync(getContext()).execute();
return view;
}
private void init(){
map = new HashMap<>();
keyList = new ArrayList<>();
photoList = new ArrayList<>();
}
//set layout manager to recyclerView
private void setRecyclerViewAdapter() {
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
}
//get list of images
@RequiresApi(api = Build.VERSION_CODES.Q)
private List<Photo> getAllImages(){
Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = {MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_TAKEN};
Cursor c = null;
ArrayList<Photo> photoList = new ArrayList<>();
if (u != null) {
c = getContext().getContentResolver().query(u, projection, null, null, null); }
if ((c != null) && (c.moveToFirst())) {
do {
Photo photo = new Photo();
String path = c.getString(c.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATA));
String takenDate = c.getString(c.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_TAKEN));
long millisecond = Long.parseLong(takenDate);
String date = DateFormat.format("dd-MMM-yyyy", new Date(millisecond)).toString();
try{
photo.setImage(path);
photo.setDate(date);
photoList.add(photo);
}
catch(Exception e)
{ }
}
while (c.moveToNext());
}
//reverse photoList
Collections.reverse(photoList);
return photoList;
}
public class PhotoAsync extends AsyncTask<Void, Void, Void> {
private Context context;
public PhotoAsync(Context context) {
this.context = context;
}
@RequiresApi(api = Build.VERSION_CODES.Q)
@Override
protected Void doInBackground(Void... params) {
getPhotoList();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
photoAdapter = new PhotoAdapter(map, context, keyList);
recyclerView.setAdapter(photoAdapter);
photoAdapter.notifyDataSetChanged();
}
@Override
protected void onPreExecute() {
}
}
@RequiresApi(api = Build.VERSION_CODES.Q)
private void getPhotoList(){
photoList.addAll(getAllImages());
for (Photo string : photoList) {
if (!keyList.contains(string.getDate()))
keyList.add(string.getDate());
else;
}
for (String s : keyList){
ArrayList<Photo> photos = new ArrayList<>();
for (Photo s1 : photoList) {
if (s1.getDate().equals(s))
photos.add(s1);
else;
}
map.put(s, photos);
}
}
}
Here is the logic which you have to apply
1. Find all the common dates from the data list
for example you data list is :
List<Model> dataList = new ArrayList<>();
dataList.add(new Model("23/10/19"));
dataList.add(new Model("23/10/19"));
dataList.add(new Model("23/09/19"));
dataList.add(new Model("23/10/19"));
dataList.add(new Model("27/09/19"));
dataList.add(new Model("23/10/19"));
List<String> commonList = new ArrayList<>();
for(Model m : dataList){
if(!commonList.contains(model.getDate()))
commonList.add(m.getDate());
else
Log.d("Dates", commonList);
}
Above function will help in getting all common dates
//Here map store date with data which has common date
Map<String, List<Model>> map = new HashMap<>();
List<Model> objectsofCommonDate = new ArrayList();
for(String date: commonList){
objectsofCommonDate.clear();
for(Model model : dataList){
if(model.getData.contains(date))
objectsofCommonDate.add(model);
else
\do nothing
}
map.put(data, objectsOfCommonDate);
}
and pass map to main recyclerview adapter along with commonDateList;
- 首先在你的 setIncomeExpenseList 函数中清除你之前的列表。
- 然后重新分配包含来自数据库的完整数据的新列表。
将 notifyDataSetChanged() 更改为 notify() 或 notifyAll()。
public void setIncomeExpenseList(List<IncomeExpense> incomeExpenseList)
{
this.incomeExpenceList.clear();
this.incomeExpenseList = incomeExpenseList;
notify();
}
我正在使用房间数据库,我有一个 table 从那里我得到了一个 LiveData 列表。 在 table 中有一列日期,我在其中存储当前日期。默认选择当前日期,但用户也可以在向数据库中插入数据时更改日期。
我想以这种方式在 recyclerview 中显示此数据
我想根据 header 月份和年份以及它下面那个月份年份的所有条目来划分此数据。
例如,用户在2019年10月插入数据,我希望这个"October 2019"作为recyclerview中的header,以及它下面这个月的所有条目。就像这样,所有月份的条目都应该以相同的方式显示,因为每个下个月都变成 header 并且那个月的条目在它下面。
我试图通过
来实现这一点if (!thisDate.equals(dBDate))
{
holder.transMonthWrapper.setVisibility(View.VISIBLE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
thisDate = dBDate;
holder.tvTransMonth.setText(thisDate);
}
else
{
holder.transMonthWrapper.setVisibility(View.GONE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
}
但是此代码中的问题是,当用户从设置中更改月份并将一些条目放入数据库时,那一年的月份条目已经存在于 recyclerview 中。它在 recyclerview 中创建该现有月份的另一个 header。但我希望将这些条目放入现有月份 header,而不是创建该月份的新 header。
在不使用外部库的情况下实现此目标的最佳方法是什么,因为在这种情况下我不想依赖外部库。
我是编程新手。
已更新
在activity
public void getTransactionData()
{
adapter = new TransactionAdapter();
recyclerView.setAdapter(adapter);
incomeExpenseModel = ViewModelProviders.of(AllTransaction.this).get(IncomeExpenseViewModel.class);
incomeExpenseModel.getIncomeExpenseData().observe(this, new Observer<List<IncomeExpense>>() {
@Override
public void onChanged(List<IncomeExpense> incomeExpenses) {
adapter.setIncomeExpenseList(incomeExpenses);
}
});
在回收适配器中
public void onBindViewHolder(@NonNull TransactionViewHolder holder, int position) {
IncomeExpense IEList = incomeExpenseList.get(position);
preferences = context.getSharedPreferences(settingPref, Context.MODE_PRIVATE);
String dateFormat = preferences.getString("Date_Format", "MM.dd.yy");
int lastIndex = incomeExpenseList.size() - 1;
IncomeExpense IELastIndex = incomeExpenseList.get(lastIndex);
String dateFrmDb= IELastIndex.getDate();
DateFormat df=new SimpleDateFormat(dateFormat);
Date d;
try {
d = df.parse(dateFrmDb);
df=new SimpleDateFormat("MMMM yyyy");
if (d != null) {
dBDate = df.format(d);
}
} catch (ParseException e) {
Toast.makeText(context, "Error" +e, Toast.LENGTH_SHORT).show();
}
if (!thisDate.equals(dBDate))
{
holder.transMonthWrapper.setVisibility(View.VISIBLE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
thisDate = dBDate;
holder.tvTransMonth.setText(thisDate);
}
else
{
holder.transMonthWrapper.setVisibility(View.GONE);
if (IEList.getType().equalsIgnoreCase("income"))
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.GREEN);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.GREEN);
}
else
{
String amount = ""+IEList.getAmount();
holder.tvTransAmount.setText(amount);
holder.tvTransAmount.setTextColor(Color.RED);
holder.tvTransCategory.setText(IEList.getCategory());
holder.tvTransCategory.setTextColor(Color.RED);
}
}
}
@Override
public int getItemCount() {
return incomeExpenseList.size();
}
public void setIncomeExpenseList(List<IncomeExpense> incomeExpenseList)
{
this.incomeExpenseList = incomeExpenseList;
notifyDataSetChanged();
}
您不需要使用任何第三方库。您可以使用 ExpandableListView
而无需实际使用 "expand and collapse" 来做您需要的完全相同的事情。 See my answer for this post。这里的优点是您可以像处理 ExpandableListView
一样轻松地处理它,而无需自定义代码。您只需向标准 ExpandableListView
适配器添加一行。
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
...
((ExpandableListView) parent).expandGroup(groupPosition);
...
}
您的部分 headers,您可以将其设置为群组视图并将列表项设置为 children。您的数据结构需要在传递给适配器之前进行更新。它需要是分组数据,而不是必须传递给可扩展适配器的普通列表(例如 类 的数组,每个实例包含一个 String
属性 组header 和 IncomeExpense
objects 的 ArrayList
)。并且当你更新数据时,在相应的组中进行更新,而不是整个数据。
父回收者视图
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.PhotoFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:clipToPadding="false"
android:paddingBottom="170dp">
</androidx.recyclerview.widget.RecyclerView>
</FrameLayout>
它的适配器
public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.ViewHolder> {
private static final String TAG = "PhotoAdapter";
private Map<String, List<Photo>> photoMap;
private Context context;
private PhotoCategoryAdapter photoCategoryAdapter;
private List<String> keysList;
public PhotoAdapter(Map<String, List<Photo>> photoMap, Context context, List<String> keysList) {
this.photoMap = photoMap;
this.context = context;
this.keysList = keysList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_photo, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String date = keysList.get(position);
holder.lblTakenDate.setText(date);
List<Photo> photoList = photoMap.get(date);
String size = ("( "+ photoList.size() + " )");
holder.lblCountPhotos.setText(size);
setRecyclerView(holder, context, photoList);
}
@Override
public int getItemCount() {
return photoMap.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.rv_photo_category) RecyclerView recyclerView;
@BindView(R.id.lbl_taken_date_photo) TextView lblTakenDate;
@BindView(R.id.lbl_count_images_photo) TextView lblCountPhotos;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
Recyclerview 内的 Reyclerview
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<TextView
android:id="@+id/lbl_taken_date_photo"
android:textColor="@android:color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:textSize="14dp"
android:hint="23-Aug-2018" />
<TextView
android:id="@+id/lbl_count_images_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_toRightOf="@id/lbl_taken_date_photo"
android:hint="(2)"
android:textSize="12sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_photo_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/lbl_taken_date_photo"
android:layout_marginTop="10dp"
android:background="@color/light_grey" />
</RelativeLayout>
它的适配器
public class PhotoCategoryAdapter extends RecyclerView.Adapter<PhotoCategoryAdapter.ViewHolder> {
private static final String TAG = "PhotoCategoryAdapter";
private List<Photo> photoList;
private Context context;
public PhotoCategoryAdapter(List<Photo> photoList, Context context) {
this.photoList = photoList;
this.context = context;
}
@NonNull
@Override
public PhotoCategoryAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.row_category_photo, parent, false));
}
@Override
public void onBindViewHolder(@NonNull PhotoCategoryAdapter.ViewHolder holder, int position) {
Photo photo = photoList.get(position);
RequestOptions myOptions = new RequestOptions() .format(DecodeFormat.PREFER_ARGB_8888).
fitCenter().override(100, 100).placeholderOf(R.drawable.ic_image);
Glide.with(context)
.applyDefaultRequestOptions(myOptions)
.asBitmap()
.load(photo.getImage())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(holder.imgVImages);
}
@Override
public int getItemCount() {
return photoList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.imgv_images_category_photo)
ImageView imgVImages;
@BindView(R.id.imgv_selected_icon_photo) ImageView imgVSelectedPhoto;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
内部回收视图行
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_margin="5dp"
android:layout_width="80dp"
android:layout_height="80dp">
<ImageView
android:id="@+id/imgv_images_category_photo"
android:scaleType="fitXY"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/imgv_selected_icon_photo"
android:visibility="gone"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_margin="10dp"
android:src="@drawable/ic_select"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
Activity 或将数据发送到适配器的片段
public class PhotoFragment extends Fragment {
@BindView(R.id.rv_photo) RecyclerView recyclerView;
private PhotoAdapter photoAdapter;
private ArrayList<Photo> photoList;
private ArrayList<String> keyList;
private Map<String,List<Photo>> map;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_photo, container, false);
ButterKnife.bind(this, view);
init();
setRecyclerViewAdapter();
new PhotoAsync(getContext()).execute();
return view;
}
private void init(){
map = new HashMap<>();
keyList = new ArrayList<>();
photoList = new ArrayList<>();
}
//set layout manager to recyclerView
private void setRecyclerViewAdapter() {
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
}
//get list of images
@RequiresApi(api = Build.VERSION_CODES.Q)
private List<Photo> getAllImages(){
Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = {MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_TAKEN};
Cursor c = null;
ArrayList<Photo> photoList = new ArrayList<>();
if (u != null) {
c = getContext().getContentResolver().query(u, projection, null, null, null); }
if ((c != null) && (c.moveToFirst())) {
do {
Photo photo = new Photo();
String path = c.getString(c.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATA));
String takenDate = c.getString(c.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_TAKEN));
long millisecond = Long.parseLong(takenDate);
String date = DateFormat.format("dd-MMM-yyyy", new Date(millisecond)).toString();
try{
photo.setImage(path);
photo.setDate(date);
photoList.add(photo);
}
catch(Exception e)
{ }
}
while (c.moveToNext());
}
//reverse photoList
Collections.reverse(photoList);
return photoList;
}
public class PhotoAsync extends AsyncTask<Void, Void, Void> {
private Context context;
public PhotoAsync(Context context) {
this.context = context;
}
@RequiresApi(api = Build.VERSION_CODES.Q)
@Override
protected Void doInBackground(Void... params) {
getPhotoList();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
photoAdapter = new PhotoAdapter(map, context, keyList);
recyclerView.setAdapter(photoAdapter);
photoAdapter.notifyDataSetChanged();
}
@Override
protected void onPreExecute() {
}
}
@RequiresApi(api = Build.VERSION_CODES.Q)
private void getPhotoList(){
photoList.addAll(getAllImages());
for (Photo string : photoList) {
if (!keyList.contains(string.getDate()))
keyList.add(string.getDate());
else;
}
for (String s : keyList){
ArrayList<Photo> photos = new ArrayList<>();
for (Photo s1 : photoList) {
if (s1.getDate().equals(s))
photos.add(s1);
else;
}
map.put(s, photos);
}
}
}
Here is the logic which you have to apply
1. Find all the common dates from the data list
for example you data list is :
List<Model> dataList = new ArrayList<>();
dataList.add(new Model("23/10/19"));
dataList.add(new Model("23/10/19"));
dataList.add(new Model("23/09/19"));
dataList.add(new Model("23/10/19"));
dataList.add(new Model("27/09/19"));
dataList.add(new Model("23/10/19"));
List<String> commonList = new ArrayList<>();
for(Model m : dataList){
if(!commonList.contains(model.getDate()))
commonList.add(m.getDate());
else
Log.d("Dates", commonList);
}
Above function will help in getting all common dates
//Here map store date with data which has common date
Map<String, List<Model>> map = new HashMap<>();
List<Model> objectsofCommonDate = new ArrayList();
for(String date: commonList){
objectsofCommonDate.clear();
for(Model model : dataList){
if(model.getData.contains(date))
objectsofCommonDate.add(model);
else
\do nothing
}
map.put(data, objectsOfCommonDate);
}
and pass map to main recyclerview adapter along with commonDateList;
- 首先在你的 setIncomeExpenseList 函数中清除你之前的列表。
- 然后重新分配包含来自数据库的完整数据的新列表。
将 notifyDataSetChanged() 更改为 notify() 或 notifyAll()。
public void setIncomeExpenseList(List<IncomeExpense> incomeExpenseList) { this.incomeExpenceList.clear(); this.incomeExpenseList = incomeExpenseList; notify(); }