recyclerview 中的手势检测器出现故障
Gesture detectors malfunctions in recyclerview
对于我的应用程序,我正在实现 recyclerview
以网格格式显示图像。
onlongPress
我需要删除多个项目。
onclick
我需要在新 activity 中显示点击的图像。
所以我用 SimpleOnGestureListener
来实现它。
首先我实现了 onLongPress
它工作 fine.But 如果我在 recyclerview 的其他地方长按而不是 image.I 通过放置条件 [=17 处理它,它返回 id 为 -1 =].
问题 1: 这是正确的做法还是我做错了什么?
接下来,我为点击实现了 onSingleTapUp
。当我执行 onLongPress
时,也会调用 onSingleTapUp
。我处理了它,我放置了一个标志来指示它的长按。
现在,如果我单击图像,onSingleTapUp
会被多次调用。例如:如果我第一次按 2 times.next 时间 6 并继续增加。
问题2:如何解决onSingleTapUp
在onLongPress
上被调用和onSingleTapUp
被多次调用?
更新:
MainActivity
`
@Override
public void onItemClicked(int position) {
if (actionMode != null) {
toggleSelection(position);
}
}
private void toggleSelection(int position) {
mAdapter.toggleSelection(position);
int count = mAdapter.getSelectedItemCount();
if (count == 0) {
actionMode.finish();
} else {
actionMode.setTitle(String.valueOf(count));
actionMode.invalidate();
}
}
@Override
public boolean onItemLongClicked(int position) {
if (actionMode == null) {
actionMode = startSupportActionMode(actionModeCallback);
}
toggleSelection(position);
return true;
}
private class ActionModeCallback implements ActionMode.Callback {
@SuppressWarnings("unused")
private final String TAG = ActionModeCallback.class.getSimpleName();
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate (R.menu.menu_main, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
// TODO: actually remove items
Log.d(TAG, "Delete called");
List<Integer> selectedItemPositions = mAdapter.getSelectedItems();
int i;
int currPos;
for (i = (selectedItemPositions.size()) - 1; i >= 0; i--) {
currPos = selectedItemPositions.get(i);
mAdapter.removeData(currPos,filePath);
}
getDirectoryFiles();
setUpRecyclerView();
mode.finish();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mAdapter.clearSelection();
actionMode = null;
}
}`
Adapter
`
public class GridAdapter extends SelectableAdapter<GridAdapter.ViewHolder> {
List<images> mItems;
private ArrayList<String> filePath;
final Context mContext;
private ViewHolder.ClickListener clickListener;
public GridAdapter(Context context, ArrayList<String> fileName, ArrayList<String> filePath, ViewHolder.ClickListener clickListener) {
super();
this.clickListener = clickListener;
this.filePath = filePath;
mItems = new ArrayList<images>();
this.mContext = context;
for (int i = 0; i < fileName.size(); i++) {
images img = new images();
img.setName(fileName.get(i));
img.setThumbnail(i);
mItems.add(img);
}
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_item, parent, false);
// View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
ViewHolder viewHolder = new ViewHolder(v,clickListener,mContext,filePath);
return viewHolder;
}
@Override
public void onBindViewHolder(final ViewHolder viewHolder, int i) {
// Decode the filepath with BitmapFactory followed by the position
Bitmap bmp = null;
try {
bmp = decodeFile(new File(filePath.get(i)));
} catch (IOException e) {
e.printStackTrace();
}
//Picasso.with(mContext).load(new File(filePath.get(i))).into(viewHolder.imgThumbnail);
// Set the decoded bitmap into ImageView
viewHolder.imgThumbnail.setImageBitmap(bmp);
}
@Override
public int getItemCount() {
return mItems.size();
}
public void removeData(int currPos, ArrayList<String> filePath) {
File f=new File(filePath.get(currPos));
f.delete();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
View.OnLongClickListener {
public ImageView imgThumbnail;
private ClickListener listener;
private Context mContext;
private ArrayList<String> filePath;
public int press_flag=0;
public ViewHolder(View itemView, ClickListener listener,Context context,ArrayList<String> filePath) {
super(itemView);
imgThumbnail = (ImageView) itemView.findViewById(R.id.img_thumbnail);
this.listener = listener;
this.mContext=context;
this.filePath=filePath;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
// Log.v("method","viewholder constructor");
}
@Override
public void onClick(View v) {
if(press_flag==0) {
Log.d("onclick", "Item clicked at position " + getPosition());
int j = getPosition();
Intent i = new Intent(mContext, image_preview.class);
i.putExtra("j", j);
i.putExtra("filepath", filePath.get(j));
mContext.startActivity(i);
}
if (listener != null) {
listener.onItemClicked(getPosition());
}
}
@Override
public boolean onLongClick(View v) {
Log.d("Onlongclick", "Item long-clicked at position " + getPosition());
if (listener != null) {
return listener.onItemLongClicked(getPosition());
}
return false;
}
public interface ClickListener {
public void onItemClicked(int position);
public boolean onItemLongClicked(int position);
}
}
}`
这个回答是关于OP遇到的第二个问题:从SimpleOnGestureListener
切换到简单的OnClickListener
和OnLongClickListener
后,点击项目时,预览activity(应该在正常模式下显示)即使用户处于选择模式也会显示。
单击项目时实际上调用了两个位置。来自 ViewHolder
(在适配器文件中):
@Override
public void onClick(View v) {
if(press_flag==0) {
Log.d("onclick", "Item clicked at position " + getPosition());
int j = getPosition();
Intent i = new Intent(mContext, image_preview.class);
i.putExtra("j", j);
i.putExtra("filepath", filePath.get(j));
mContext.startActivity(i);
}
if (listener != null) {
listener.onItemClicked(getPosition());
}
}
从听众那里,在这种情况下,您的 MainActivity
:
@Override
public void onItemClicked(int position) {
if (actionMode != null) {
toggleSelection(position);
}
}
那么,那里发生了什么?首先,您的 ViewHolder
的侦听器方法被调用。如果 press_flag
等于 0(我猜这是为了解决您的问题,并且始终如此),您将开始预览 activity。任何状况之下。然后,你通知MainActivity
。这个MainActivity
负责设置一个item是选中还是未选中,并且知道当前的选中状态。
这里有一个简单的解决方法:将预览起始代码移至 MainActivity
。你的代码变成这样:
ViewHolder
:
@Override
public void onClick(View v) {
if (listener != null) {
listener.onItemClicked(getPosition());
}
}
MainActivity
:
@Override
public void onItemClicked(int position) {
// If we are already selecting something
if (actionMode != null) {
toggleSelection(position);
} else { // Or if we're not
Log.d("onclick", "Item clicked at position " + position);
Intent i = new Intent(this, image_preview.class); // mContext is useless here as we already are in a Context
i.putExtra("j", position);
i.putExtra("filepath", mAdapter.getFilePath(position); // New method to create in the adapter
startActivity(i); // Again, no need for an additional Context here
}
}
Adater
:
您需要一种从 MainActivity
获取文件路径的新方法,非常简单。您可能已经在 MainActivity
…
中获得了信息
public String getFilePath(int position) {
return filePath.get(position); // You may need to check for position being valid (compare to 0 and filePath.size())
}
对于我的应用程序,我正在实现 recyclerview
以网格格式显示图像。
onlongPress
我需要删除多个项目。
onclick
我需要在新 activity 中显示点击的图像。
所以我用 SimpleOnGestureListener
来实现它。
首先我实现了 onLongPress
它工作 fine.But 如果我在 recyclerview 的其他地方长按而不是 image.I 通过放置条件 [=17 处理它,它返回 id 为 -1 =].
问题 1: 这是正确的做法还是我做错了什么?
接下来,我为点击实现了 onSingleTapUp
。当我执行 onLongPress
时,也会调用 onSingleTapUp
。我处理了它,我放置了一个标志来指示它的长按。
现在,如果我单击图像,onSingleTapUp
会被多次调用。例如:如果我第一次按 2 times.next 时间 6 并继续增加。
问题2:如何解决onSingleTapUp
在onLongPress
上被调用和onSingleTapUp
被多次调用?
更新:
MainActivity
`
@Override
public void onItemClicked(int position) {
if (actionMode != null) {
toggleSelection(position);
}
}
private void toggleSelection(int position) {
mAdapter.toggleSelection(position);
int count = mAdapter.getSelectedItemCount();
if (count == 0) {
actionMode.finish();
} else {
actionMode.setTitle(String.valueOf(count));
actionMode.invalidate();
}
}
@Override
public boolean onItemLongClicked(int position) {
if (actionMode == null) {
actionMode = startSupportActionMode(actionModeCallback);
}
toggleSelection(position);
return true;
}
private class ActionModeCallback implements ActionMode.Callback {
@SuppressWarnings("unused")
private final String TAG = ActionModeCallback.class.getSimpleName();
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate (R.menu.menu_main, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
// TODO: actually remove items
Log.d(TAG, "Delete called");
List<Integer> selectedItemPositions = mAdapter.getSelectedItems();
int i;
int currPos;
for (i = (selectedItemPositions.size()) - 1; i >= 0; i--) {
currPos = selectedItemPositions.get(i);
mAdapter.removeData(currPos,filePath);
}
getDirectoryFiles();
setUpRecyclerView();
mode.finish();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mAdapter.clearSelection();
actionMode = null;
}
}`
Adapter
`
public class GridAdapter extends SelectableAdapter<GridAdapter.ViewHolder> {
List<images> mItems;
private ArrayList<String> filePath;
final Context mContext;
private ViewHolder.ClickListener clickListener;
public GridAdapter(Context context, ArrayList<String> fileName, ArrayList<String> filePath, ViewHolder.ClickListener clickListener) {
super();
this.clickListener = clickListener;
this.filePath = filePath;
mItems = new ArrayList<images>();
this.mContext = context;
for (int i = 0; i < fileName.size(); i++) {
images img = new images();
img.setName(fileName.get(i));
img.setThumbnail(i);
mItems.add(img);
}
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_item, parent, false);
// View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
ViewHolder viewHolder = new ViewHolder(v,clickListener,mContext,filePath);
return viewHolder;
}
@Override
public void onBindViewHolder(final ViewHolder viewHolder, int i) {
// Decode the filepath with BitmapFactory followed by the position
Bitmap bmp = null;
try {
bmp = decodeFile(new File(filePath.get(i)));
} catch (IOException e) {
e.printStackTrace();
}
//Picasso.with(mContext).load(new File(filePath.get(i))).into(viewHolder.imgThumbnail);
// Set the decoded bitmap into ImageView
viewHolder.imgThumbnail.setImageBitmap(bmp);
}
@Override
public int getItemCount() {
return mItems.size();
}
public void removeData(int currPos, ArrayList<String> filePath) {
File f=new File(filePath.get(currPos));
f.delete();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
View.OnLongClickListener {
public ImageView imgThumbnail;
private ClickListener listener;
private Context mContext;
private ArrayList<String> filePath;
public int press_flag=0;
public ViewHolder(View itemView, ClickListener listener,Context context,ArrayList<String> filePath) {
super(itemView);
imgThumbnail = (ImageView) itemView.findViewById(R.id.img_thumbnail);
this.listener = listener;
this.mContext=context;
this.filePath=filePath;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
// Log.v("method","viewholder constructor");
}
@Override
public void onClick(View v) {
if(press_flag==0) {
Log.d("onclick", "Item clicked at position " + getPosition());
int j = getPosition();
Intent i = new Intent(mContext, image_preview.class);
i.putExtra("j", j);
i.putExtra("filepath", filePath.get(j));
mContext.startActivity(i);
}
if (listener != null) {
listener.onItemClicked(getPosition());
}
}
@Override
public boolean onLongClick(View v) {
Log.d("Onlongclick", "Item long-clicked at position " + getPosition());
if (listener != null) {
return listener.onItemLongClicked(getPosition());
}
return false;
}
public interface ClickListener {
public void onItemClicked(int position);
public boolean onItemLongClicked(int position);
}
}
}`
这个回答是关于OP遇到的第二个问题:从SimpleOnGestureListener
切换到简单的OnClickListener
和OnLongClickListener
后,点击项目时,预览activity(应该在正常模式下显示)即使用户处于选择模式也会显示。
单击项目时实际上调用了两个位置。来自 ViewHolder
(在适配器文件中):
@Override
public void onClick(View v) {
if(press_flag==0) {
Log.d("onclick", "Item clicked at position " + getPosition());
int j = getPosition();
Intent i = new Intent(mContext, image_preview.class);
i.putExtra("j", j);
i.putExtra("filepath", filePath.get(j));
mContext.startActivity(i);
}
if (listener != null) {
listener.onItemClicked(getPosition());
}
}
从听众那里,在这种情况下,您的 MainActivity
:
@Override
public void onItemClicked(int position) {
if (actionMode != null) {
toggleSelection(position);
}
}
那么,那里发生了什么?首先,您的 ViewHolder
的侦听器方法被调用。如果 press_flag
等于 0(我猜这是为了解决您的问题,并且始终如此),您将开始预览 activity。任何状况之下。然后,你通知MainActivity
。这个MainActivity
负责设置一个item是选中还是未选中,并且知道当前的选中状态。
这里有一个简单的解决方法:将预览起始代码移至 MainActivity
。你的代码变成这样:
ViewHolder
:
@Override
public void onClick(View v) {
if (listener != null) {
listener.onItemClicked(getPosition());
}
}
MainActivity
:
@Override
public void onItemClicked(int position) {
// If we are already selecting something
if (actionMode != null) {
toggleSelection(position);
} else { // Or if we're not
Log.d("onclick", "Item clicked at position " + position);
Intent i = new Intent(this, image_preview.class); // mContext is useless here as we already are in a Context
i.putExtra("j", position);
i.putExtra("filepath", mAdapter.getFilePath(position); // New method to create in the adapter
startActivity(i); // Again, no need for an additional Context here
}
}
Adater
:
您需要一种从 MainActivity
获取文件路径的新方法,非常简单。您可能已经在 MainActivity
…
public String getFilePath(int position) {
return filePath.get(position); // You may need to check for position being valid (compare to 0 and filePath.size())
}