OnTouchListener 防止视觉反馈
Posted
技术标签:
【中文标题】OnTouchListener 防止视觉反馈【英文标题】:OnTouchListener prevents visual feedback 【发布时间】:2015-10-16 18:15:45 【问题描述】:我有一个 ListView,它有一个 OnItemClickListener。最重要的是,每一行(CardView)都有一个 OnTouchListener 以实现滑动手势。
OnTouchListener 对 ACTION_DOWN、ACTION_CANCEL、ACTION_MOVE 和 ACTION_UP 做出反应。我在 ACTION_UP 发生时使用 performItemClick(),以便在需要时调用 OnItemClickListener。
如果我在 OnTouchListener 中返回 true,我通过 ACTION_MOVE 实现的滑动动作可以完美运行,单击该项目也可以。 但是,视觉反馈为零。 通常情况下,Lollipop 上会有波纹或 ICS 上的背景变化。
如果我返回 False(意味着我不想拦截该事件),那么会有视觉反馈并且点击有效……但我的 OnTouchListener 永远不会拦截任何 ACTION_MOVE 事件。这可以防止任何滑动。
我尝试了多种解决方案,例如使用 v.setpressed() 但都没有效果。
我很想知道如果我的 OnTouchListener 没有拦截事件,我如何才能保留涟漪(或一般的视觉反馈)。
这是我的 OnTouchListener,如果你好奇的话。
private final View.OnTouchListener mTouchListener = new View.OnTouchListener()
float mDownX;
private int mSwipeSlop = -1;
private boolean mItemPressed;
private VelocityTracker mVelocityTracker = null;
private HashMap<Long, Integer> mItemIdTopMap = new HashMap<>();
@Override
public boolean onTouch(final View v, MotionEvent event)
int index = event.getActionIndex();
int pointerId = event.getPointerId(index);
if (mSwipeSlop < 0)
mSwipeSlop = ViewConfiguration.get(getActivity())
.getScaledTouchSlop();
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
if (mItemPressed)
// Multi-item swipes not handled
return false;
mItemPressed = true;
mDownX = event.getX();
if (mVelocityTracker == null)
// Retrieve a new VelocityTracker object to watch the velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
else
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_CANCEL:
v.setAlpha(1);
v.setTranslationX(0);
mItemPressed = false;
mVelocityTracker.recycle();
mVelocityTracker = null;
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
float x = event.getX() + v.getTranslationX();
float deltaX = x - mDownX;
float deltaXAbs = Math.abs(deltaX);
if (!mSwiping)
if (deltaXAbs > mSwipeSlop)
mSwiping = true;
getListView().requestDisallowInterceptTouchEvent(true);
mBackgroundContainer.showBackground(v.getTop(), v.getHeight());
if (mSwiping)
v.setTranslationX((x - mDownX));
v.setAlpha(1 - deltaXAbs / v.getWidth());
break;
case MotionEvent.ACTION_UP:
// User let go - figure out whether to animate the view out, or back into place
if (mSwiping)
float x = event.getX() + v.getTranslationX();
float deltaX = x - mDownX;
float deltaXAbs = Math.abs(deltaX);
float fractionCovered;
float endX;
float endAlpha;
final boolean remove;
mVelocityTracker.computeCurrentVelocity(1000);
float velocityX = Math.abs(VelocityTrackerCompat.getXVelocity(mVelocityTracker, pointerId));
if (velocityX > 700 || deltaXAbs > v.getWidth() / 4)
// fixme
fractionCovered = deltaXAbs / v.getWidth();
endX = deltaX < 0 ? -v.getWidth() : v.getWidth();
endAlpha = 0;
remove = true;
else
// Not far enough - animate it back
fractionCovered = 1 - (deltaXAbs / v.getWidth());
endX = 0;
endAlpha = 1;
remove = false;
mVelocityTracker.clear();
int SWIPE_DURATION = 600;
long duration = (int) ((1 - fractionCovered) * SWIPE_DURATION);
getListView().setEnabled(false);
v.animate().setDuration(duration).
alpha(endAlpha).translationX(endX).
withEndAction(new Runnable() // fixme replace with AnimationListener
@Override
public void run()
// Restore animated values
v.setAlpha(1);
v.setTranslationX(0);
if (remove)
animateRemoval(getListView(), v);
else
mBackgroundContainer.hideBackground();
mSwiping = false;
getListView().setEnabled(true);
);
else
int position = getListView().getPositionForView(v);
if (position != ListView.INVALID_POSITION)
getListView().performItemClick(v, position, getListView().getItemIdAtPosition(position));
mItemPressed = false;
break;
default:
return false;
return true;
private void animateRemoval(final ListView listview, View viewToRemove)
// irrelevant
;
它基于几年前 Chet Haase 的 demo。
我真的想不通。帮忙?
谢谢!
【问题讨论】:
可能是***.com/questions/3921138/gesture-in-listview-android? @TudorLuca 手势检测(滑动)工作正常。问题是触摸一行并没有给我任何视觉反馈。 你有没有试过在 ACTION_MOVE 时返回 true,在滑动完成时返回 false? 在你的 switch 案例中 Action_Move 而不是使用 break;删除该行并使用 return false ,试试看 @TudorLuca 我刚试过。诡异:一开始只能滑动(没有点击,没有涟漪),滑动一次之后,变成可以点击(有涟漪),不能滑动。 【参考方案1】:对我来说,v.setPressed 成功了,其中 v 是接收触摸事件的视图。这意味着在 ACTION_DOWN 上我调用了 v.setPressed(true) 并在 ACTION_UP 上调用了 v.setPressed(false)
【讨论】:
view.setPress()
完美运行,ACTION_UP
时记得设置为 false 【参考方案2】:
我发现导致新片段出现的点击可以防止涟漪。在点击中添加短暂的延迟解决了我的问题。也就是这个
columnViewHolder.rippleLayout.setOnClickListener((v) ->
dataManager.setProducts(id, response.getProducts());
dataManager.setProductListPosition(id, position);
dataManager.clearCurrentProductItem();
Log.d(TAG, "product click " + product.toString());
EventBus.getDefault().post(new ProductDetailEvent(id, product));
tagManager.hubSpokeClick(product.getCode());
);
没有用,但是可以:
columnViewHolder.rippleLayout.setOnClickListener((v) ->
handler.postDelayed(() ->
dataManager.setProducts(id, response.getProducts());
dataManager.setProductListPosition(id, position);
dataManager.clearCurrentProductItem();
Log.d(TAG, "product click " + product.toString());
EventBus.getDefault().post(new ProductDetailEvent(id, product));
tagManager.hubSpokeClick(product.getCode());
, 200l);
);
【讨论】:
以上是关于OnTouchListener 防止视觉反馈的主要内容,如果未能解决你的问题,请参考以下文章