在 RecyclerView 的单个界面中使用多个 onClick 方法
Using multiple onClick methods in a single interface for RecyclerView
上下文:
我在我的待办事项列表应用程序中实现了 RecyclerView。
我希望能够对 RecyclerView 中的项目使用各种 onClick 方法,因此我创建了一个名为 onTaskListener 的接口。
这个接口有两个方法存根,一个是onClick,一个是onLongClick。在我的 ViewHolder 中,我实现了 onClick() 和 onLongClick() 方法,它们只是将控制传递给了我的 onTaskClickListener()。
在我的适配器中,我创建了一个 onTaskClickListener()。
然后在我的 main activity 中,我实现了 onTaskClickListener().
中的方法
我的问题是,虽然我的 onTaskClick() 运行良好,但我的 onTaskLongClick 似乎根本不起作用。我设置 RecyclerView/Adapter/ViewHolder/ViewModel 模式的方式有问题吗?
问题:如果我实现界面的方式不对,如何在一个界面中包含多种类型的点击事件?
下面是每个文件的相关内容(我知道的很多,代码墙很抱歉):
onTaskClickListener.java:
public interface OnTaskListener {
void onTaskClick(int position); // Interfaces are implicitly abstract
void onTaskLongClick(int position);
}
itemViewHolder.java:
public class itemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
View itmView; // This is the general view
TextView txtView; // This is the specific text view that shows up as a singular task in the list of to-do tasks
OnTaskListener onTaskListener; // Create an OnTaskListener inside our view holder which allows the view holder to realize it's been clicked
public itemViewHolder(@NonNull View itemView, OnTaskListener inputOnTaskListener) {
super(itemView);
itmView = itemView;
txtView = itemView.findViewById(R.id.txtTask);
this.onTaskListener = inputOnTaskListener; // Take an onTaskListener that is passed into the object and store it internally
itemView.setOnClickListener(this); // passes the View.OnClickListener context to the itemView via "this"
}
@Override
public void onClick(View view) {
onTaskListener.onTaskClick(getAdapterPosition()); // This says that whenever we register a click event, we pass the logic onto the taskClick event
}
@Override
public boolean onLongClick(View view) {
onTaskListener.onTaskLongClick(getAdapterPosition()); // This says that whenever we register a longClick event, we pass the logic onto the taskClick event
return true; // This means that we have successfully consumed the long click event. No other click events will be notified
}
}
dataAdapter.java
public class dataAdapter extends RecyclerView.Adapter<itemViewHolder> {
List<taskItem> taskItemList;
private OnTaskListener onTaskListener;
public dataAdapter(List<taskItem> inputTaskItemList, OnTaskListener inputOnTaskListener){
this.taskItemList = inputTaskItemList;
this.onTaskListener = inputOnTaskListener;
}
@NonNull
@Override
public itemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View localView = LayoutInflater.from(parent.getContext()).inflate(R.layout.taskholder, parent, false); //Don't even know what this line does, it's all so over my head
return new itemViewHolder(localView, onTaskListener); // Return an instance of whatever we made directly above this line
}
@Override
public void onBindViewHolder(@NonNull itemViewHolder holder, final int position) {
holder.txtView.setText(taskItemList.get(position).taskTitle);
// Look inside our ViewModel and get the text for this specific instance of the ViewModel, which corresponds to the current position
}
@Override
public int getItemCount() {
return taskItemList.size();
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements OnTaskListener{
private RecyclerView taskList; // Creates a RecyclerView to hook up to our RecyclerView widget in the UI
private dataAdapter localAdapter; // Instantiates our custom adapter class
List<taskItem> myItems; // Stores the items in a list of taskItem's
private RecyclerView.LayoutManager localLayoutManager; // God knows what this does :(
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
taskList = findViewById(R.id.taskList); // Connects our list from UI to recycler view code
localLayoutManager = new LinearLayoutManager(this); // assigns our localLayoutManager to an actual Layout Manager
taskList.setLayoutManager(localLayoutManager); // connecting our layout manager to our recycler view
taskList.setHasFixedSize(true);
myItems = new ArrayList<>(); // Now we FINALLY make our to-do list and populate it with actual tasks
myItems.add(new taskItem("groceries"));
myItems.add(new taskItem("practice bjj"));
localAdapter = new dataAdapter(myItems, this); // Pass the to do list to the adapter so it can feed it to the recycler view
taskList.setAdapter(localAdapter); // Lastly set the recycler view's adapter to the one we made above
}
@Override
public void onTaskClick(int position) {
taskItem currentTask = myItems.get(position);
if(!(currentTask.taskTitle.startsWith("Done: "))){ // Logic that marks a task as done on tap
currentTask.taskTitle = "Done: " + currentTask.taskTitle;
//logic that moves the tapped item to bottom of list
myItems.remove(position);
myItems.add(myItems.size(), currentTask);
localAdapter.notifyItemMoved(position, myItems.size());
}
else if(myItems.get(position).taskTitle.startsWith("Done: ")){ // Logic for if user taps a task already marked "done"
currentTask.taskTitle = currentTask.taskTitle.replaceFirst("Done: ", "");
myItems.set(position, currentTask); // Remove prefix
localAdapter.notifyItemChanged(position);
myItems.remove(position);
myItems.add(0, currentTask);
}
localAdapter.notifyDataSetChanged(); // Let the activity know that the data has changed
}
@Override
public void onTaskLongClick(int position) { // This branch deals with deleting tasks on long click
myItems.remove(position);
localAdapter.notifyItemRemoved(position); // Item has been deleted
}
}
你永远不会打电话给 setOnLongClickListener()
:
public itemViewHolder(@NonNull View itemView, OnTaskListener inputOnTaskListener) {
super(itemView);
itmView = itemView;
txtView = itemView.findViewById(R.id.txtTask);
this.onTaskListener = inputOnTaskListener; // Take an onTaskListener that is passed into the object and store it internally
itemView.setOnClickListener(this); // passes the View.OnClickListener context to the itemView via "this"
// Add this line
itemView.setOnLongClickListener(this); // passes the View.OnLongClickListener context to the itemView via "this"
}
或者,您可以通过内联整个 OnLongClickListener
(对于 OnClickListener
也是如此)来避免完全经历 this
:
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
onTaskListener.onTaskLongClick(getAdapterPosition()); // This says that whenever we register a longClick event, we pass the logic onto the taskClick event
return true; // This means that we have successfully consumed the long click event. No other click events will be notified
}
});
从而避免让您的 itemViewHolder
class 实现 OnLongClickListener
接口并且不可能忘记调用 setOnLongClickListener()
.
上下文:
我在我的待办事项列表应用程序中实现了 RecyclerView。
我希望能够对 RecyclerView 中的项目使用各种 onClick 方法,因此我创建了一个名为 onTaskListener 的接口。
这个接口有两个方法存根,一个是onClick,一个是onLongClick。在我的 ViewHolder 中,我实现了 onClick() 和 onLongClick() 方法,它们只是将控制传递给了我的 onTaskClickListener()。
在我的适配器中,我创建了一个 onTaskClickListener()。 然后在我的 main activity 中,我实现了 onTaskClickListener().
中的方法我的问题是,虽然我的 onTaskClick() 运行良好,但我的 onTaskLongClick 似乎根本不起作用。我设置 RecyclerView/Adapter/ViewHolder/ViewModel 模式的方式有问题吗?
问题:如果我实现界面的方式不对,如何在一个界面中包含多种类型的点击事件?
下面是每个文件的相关内容(我知道的很多,代码墙很抱歉):
onTaskClickListener.java:
public interface OnTaskListener {
void onTaskClick(int position); // Interfaces are implicitly abstract
void onTaskLongClick(int position);
}
itemViewHolder.java:
public class itemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
View itmView; // This is the general view
TextView txtView; // This is the specific text view that shows up as a singular task in the list of to-do tasks
OnTaskListener onTaskListener; // Create an OnTaskListener inside our view holder which allows the view holder to realize it's been clicked
public itemViewHolder(@NonNull View itemView, OnTaskListener inputOnTaskListener) {
super(itemView);
itmView = itemView;
txtView = itemView.findViewById(R.id.txtTask);
this.onTaskListener = inputOnTaskListener; // Take an onTaskListener that is passed into the object and store it internally
itemView.setOnClickListener(this); // passes the View.OnClickListener context to the itemView via "this"
}
@Override
public void onClick(View view) {
onTaskListener.onTaskClick(getAdapterPosition()); // This says that whenever we register a click event, we pass the logic onto the taskClick event
}
@Override
public boolean onLongClick(View view) {
onTaskListener.onTaskLongClick(getAdapterPosition()); // This says that whenever we register a longClick event, we pass the logic onto the taskClick event
return true; // This means that we have successfully consumed the long click event. No other click events will be notified
}
}
dataAdapter.java
public class dataAdapter extends RecyclerView.Adapter<itemViewHolder> {
List<taskItem> taskItemList;
private OnTaskListener onTaskListener;
public dataAdapter(List<taskItem> inputTaskItemList, OnTaskListener inputOnTaskListener){
this.taskItemList = inputTaskItemList;
this.onTaskListener = inputOnTaskListener;
}
@NonNull
@Override
public itemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View localView = LayoutInflater.from(parent.getContext()).inflate(R.layout.taskholder, parent, false); //Don't even know what this line does, it's all so over my head
return new itemViewHolder(localView, onTaskListener); // Return an instance of whatever we made directly above this line
}
@Override
public void onBindViewHolder(@NonNull itemViewHolder holder, final int position) {
holder.txtView.setText(taskItemList.get(position).taskTitle);
// Look inside our ViewModel and get the text for this specific instance of the ViewModel, which corresponds to the current position
}
@Override
public int getItemCount() {
return taskItemList.size();
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements OnTaskListener{
private RecyclerView taskList; // Creates a RecyclerView to hook up to our RecyclerView widget in the UI
private dataAdapter localAdapter; // Instantiates our custom adapter class
List<taskItem> myItems; // Stores the items in a list of taskItem's
private RecyclerView.LayoutManager localLayoutManager; // God knows what this does :(
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
taskList = findViewById(R.id.taskList); // Connects our list from UI to recycler view code
localLayoutManager = new LinearLayoutManager(this); // assigns our localLayoutManager to an actual Layout Manager
taskList.setLayoutManager(localLayoutManager); // connecting our layout manager to our recycler view
taskList.setHasFixedSize(true);
myItems = new ArrayList<>(); // Now we FINALLY make our to-do list and populate it with actual tasks
myItems.add(new taskItem("groceries"));
myItems.add(new taskItem("practice bjj"));
localAdapter = new dataAdapter(myItems, this); // Pass the to do list to the adapter so it can feed it to the recycler view
taskList.setAdapter(localAdapter); // Lastly set the recycler view's adapter to the one we made above
}
@Override
public void onTaskClick(int position) {
taskItem currentTask = myItems.get(position);
if(!(currentTask.taskTitle.startsWith("Done: "))){ // Logic that marks a task as done on tap
currentTask.taskTitle = "Done: " + currentTask.taskTitle;
//logic that moves the tapped item to bottom of list
myItems.remove(position);
myItems.add(myItems.size(), currentTask);
localAdapter.notifyItemMoved(position, myItems.size());
}
else if(myItems.get(position).taskTitle.startsWith("Done: ")){ // Logic for if user taps a task already marked "done"
currentTask.taskTitle = currentTask.taskTitle.replaceFirst("Done: ", "");
myItems.set(position, currentTask); // Remove prefix
localAdapter.notifyItemChanged(position);
myItems.remove(position);
myItems.add(0, currentTask);
}
localAdapter.notifyDataSetChanged(); // Let the activity know that the data has changed
}
@Override
public void onTaskLongClick(int position) { // This branch deals with deleting tasks on long click
myItems.remove(position);
localAdapter.notifyItemRemoved(position); // Item has been deleted
}
}
你永远不会打电话给 setOnLongClickListener()
:
public itemViewHolder(@NonNull View itemView, OnTaskListener inputOnTaskListener) {
super(itemView);
itmView = itemView;
txtView = itemView.findViewById(R.id.txtTask);
this.onTaskListener = inputOnTaskListener; // Take an onTaskListener that is passed into the object and store it internally
itemView.setOnClickListener(this); // passes the View.OnClickListener context to the itemView via "this"
// Add this line
itemView.setOnLongClickListener(this); // passes the View.OnLongClickListener context to the itemView via "this"
}
或者,您可以通过内联整个 OnLongClickListener
(对于 OnClickListener
也是如此)来避免完全经历 this
:
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
onTaskListener.onTaskLongClick(getAdapterPosition()); // This says that whenever we register a longClick event, we pass the logic onto the taskClick event
return true; // This means that we have successfully consumed the long click event. No other click events will be notified
}
});
从而避免让您的 itemViewHolder
class 实现 OnLongClickListener
接口并且不可能忘记调用 setOnLongClickListener()
.