我对Android开发很陌生 - 并且非常震惊:
我有一个Activity,显示添加了CardViews的RecyclerView。
每个CardView都附加了一个View.OnClickListener,每个CardView还包含一个附加了View.OnLongClickListener的ImageView。 此外,RecyclerView附加了一个RecyclerView.ItemTouchHelper以支持Drag(通过拖动整个CardView)和Swipe(通过在CardView中滑动ImageView,因此ImageView可以作为一种句柄)。
到目前为止,所有这些Listeners以及Dragging和Swiping在Android Studio中的模拟器(任何模拟的Android版本)上完美协调(使用鼠标点击)。但是当谈到真正的(Lollipop)设备(使用触摸)时,CardView中的OnClickListener似乎不再起作用了。它显示了单击该项目的视觉效果,但未调用onClick方法 - 就像点击/触摸事件未被识别或另一个“隐藏”侦听器捕获并消耗它。
如果在仿真器和真实设备上的行为相同,则很容易进行故障排除。但事实并非如此,我必须假设,任何(真实)设备上的行为都可能不同?
在模拟器和真实设备之间没有发现应用行为会有所不同的有用参考,但只是在模拟器中平稳运行时,应用甚至可能无法在真实设备上启动。任何想法?
这是我的听众的实现:
private class MyOnClickListener implements View.OnClickListener {
private final Context context;
public MyOnClickListener(Context context) {
this.context = context;
}
@Override
public void onClick(View v) {
Log.i("ClickListener", "onClick fired");
int selectedItemPosition = recyclerView.getChildAdapterPosition(v);
Flight f = flightListRecyclerAdapter.getFlight(selectedItemPosition);
if (data().getNewFlights().contains(f)) {
data().getNewFlights().remove(f);
flightListRecyclerAdapter.notifyItemChanged(selectedItemPosition);
} else {
Intent intent = new Intent(ShowFlightsActivity.this, EditFlightActivity.class);
intent.putExtra(EditFlightActivity.FLIGHT_INFO, f);
startActivity(intent);
}
}
}
private class MyOnLongClickListener implements View.OnLongClickListener {
private final Context context;
public MyOnLongClickListener(Context context) {
this.context = context;
}
@Override
public boolean onLongClick(View v) {
Log.i("ClickListener", "onLongClick fired");
int selectedItemPosition = recyclerView.getChildAdapterPosition((View) v.getParent().getParent());
Flight f = flightListRecyclerAdapter.getFlight(selectedItemPosition);
FlightListViewHolder viewHolder = (FlightListViewHolder) recyclerView.findViewHolderForAdapterPosition(selectedItemPosition);
// toggle assumption of flight (but only for foreign flights)
synchronized (LocalData.getInstance().getLock()) {
if (f.getAssumptions() != null) {
if (f.getAssumptions().size() == 0 || !f.getAssumptions().get(0).getAirport().equals(data().getOwnAirport())) {
assumeFlight(f);
} else {
unassumeFlight(f);
}
}
setCardBackground(ShowFlightsActivity.this, viewHolder.getCardView(), f);
}
return true;
}
}
TouchHelperCallback:
public class FlightListItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final FlightListItemTouchHelperAdapter adapter;
public FlightListItemTouchHelperCallback(FlightListItemTouchHelperAdapter adapter) {
this.adapter = adapter;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// support up and down movement
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags=0;
if (viewHolder instanceof FlightListViewHolder) {
FlightListViewHolder flightListViewHolder = (FlightListViewHolder) viewHolder;
if (flightListViewHolder.dismissable) {
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
}
}
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
adapter.onItemDismiss(viewHolder.getAdapterPosition());
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
}
在onCreateViewHolder()中从适配器内调用的静态方法(我将其解析为在另一个地方使用相同的功能 - 不同的活动,所以不应该是问题,我认为),这里的监听器是附加的到CardViews:
public static FlightListViewHolder createViewHolder(ViewGroup parent, Context context, boolean setListeners) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.flightlist_layout, parent, false);
FlightListViewHolder flightListViewHolder = new FlightListViewHolder(view);
ImageView leftImage = flightListViewHolder.leftImage;
ImageView rightImage = flightListViewHolder.rightImage;
if (setListeners) {
view.setOnClickListener(ShowFlightsActivity.getMyOnClickListener());
leftImage.setOnLongClickListener(ShowFlightsActivity.getMyOnLongClickListener());
rightImage.setOnLongClickListener(ShowFlightsActivity.getMyOnLongClickListener());
}
return flightListViewHolder;
}
编辑:我想我现在看到了问题......我也在同一个cardView上设置一个OnTouchListener ......但是我仍然想知道它在模拟器中是如何工作的......
EDIT2:确实因为同时拥有OnTouchListener和OnClickListener而引发了问题。我终于通过覆盖我的CardView中的View.OnTouchEvent来解决它,如果触摸事件结果是点击(在此之后OnClickListener正常工作),则给出performClick():
@Override
public boolean onTouchEvent(MotionEvent e) {
if (MotionEventCompat.getActionMasked(e) ==
MotionEvent.ACTION_DOWN) {
Log.i("ClickableCardView", "onTouch fired");
impactPoint = e.getX();
} else if (MotionEventCompat.getActionMasked(e) == MotionEvent.ACTION_UP) {
if (impactPoint - e.getX() == 0) {
Log.i("ClickableCardView", "this was a click");
performClick();
} else {
Log.i("ClickableCardView", "this was a move: " + Float.toString(impactPoint - e.getX()));
}
}
return true;
}