如何使用onScroll和GestureDetector让一个视图跟随手指移动 - Android

9

我有一个RelativeLayout,其中包含一个位于中间的TextView。我已经使用SimpleOnGestureListener()使其检测到onFling、onDown和onScroll事件。

我希望TextView能够跟随我的手指在屏幕上移动(仅限于x轴),当我松开手指时,它可以动画地移出屏幕或回到中间(取决于我移动了多远)。

1个回答

15

以下是我在这种情况下通常要做的事情。

首先,您的onScroll方法应该类似于下面这样:

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
    // Make sure that mTextView is the text view you want to move around

    if (!(mTextView.getLayoutParams() instanceof MarginLayoutParams))
    {
        return false;
    }

    MarginLayoutParams marginLayoutParams = (MarginLayoutParams) mTextView.getLayoutParams();

    marginLayoutParams.leftMargin = (int) marginLayoutParams.leftMargin - distanceX;
    marginLayoutParams.topMargin = (int) marginLayoutParams.topMargin - distanceY;

    mTextView.requestLayout();

    return true;
}

我们正在修改leftMargin和topMargin,使其移动的距离相当于已经滚动的距离。
接下来,为了使文本视图动画回到原始位置,需要在事件为ACTION_UP或ACTION_CANCEL时这样做:
@Override
public boolean onTouch(View arg0, MotionEvent event)
{
    if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMasked() == MotionEvent.ACTION_CANCEL)
    {
        snapBack();
    }
    return mScrollDetector.onTouchEvent(event);
}

然后在snapBack方法中,我们会将文本视图动画返回:

private void snapBack ()
{
    if (mTextView.getLayoutParams() instanceof MarginLayoutParams)
    {
        final MarginLayoutParams marginLayoutParams = (MarginLayoutParams) mTextView.getLayoutParams();

        final int startValueX = marginLayoutParams.leftMargin;
        final int startValueY = marginLayoutParams.topMargin;
        final int endValueX = 0;
        final int endValueY = 0;

        mTextView.clearAnimation();

        Animation animation = new Animation()
        {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t)
            {
                int leftMarginInterpolatedValue = (int) (startValueX + (endValueX - startValueX) * interpolatedTime);
                marginLayoutParams.leftMargin = leftMarginInterpolatedValue;

                int topMarginInterpolatedValue = (int) (startValueY + (endValueY - startValueY) * interpolatedTime);
                marginLayoutParams.topMargin = topMarginInterpolatedValue;

                mTextView.requestLayout();
            }
        };
        animation.setDuration(200);
        animation.setInterpolator(new DecelerateInterpolator());
        mTextView.startAnimation(animation);
    }
}

完成了!您可以修改endValueXendValueY变量,以控制在放开手指后文本视图返回的位置。


为了避免每次滚动都重新绘制视图,可以为distanceX添加一个条件。像这样:if(distanceX > 5){ marginLayoutParams.leftMargin = (int)marginLayoutParams.leftMargin - distanceX; - Saba Jamalian
@monchote 兄弟,你的代码完美运行...我使用的是Button而不是TextView。我可以拖动这个按钮。当我松开手指时,按钮会回到原始位置。我想让按钮停留在我手指放置的RelativeLayout周围,请帮忙... - reegan29
1
@reegan29 简单地尝试不要在onTouch内部调用snapBack()。这样应该就可以了。 - monchote
@monchote 你好,我也需要使用手势旋转视图。当我将视图旋转>=90度时,滚动会变得奇怪。这是因为顶部和左侧的边距在旋转视图时也在旋转。有没有解决这个问题的方法? - hushed_voice

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接