从 RecyclerView 中删除消息
Delete a message from the RecyclerView
我有一个发送消息的应用程序。
我想实现删除消息的功能。如果您长时间单击该消息,将出现一个标记的复选框。接下来,用户可以select他想删除的所有消息,然后点击垃圾桶图标。
消息是使用 RecyclerView 实现的。使用 LiveData 和 Room。
这是 ListAdapter 的样子:
package com.mardaunt.telesupp.recyclerview;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import com.mardaunt.telesupp.R;
import com.mardaunt.telesupp.room.Message;
import com.mardaunt.telesupp.room.TimeStampConverter;
public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {
public MessageListAdapter(@NonNull DiffUtil.ItemCallback<Message> diffCallback) {
super(diffCallback);
}
@Override
public int getItemViewType(int position) {
if (getItem(position).getNature().equals("outgoing"))
return R.layout.recyclerview_item_outgoing;
else
return R.layout.recyclerview_item_incoming;
}
@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return MessageViewHolder.create(parent, viewType);
}
@Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
Message current = getItem(position);
holder.bind(current.getPhone(),
current.getText(),
TimeStampConverter.getTime(current.getDate())); // Бинтим телефон сообщение и время.
}
public static class MessageDiff extends DiffUtil.ItemCallback<Message> {
@Override
public boolean areItemsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem == newItem;
}
@Override
public boolean areContentsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem.getText().equals(newItem.getText());
}
}
}
这是 ViewHolder 的样子:
package com.mardaunt.telesupp.recyclerview;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.mardaunt.telesupp.R;
class MessageViewHolder extends RecyclerView.ViewHolder {
private final TextView phoneItemView;
private final TextView messageItemView;
private final TextView timeItemView;
private MessageViewHolder(View itemView) {
super(itemView);
messageItemView = itemView.findViewById(R.id.text_view_message);
phoneItemView = itemView.findViewById(R.id.text_view_phone);
timeItemView = itemView.findViewById(R.id.text_view_time);
}
public void bind(String phone, String message, String time) {
phoneItemView.setText(phone);
messageItemView.setText(message);
timeItemView.setText(time);
}
//viewType содержит id для нужного layout.
static MessageViewHolder create(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(viewType, parent, false);
return new MessageViewHolder(view);
}
}
请告诉我如何正确启动此任务?如果我没看错的话,我需要在MessageListAdapter class.
中设置一个长按消息的监听器
MainActivity GitHub。
应用程序的工作原型 (apk file)。
你可能想要一个类似 MessageView
的中间对象
//this will allow each message to be selected individually.
//the adapter should display MessageViews instead of Messages directly.
public class MessageView{
private Message message;
private boolean isSelected;
//constructor and getters and setters;
}
//set your view holder like this
class MessageViewHolder extends RecyclerView.ViewHolder {
private final TextView phoneItemView;
private final TextView messageItemView;
private final TextView timeItemView;
private final Checkbox checkBoxView;
private MessageViewHolder(View itemView) {
super(itemView);
messageItemView = itemView.findViewById(R.id.text_view_message);
phoneItemView = itemView.findViewById(R.id.text_view_phone);
timeItemView = itemView.findViewById(R.id.text_view_time);
checkBoxView= itemView.findViewById(R.id.check_box_view);
checkboxView.setOnCheckedChangeListener((checkbox,checked)=>{
messageList.get(getAdapterPosition()).isSelected(checked);
});
}
public void bind(MessageView messageView) {
phoneItemView.setText(messageView.getMessage().getPhone());
messageItemView.setText(messageView.getMessage().getMessage());
timeItemView.setText(TimeStampConverter.getTime(messageView.getMessage().getDate()));
checkBoxView.setChecked(messageView.isSelected());
}
}
//call this on the select all check box in your activity/fragment
public void onSelectAll(boolean selected){
for(MessageView view : messageList)
view.isSelected(selected);
adapter.notifyDataSetChanged();
}
//call this on the delete all button click in your activity/fragment
public void onDeleteSelected(){
Iterator i = messageList.iterator();
MessageView messageView;
while (i.hasNext()) {
messageView = (MessageView ) i.next();
if (messageView.isSelected())
i.remove();
}
adapter.notifyDataSetChanged();
}
我已经考虑了一段时间可以做什么。
因此,我决定尝试为 RecyclerView 中的每个元素添加复选框,并在 ListAdapter class.
中设置侦听器
public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {
HelperAdapter helperAdapter;
public MessageListAdapter(@NonNull DiffUtil.ItemCallback<Message> diffCallback, HelperAdapter helperAdapter) {
super(diffCallback);
this.helperAdapter = helperAdapter;
}
@Override
public int getItemViewType(int position) {
if (getItem(position).getNature().equals("outgoing"))
return R.layout.recyclerview_item_outgoing;
else
return R.layout.recyclerview_item_incoming;
}
@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return MessageViewHolder.create(parent, viewType);
}
@Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
Message current = getItem(position);
holder.bind(current.getPhone(),
current.getText(),
TimeStampConverter.getTime(current.getDate())); // Бинтим телефон сообщение и время
// Добавим все view CheckBox в list чтобы скрывать и показывать их по мере необходимости
helperAdapter.addCheckBox(holder.getMessageCheckBox());
// Установим слушатель короткого нажатия по сообщению.
holder.getMessageBox().setOnClickListener(v -> {
EditText editPhone = helperAdapter.getMainActivity()
.findViewById(R.id.edit_phone);
editPhone.setText(current.getPhone());
});
// Установим слушатель долгого нажатия по сообщению.
holder.getMessageBox().setOnLongClickListener(v -> {
helperAdapter.getMainActivity()
.findViewById(R.id.trash_button)
.setVisibility(View.VISIBLE);
helperAdapter.getMainActivity()
.findViewById(R.id.close_button)
.setVisibility(View.VISIBLE);
for (CheckBox checkBox: helperAdapter.getSetCheckBox())
checkBox.setVisibility(View.VISIBLE);
return false;
});
// Установим слушатели для чекбоксов, которые переключают переменную isSelected
holder.getMessageCheckBox().setOnClickListener(v -> {
current.isSelected = ((CheckBox) v).isChecked();
helperAdapter.addCheckBox((CheckBox) v);
});
}
public static class MessageDiff extends DiffUtil.ItemCallback<Message> {
@Override
public boolean areItemsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem == newItem;
}
@Override
public boolean areContentsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem.getText().equals(newItem.getText());
}
}
}
我还创建了一个辅助 class HelperAdapter 来通过它删除标记的消息。
public class HelperAdapter {
private static HelperAdapter helperAdapter;
private MessageViewModel mMessageViewModel;
private MainActivity mainActivity;
private final HashSet<CheckBox> listCheckBox = new HashSet<>();
public void deleteSelected() {
LiveData<List<Message>> temp = mMessageViewModel.getAllMessages();
List<Message> allMessages = temp.getValue();
if (allMessages != null)
for(Message message: allMessages)
if(message.isSelected)
mMessageViewModel.delete(message);
// Скроем иконку корзины и чекбоксы
mainActivity.findViewById(R.id.trash_button).setVisibility(View.GONE);
mainActivity.findViewById(R.id.close_button).setVisibility(View.GONE);
for (CheckBox checkBox: listCheckBox)
checkBox.setVisibility(View.GONE);
}
public void setMessageViewModel(MessageViewModel messageViewModel){
mMessageViewModel = messageViewModel;
}
public MessageViewModel getMessageViewModel() { return mMessageViewModel; }
public HashSet<CheckBox> getSetCheckBox() {return listCheckBox;}
public void addCheckBox(CheckBox checkBox) {
listCheckBox.add(checkBox);
}
public void removeCheckBox(CheckBox checkBox){
listCheckBox.remove(checkBox);
}
public int sizeCheckBox() {return listCheckBox.size();}
public static HelperAdapter getHelperAdapter(){
if (helperAdapter == null) helperAdapter = new HelperAdapter();
return helperAdapter;
}
public void setMainActivity(MainActivity mainActivity){
this.mainActivity = mainActivity;
}
public MainActivity getMainActivity() { return mainActivity; }
}
我还为消息添加了一个布尔变量 class:
@Entity(tableName = "messages_table")
public class Message {
@PrimaryKey(autoGenerate = true)
private int id;
private String phone;
private String text;
private String nature;
private String service;
private Date date;
@Ignore
public boolean isSelected; // I added it
public Message(int id,
@NonNull String phone,
@NonNull String text,
@NonNull String nature,
@NonNull String service,
@NonNull Date date
) {
this.id = id;
this.phone = phone;
this.text = text;
this.nature = nature;
this.service = service;
this.date = date;
}
public int getId(){return this.id;}
public String getPhone(){return this.phone;}
public String getText(){return this.text;}
public String getNature(){return this.nature;}
public String getService(){return this.service;}
public Date getDate(){return this.date;}
}
现在我可以为垃圾桶图标设置监听器了:
// ОнКлик для иконки корзины
public void deleteMessage(View view){
helperAdapter.deleteSelected();
}
感谢 LiveData,我不必考虑更新 RecyclerView。 LiveData 删除已删除的消息。
这工作或多或少稳定,但我感觉我搞砸了体系结构并选择了错误的方法。
测试 apk 文件:https://dropmefiles.com/UxPPx
我有一个发送消息的应用程序。
我想实现删除消息的功能。如果您长时间单击该消息,将出现一个标记的复选框。接下来,用户可以select他想删除的所有消息,然后点击垃圾桶图标。
消息是使用 RecyclerView 实现的。使用 LiveData 和 Room。
这是 ListAdapter 的样子:
package com.mardaunt.telesupp.recyclerview;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import com.mardaunt.telesupp.R;
import com.mardaunt.telesupp.room.Message;
import com.mardaunt.telesupp.room.TimeStampConverter;
public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {
public MessageListAdapter(@NonNull DiffUtil.ItemCallback<Message> diffCallback) {
super(diffCallback);
}
@Override
public int getItemViewType(int position) {
if (getItem(position).getNature().equals("outgoing"))
return R.layout.recyclerview_item_outgoing;
else
return R.layout.recyclerview_item_incoming;
}
@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return MessageViewHolder.create(parent, viewType);
}
@Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
Message current = getItem(position);
holder.bind(current.getPhone(),
current.getText(),
TimeStampConverter.getTime(current.getDate())); // Бинтим телефон сообщение и время.
}
public static class MessageDiff extends DiffUtil.ItemCallback<Message> {
@Override
public boolean areItemsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem == newItem;
}
@Override
public boolean areContentsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem.getText().equals(newItem.getText());
}
}
}
这是 ViewHolder 的样子:
package com.mardaunt.telesupp.recyclerview;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.mardaunt.telesupp.R;
class MessageViewHolder extends RecyclerView.ViewHolder {
private final TextView phoneItemView;
private final TextView messageItemView;
private final TextView timeItemView;
private MessageViewHolder(View itemView) {
super(itemView);
messageItemView = itemView.findViewById(R.id.text_view_message);
phoneItemView = itemView.findViewById(R.id.text_view_phone);
timeItemView = itemView.findViewById(R.id.text_view_time);
}
public void bind(String phone, String message, String time) {
phoneItemView.setText(phone);
messageItemView.setText(message);
timeItemView.setText(time);
}
//viewType содержит id для нужного layout.
static MessageViewHolder create(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(viewType, parent, false);
return new MessageViewHolder(view);
}
}
请告诉我如何正确启动此任务?如果我没看错的话,我需要在MessageListAdapter class.
中设置一个长按消息的监听器MainActivity GitHub。
应用程序的工作原型 (apk file)。
你可能想要一个类似 MessageView
//this will allow each message to be selected individually.
//the adapter should display MessageViews instead of Messages directly.
public class MessageView{
private Message message;
private boolean isSelected;
//constructor and getters and setters;
}
//set your view holder like this
class MessageViewHolder extends RecyclerView.ViewHolder {
private final TextView phoneItemView;
private final TextView messageItemView;
private final TextView timeItemView;
private final Checkbox checkBoxView;
private MessageViewHolder(View itemView) {
super(itemView);
messageItemView = itemView.findViewById(R.id.text_view_message);
phoneItemView = itemView.findViewById(R.id.text_view_phone);
timeItemView = itemView.findViewById(R.id.text_view_time);
checkBoxView= itemView.findViewById(R.id.check_box_view);
checkboxView.setOnCheckedChangeListener((checkbox,checked)=>{
messageList.get(getAdapterPosition()).isSelected(checked);
});
}
public void bind(MessageView messageView) {
phoneItemView.setText(messageView.getMessage().getPhone());
messageItemView.setText(messageView.getMessage().getMessage());
timeItemView.setText(TimeStampConverter.getTime(messageView.getMessage().getDate()));
checkBoxView.setChecked(messageView.isSelected());
}
}
//call this on the select all check box in your activity/fragment
public void onSelectAll(boolean selected){
for(MessageView view : messageList)
view.isSelected(selected);
adapter.notifyDataSetChanged();
}
//call this on the delete all button click in your activity/fragment
public void onDeleteSelected(){
Iterator i = messageList.iterator();
MessageView messageView;
while (i.hasNext()) {
messageView = (MessageView ) i.next();
if (messageView.isSelected())
i.remove();
}
adapter.notifyDataSetChanged();
}
我已经考虑了一段时间可以做什么。 因此,我决定尝试为 RecyclerView 中的每个元素添加复选框,并在 ListAdapter class.
中设置侦听器public class MessageListAdapter extends ListAdapter<Message, MessageViewHolder> {
HelperAdapter helperAdapter;
public MessageListAdapter(@NonNull DiffUtil.ItemCallback<Message> diffCallback, HelperAdapter helperAdapter) {
super(diffCallback);
this.helperAdapter = helperAdapter;
}
@Override
public int getItemViewType(int position) {
if (getItem(position).getNature().equals("outgoing"))
return R.layout.recyclerview_item_outgoing;
else
return R.layout.recyclerview_item_incoming;
}
@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return MessageViewHolder.create(parent, viewType);
}
@Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
Message current = getItem(position);
holder.bind(current.getPhone(),
current.getText(),
TimeStampConverter.getTime(current.getDate())); // Бинтим телефон сообщение и время
// Добавим все view CheckBox в list чтобы скрывать и показывать их по мере необходимости
helperAdapter.addCheckBox(holder.getMessageCheckBox());
// Установим слушатель короткого нажатия по сообщению.
holder.getMessageBox().setOnClickListener(v -> {
EditText editPhone = helperAdapter.getMainActivity()
.findViewById(R.id.edit_phone);
editPhone.setText(current.getPhone());
});
// Установим слушатель долгого нажатия по сообщению.
holder.getMessageBox().setOnLongClickListener(v -> {
helperAdapter.getMainActivity()
.findViewById(R.id.trash_button)
.setVisibility(View.VISIBLE);
helperAdapter.getMainActivity()
.findViewById(R.id.close_button)
.setVisibility(View.VISIBLE);
for (CheckBox checkBox: helperAdapter.getSetCheckBox())
checkBox.setVisibility(View.VISIBLE);
return false;
});
// Установим слушатели для чекбоксов, которые переключают переменную isSelected
holder.getMessageCheckBox().setOnClickListener(v -> {
current.isSelected = ((CheckBox) v).isChecked();
helperAdapter.addCheckBox((CheckBox) v);
});
}
public static class MessageDiff extends DiffUtil.ItemCallback<Message> {
@Override
public boolean areItemsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem == newItem;
}
@Override
public boolean areContentsTheSame(@NonNull Message oldItem, @NonNull Message newItem) {
return oldItem.getText().equals(newItem.getText());
}
}
}
我还创建了一个辅助 class HelperAdapter 来通过它删除标记的消息。
public class HelperAdapter {
private static HelperAdapter helperAdapter;
private MessageViewModel mMessageViewModel;
private MainActivity mainActivity;
private final HashSet<CheckBox> listCheckBox = new HashSet<>();
public void deleteSelected() {
LiveData<List<Message>> temp = mMessageViewModel.getAllMessages();
List<Message> allMessages = temp.getValue();
if (allMessages != null)
for(Message message: allMessages)
if(message.isSelected)
mMessageViewModel.delete(message);
// Скроем иконку корзины и чекбоксы
mainActivity.findViewById(R.id.trash_button).setVisibility(View.GONE);
mainActivity.findViewById(R.id.close_button).setVisibility(View.GONE);
for (CheckBox checkBox: listCheckBox)
checkBox.setVisibility(View.GONE);
}
public void setMessageViewModel(MessageViewModel messageViewModel){
mMessageViewModel = messageViewModel;
}
public MessageViewModel getMessageViewModel() { return mMessageViewModel; }
public HashSet<CheckBox> getSetCheckBox() {return listCheckBox;}
public void addCheckBox(CheckBox checkBox) {
listCheckBox.add(checkBox);
}
public void removeCheckBox(CheckBox checkBox){
listCheckBox.remove(checkBox);
}
public int sizeCheckBox() {return listCheckBox.size();}
public static HelperAdapter getHelperAdapter(){
if (helperAdapter == null) helperAdapter = new HelperAdapter();
return helperAdapter;
}
public void setMainActivity(MainActivity mainActivity){
this.mainActivity = mainActivity;
}
public MainActivity getMainActivity() { return mainActivity; }
}
我还为消息添加了一个布尔变量 class:
@Entity(tableName = "messages_table")
public class Message {
@PrimaryKey(autoGenerate = true)
private int id;
private String phone;
private String text;
private String nature;
private String service;
private Date date;
@Ignore
public boolean isSelected; // I added it
public Message(int id,
@NonNull String phone,
@NonNull String text,
@NonNull String nature,
@NonNull String service,
@NonNull Date date
) {
this.id = id;
this.phone = phone;
this.text = text;
this.nature = nature;
this.service = service;
this.date = date;
}
public int getId(){return this.id;}
public String getPhone(){return this.phone;}
public String getText(){return this.text;}
public String getNature(){return this.nature;}
public String getService(){return this.service;}
public Date getDate(){return this.date;}
}
现在我可以为垃圾桶图标设置监听器了:
// ОнКлик для иконки корзины
public void deleteMessage(View view){
helperAdapter.deleteSelected();
}
感谢 LiveData,我不必考虑更新 RecyclerView。 LiveData 删除已删除的消息。
这工作或多或少稳定,但我感觉我搞砸了体系结构并选择了错误的方法。
测试 apk 文件:https://dropmefiles.com/UxPPx