android:移动触摸移动视图(ACTION_MOVE)

Zel*_*Ady 171 android touch

我想做一个简单的控制:一个内部有视图的容器.如果我触摸容器并移动手指,我想移动视图以跟随我的手指.

我应该使用什么样的容器(布局)?这该怎么做?

我不需要使用表面,而是简单的布局.

And*_*rey 338

我发现使用ViewPropertyAnimator可以轻松实现这一点:

float dX, dY;

@Override
public boolean onTouch(View view, MotionEvent event) {

    switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            dX = view.getX() - event.getRawX();
            dY = view.getY() - event.getRawY();
            break;

        case MotionEvent.ACTION_MOVE:

            view.animate()
                    .x(event.getRawX() + dX)
                    .y(event.getRawY() + dY)
                    .setDuration(0)
                    .start();
            break;
        default:
            return false;
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)

  • 如果某人对我的原因感到困惑,那么只知道getX()返回一个相对于视图的X坐标,而getRawX()则返回相对于设备屏幕的绝对坐标.http://stackoverflow.com/a/20636236/4258848 (11认同)
  • @ruan65 我可以限制视图不被拖出我的屏幕吗? (4认同)
  • Genius,只是添加了一些边界检查,它适用于滑动按钮的水平滚动 (2认同)
  • 虽然这与之前的答案一样,但最好在move事件中使用translationX和translationY方法.要使位置持久,请在"向上"事件中设置视图的布局属性.翻译方法使用手机的硬件层.布局属性不是. (2认同)
  • 我们也可以直接使用`setX`和`setY`,而不是应用持续时间为0的动画。 (2认同)

Vya*_*kin 230

像这样的东西:

public class MyActivity extends Activity implements View.OnTouchListener {

TextView _view;
ViewGroup _root;
private int _xDelta;
private int _yDelta;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    _root = (ViewGroup)findViewById(R.id.root);

    _view = new TextView(this);
    _view.setText("TextView!!!!!!!!");

    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(150, 50);
    layoutParams.leftMargin = 50;
    layoutParams.topMargin = 50;
    layoutParams.bottomMargin = -250;
    layoutParams.rightMargin = -250;
    _view.setLayoutParams(layoutParams);

    _view.setOnTouchListener(this);
    _root.addView(_view);
}

public boolean onTouch(View view, MotionEvent event) {
    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();
            _xDelta = X - lParams.leftMargin;
            _yDelta = Y - lParams.topMargin;
            break;
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            break;
        case MotionEvent.ACTION_POINTER_UP:
            break;
        case MotionEvent.ACTION_MOVE:
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
            layoutParams.leftMargin = X - _xDelta;
            layoutParams.topMargin = Y - _yDelta;
            layoutParams.rightMargin = -250;
            layoutParams.bottomMargin = -250;
            view.setLayoutParams(layoutParams);
            break;
    }
    _root.invalidate();
    return true;
}}
Run Code Online (Sandbox Code Playgroud)

main.xml刚刚RelativeLayout@+id/root

  • 它工作正常,但是有什么方法可以限制从屏幕外部的移动,这意味着只能在屏幕边界内移动。 (2认同)
  • @VyacheslavShilkin我在这段代码中发现的唯一问题是我无法使布局从xml文件中移出来移动.这真的是代码的问题,还是因为我的无知而失踪? (2认同)

Abd*_*shi 12

触摸容器,视图将跟随您的手指。

xml代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/floating_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <ImageView
      android:id="@+id/btn_chat"
      android:layout_width="42dp"
      android:layout_height="42dp"
      />
    
<LinearLayout>
Run Code Online (Sandbox Code Playgroud)

Java代码

public class DashBoardActivity extends Activity implements View.OnClickListener, View.OnTouchListener {
    
    float dX;
    float dY;
    int lastAction;
    LinearLayout floatingLayout;

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

        floatingLayout = findViewById(R.id.floating_layout);
        floatingLayout.setOnTouchListener(this);    
    
    
    
     @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                dX = view.getX() - event.getRawX();
                dY = view.getY() - event.getRawY();
                lastAction = MotionEvent.ACTION_DOWN;
                break;

            case MotionEvent.ACTION_MOVE:
                view.setY(event.getRawY() + dY);
                view.setX(event.getRawX() + dX);
                lastAction = MotionEvent.ACTION_MOVE;
                break;

            case MotionEvent.ACTION_UP:
                if (lastAction == MotionEvent.ACTION_DOWN)
                    Toast.makeText(DashBoardActivity.this, "Clicked!", Toast.LENGTH_SHORT).show();
                break;

            default:
                return false;
        }
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)


Jul*_*mez 9

按照@Andrey方法,如果要从中心移动视图,则只需将视图的半高和宽度减去运动.

float dX, dY;

@Override
public boolean onTouchEvent(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            dX = view.getX() - event.getRawX();
            dY = view.getY() - event.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:
            view.animate()
                .x(event.getRawX() + dX - (view.getWidth() / 2))
                .y(event.getRawY() + dY - (view.getHeight() / 2))
                .setDuration(0)
                .start();
            break;
        default:
            return false;
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)


Mis*_*agh 8

创建自定义触摸侦听器类(在 Kotlin 中):

(此代码限制您的视图拖出其父视图)

class CustomTouchListener(
  val screenWidth: Int, 
  val screenHeight: Int
) : View.OnTouchListener {
    private var dX: Float = 0f
    private var dY: Float = 0f

    override fun onTouch(view: View, event: MotionEvent): Boolean {

        val newX: Float
        val newY: Float

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                dX = view.x - event.rawX
                dY = view.y - event.rawY
            }
            MotionEvent.ACTION_MOVE -> {

                newX = event.rawX + dX
                newY = event.rawY + dY

                if ((newX <= 0 || newX >= screenWidth - view.width) || (newY <= 0 || newY >= screenHeight - view.height)) {
                    return true
                }

                view.animate()
                    .x(newX)
                    .y(newY)
                    .setDuration(0)
                    .start()
            }
        }
        return true
    }
}
Run Code Online (Sandbox Code Playgroud)

如何使用它?

parentView.viewTreeObserver.addOnGlobalLayoutListener { view.setOnTouchListener(CustomTouchListener(parentView.width, parentView.height)) }
Run Code Online (Sandbox Code Playgroud)

parentView 是您视图的父级。


Hit*_*ahu 5

Kotlin 中的相同实现

    rightPanel.setOnTouchListener(View.OnTouchListener { view, event ->
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {

                rightDX = view!!.x - event.rawX
                // rightDY = view!!.getY() - event.rawY;

            }
            MotionEvent.ACTION_MOVE -> {

                var displacement = event.rawX + rightDX

                view!!.animate()
                        .x(displacement)
                        // .y(event.getRawY() + rightDY)
                        .setDuration(0)
                        .start()
            }
            else -> { // Note the block
                return@OnTouchListener false
            }
        }
        true
 })
Run Code Online (Sandbox Code Playgroud)

  • 这个答案的有趣之处在于我写了它并且它多次帮助了我。 (4认同)