我有一個帶有專案串列的回收站視圖,每個專案都附有復選框。當一個復選框被選中時,它的行為是正確的,并且不需要的專案被選中是沒有問題的。但是當一個選中的專案被洗掉時,不需要的專案就會被選中。
我的配接器類:
public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskHolder> {
private static List<Task> tasks = new ArrayList<>();
private static OnItemClickListener listener;
private static TaskAdapter adapter = new TaskAdapter();
@NonNull
@Override
public TaskHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.task_item, parent, false);
return new TaskHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull TaskHolder holder, int position) {
Task currentTask = tasks.get(position);
holder.a_tname.setText(currentTask.getTname());
holder.a_tdate.setText(currentTask.getTDate());
holder.a_ttime.setText(currentTask.getTTime());
holder.a_tprior.setText(currentTask.getTprior());
holder.bind(tasks.get(position));
holder.bind2(tasks.get(position));
}
@Override
public int getItemCount() {
return tasks.size();
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
Collections.sort( tasks, Task.comparepriority);
notifyDataSetChanged();
}
public Task getTaskAt(int position){
return tasks.get(position);
}
class TaskHolder extends RecyclerView.ViewHolder {
private final TextView a_tname;
private final TextView a_tdate;
private final TextView a_ttime;
private final TextView a_tprior;
ImageView priorityIndicator;
CheckBox checkbox;
public TaskHolder(View itemView) {
super(itemView);
a_tname = itemView.findViewById(R.id.a_tname);
a_tdate=itemView.findViewById(R.id.a_tdate);
a_ttime = itemView.findViewById(R.id.a_ttime);
a_tprior = itemView.findViewById(R.id.a_tprior);
priorityIndicator = itemView.findViewById(R.id.priorityIndicator);
checkbox = itemView.findViewById(R.id.checkbox);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if(listener!=null&&position!=RecyclerView.NO_POSITION){
listener.onItemClick(tasks.get(position));
}
}
});
}
private void bind(Task task){
int drawableId;int red = R.color.red;int yellow = R.color.yellow;int green = R.color.green;
int color1 = ContextCompat.getColor(a_tprior.getContext(), red);
int color2 = ContextCompat.getColor(a_tprior.getContext(),yellow);
int color3 = ContextCompat.getColor(a_tprior.getContext(),green);
switch(task.t_prior){
case "1": drawableId = R.drawable.ic_baseline_priority_high_24;
a_tprior.setTextColor(color1);
break;
case "2": drawableId = R.drawable.ic_baseline_priority_middle_24;
a_tprior.setTextColor(color2);
break;
case "3" : drawableId = R.drawable.ic_baseline_low_priority_24;
a_tprior.setTextColor(color3);
break;
default: drawableId = R.drawable.ic_baseline_crop_square_24;
}
priorityIndicator.setImageDrawable(ContextCompat.getDrawable(priorityIndicator.getContext(),drawableId));
}
public void bind2(Task task){
final boolean[] checked = {true};
checkbox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(checkbox.isChecked()) {
String pos = Integer.valueOf(getAdapterPosition()).toString();
PreferenceManager.getDefaultSharedPreferences(checkbox.getContext()).edit().
putBoolean("checkbox" pos , checked[0]).apply();
Toast.makeText(checkbox.getContext(), "Way to go! Now swipe to delete", Toast.LENGTH_LONG).show();
}
else {
checked[0] =false;
String pos = Integer.valueOf(getAdapterPosition()).toString();
PreferenceManager.getDefaultSharedPreferences(checkbox.getContext()).edit().
putBoolean("checkbox" pos, checked[0]).apply();
}
}
}); String pos = Integer.valueOf(getAdapterPosition()).toString();
boolean cb = PreferenceManager.getDefaultSharedPreferences(checkbox.getContext()).getBoolean
("checkbox" pos, false);
checkbox.setChecked(cb);
}
}
public interface OnItemClickListener {
void onItemClick(Task ta);
}
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
}

我要在 HomeFragment.java 中洗掉的代碼 -
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull
RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
new AlertDialog.Builder(getActivity())
.setMessage("Do you want to delete this task?")
.setPositiveButton("Delete", ((dialog, which) ->
taskViewmodel.delete(adapter.getTaskAt(viewHolder.getAdapterPosition()))))
.setNegativeButton("Cancel", ((dialog, which) -> adapter.notifyItemChanged(position)))
.setOnCancelListener(dialog -> adapter.notifyItemChanged(position))
.create().show();
}
}).attachToRecyclerView(recyclerView);
編輯:我猜問題出在與保存復選框狀態相關的代碼上,因為選中了特定專案位置的復選框,因此當洗掉專案時,下面的專案會取代它的位置,因此它會被選中。假設檢查了第 2 個位置的專案,然后我洗掉了該專案,然后第 3 個位置的專案取而代之,這樣就被檢查了。我需要知道如何解決這個問題。我可以知道我應該做哪些更改來糾正這個問題?謝謝
uj5u.com熱心網友回復:
回到那天,沒有洗掉直覺,現在因為你使用它的位置在 SharedPreferences 中存盤一個專案是否被選中的狀態,如果你有 3 個專案的位置 =2 被選中,并且你洗掉這個選中的專案在 pos=2 時,第三個專案將在 pos=2 處作為新專案取而代之,這就是為什么當您洗掉一個時,所有選中的狀態都會發生變化。
我想這里別無選擇,只能在您的 Task 類中使用一些識別符號,其中一個 Task 使用此數字/字串唯一標識,并且您使用該唯一識別符號將專案狀態存盤在 SharedPreferences 中作為鍵。
一種快速且廉價的方法是使 Task 類的行為類似于 Room 資料庫識別其自動唯一 int/long 識別符號的方式。
這樣做的方法是
在您的 Task 類中定義一個靜態 int/long 計數器欄位,用于標識您到目前為止使用了多少個 id,以免重復之前使用的任何 id(即使它已被洗掉且現在未使用)
在 Task 類中定義一個私有 int/long id 欄位,而在 Task 類建構式中,當您初始化一個新任務時,您將增加靜態計數器欄位并將此新值用作新創建的私有 id 的值任務。注意:如果您為其創建物件的物件是從已有舊 ID 的 SharedPreferences/Database 中檢索的舊任務,則不應增加靜態值并為每個創建的任務分配新 ID,在這種情況下您可能有兩個建構式,一個接受舊 id 作為引數,另一個增加 taskCounter 并獲得新 id,您可能還有兩個建構式,一個呼叫另一個,以防萬一您有其他一些引數傳遞給任務物件在創建時,您希望避免在兩個建構式中重復代碼。
這樣,當您使用 SharedPreferences 檢查某些任務的狀態時,您將使用 Task 的私有 id 值而不是它的位置。
您的 Task 類可能如下所示(如果有兩個建構式,但建構式中沒有任何附加代碼):
public class Task {
public static int tasksCounter =0;
public int taskId ;
...
//constructor for a new Task
public Task(){
this.taskId= tasksCounter ;
}
//constructor for an old Task
public Task(int oldId){
this.taskId= oldId ;
}
您的 Task 類可能如下所示(如果有兩個建構式并且您想避免代碼重復):
public class Task {
public static int tasksCounter =0;
public int taskId ;
//you'd call that one if you're creating a completely new Task and it will call
the other constructor for you
public Task(){
Task( tasksCounter)
}
//you'd call that one if you're creating a Task that you already have an id for
public Task(int id){
this.taskId= id ;
//some other code here
}
在你的配接器中,當你詢問它是否被檢查時,它會是這樣的:
PreferenceManager.getDefaultSharedPreferences(checkbox.getContext()).getBoolean
("checkbox" task.taskId, false);
并且當您更改復選框狀態時,您將同樣使用task.taskId代替位置更改其在首選項中的值。
這當然會引發另一個問題,即每次啟動應用程式時,靜態欄位都會再次重置為 0。
所以你也應該將它的值存盤在 sharedpreferences 中
- when you create a new Task, its value will be incremented so you should store the new value
or - just before the activity or fragment getting destroyed by overriding the method
onDestroy()in either the activity or the fragment, you should store the last value it had and when you start your activity or fragment you need to fetch it from sharedpreferences and assign it toTask.tasksCounter.
N.B : just incase you don't know, you get the value of static field by calling the class it self and you don't need to create a new object of this class to get its value, calling the next code is sufficent to get and edit its value :
Task.tasksCounter
最后,
由于您現在擁有復雜的資料(任務類),我強烈建議您停止使用 SharedPreferences 來存盤所有內容,然后開始閱讀并切換到Room Database
Room Database為您提供資料庫的必要存盤能力,包括:
- 有一個自動增量識別符號而不必擔心它們的值
- 只用一行代碼和一個簡單的查詢來存盤和獲取你的資料,而不是用鍵 a 呼叫 get 100 次。
將您的 Task 類更改為具有自動增量欄位的物體,您就可以開始使用 Room 來存盤您的任務了。
uj5u.com熱心網友回復:
我對 lambda 函式不太熟悉,所以我分享了我將如何完成相同的任務。我為我自己的應用程式嘗試了這段代碼,它運行得非常好。檢查以下代碼:
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAbsoluteAdapterPosition();//getAdapterPosition is depreciated, use getAbsoluteAdapterPosition
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMessage("Do you want to delete this task?");
builder.setPositiveButton("Delete",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
taskViewmodel.delete(adapter.getTaskAt(viewHolder.getAdapterPosition()))
adapter.notifyItemRemoved(position);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
adapter.notifyItemChanged(position);
}
}).show();
}
}).attachToRecyclerView(recyclerView);
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/334740.html
標籤:安卓 复选框 android-recyclerview 安卓适配器
