Android触摸事件下移视图

16

我希望将两个不同的视图移入我的布局中,以便用户可以根据自己的喜好显示。

到目前为止,我已经编写了以下代码来处理触摸事件:

this.viewEvent.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent event)
    {           
        final int y = (int) event.getRawY();

        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
        switch (event.getAction() & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
                element.setEventY(y - params.topMargin);
                break;

            case MotionEvent.ACTION_UP:
                viewGroup.invalidate();
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                break;

            case MotionEvent.ACTION_MOVE:
                params.topMargin = y - element.getEventY();
                params.bottomMargin = screenHeight - view.getHeight() - params.topMargin;

                // Avoid out of screen
                if (params.topMargin < 0) return true;

                // Apply changes
                view.setLayoutParams(params);
                break;
        }

        return true;
    }
});

element是一个自定义对象的实例,用于处理位置。

screenHeight是由Display类提供的屏幕高度。

我能够移动这个元素,但当我触摸它时它会闪烁,一旦我松开手指,视图就消失了。我甚至无法检索它,因为它已经超出了屏幕。

我做错了什么吗?

谢谢你的帮助。


这是一个例子 http://thegeekyland.blogspot.com/2015/12/android-animations-explained.html - Arlind Hajredinaj
3个回答

21

使用以下代码执行一个简单的触摸移动

layout_counter.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent event)
        {
            if (currentState != State.EDIT_MOVE) return false;

            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
            if (view.getId() != R.id.layout_counter) return false;

            switch (event.getAction())
            {
                case MotionEvent.ACTION_MOVE:
                    params.topMargin = (int) event.getRawY() - view.getHeight();
                    params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
                    view.setLayoutParams(params);
                    break;

                case MotionEvent.ACTION_UP:
                    params.topMargin = (int) event.getRawY() - view.getHeight();
                    params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
                    view.setLayoutParams(params);
                    break;

                case MotionEvent.ACTION_DOWN:
                    view.setLayoutParams(params);
                    break;
            }

            return true;
        }
    });

在这里,layout_counter 是您想要移动的视图。

别忘了将可移动的元素放入FrameLayout中。


4
使用FrameLayout非常重要。我曾经花费了整整一天使用相对布局,试图弄清楚为什么只有一个我的图像视图是可拖动的,而其他的在触摸时显示日志,但它们不移动.. :( 谢谢。 - Ewoks
1
尽管我已经声明了FrameLayout,但它显示了尝试调用虚拟方法的空指针异常。 - Jeff Bootsholz
2
什么是State.EDIT_MOVE和currentState?你能解释一下吗? - Ajeet
这是我在代码中使用的 enum 状态,用于启用/禁用拖动按钮。 - Manitoba
我可以将相对布局添加到帧布局中以移动整个相对布局吗? - Pratik PSB

3

我创建了一个库,可以移动视图:

  • 对于低于JellyBean(16)的API,它会修改视图在其父容器内的边距
  • 对于JellyBean及更高版本的API,它会修改视图在其父容器内的绝对位置

只需添加依赖项:

dependencies {
    compile 'com.scalified:viewmover:1.1.0'
}

您可以在GitHub上找到更多信息。


2
你能举个例子说明如何使用吗?GitHub上的说明不太清楚。 - Name is Nilay

1
我将为那些使用相对布局的人提供另一种解决方案。
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class MainActivity extends Activity implements View.OnTouchListener
{
    private int       _xDelta;
    private int       _yDelta;
    private int       _rightMargin;
    private int       _bottomMargin;
    private ImageView _floatingView;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this._floatingView = (ImageView) findViewById(R.id.textView);

        this._floatingView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
        {
            @Override
            public boolean onPreDraw()
            {
                if (_floatingView.getViewTreeObserver().isAlive())
                    _floatingView.getViewTreeObserver().removeOnPreDrawListener(this);

                updateLayoutParams(_floatingView);
                return false;
            }
        });

        this._floatingView.setOnTouchListener(this);
    }

    private void updateLayoutParams(View view)
    {
        this._rightMargin = -view.getMeasuredWidth();
        this._bottomMargin = -view.getMeasuredHeight();

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(view.getMeasuredWidth(), view.getMeasuredHeight());
        layoutParams.bottomMargin = this._bottomMargin;
        layoutParams.rightMargin = this._rightMargin;

        view.setLayoutParams(layoutParams);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event)
    {
        if (view == this._floatingView)
        {
            final int X = (int) event.getRawX();
            final int Y = (int) event.getRawY();

            switch (event.getAction() & MotionEvent.ACTION_MASK)
            {
                case MotionEvent.ACTION_DOWN:
                    RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    this._xDelta = X - lParams.leftMargin;
                    this._yDelta = Y - lParams.topMargin;
                    break;

                case MotionEvent.ACTION_MOVE:
                    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    layoutParams.leftMargin = X - this._xDelta;
                    layoutParams.topMargin = Y - this._yDelta;
                    layoutParams.rightMargin = this._rightMargin;
                    layoutParams.bottomMargin = this._bottomMargin;
                    view.setLayoutParams(layoutParams);
                    break;
            }

            return true;
        }
        else
        {
            return false;
        }
    }
}

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