android: mover una vista al tocar mover (ACTION_MOVE)

6 minutos de lectura

Me gustaría hacer un control simple: un contenedor con una vista interior. Si toco el contenedor y muevo el dedo, quiero mover la vista para seguir mi dedo.

¿Qué tipo de contenedor (diseño) debo usar? ¿Como hacer esto?

No necesito usar una superficie, sino un diseño simple.

android mover una vista al tocar mover ACTION MOVE
Andrés

Encontré un enfoque fácil para hacerlo con 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;
}

  • @ ruan65 ¿puedo restringir la vista para que no me arrastren de la pantalla?

    –Dhiraj Devkar

    02/12/2015 a las 11:30

  • Si alguien estaba tan confundido como yo sobre por qué esto funciona, entonces sepa que getX() devuelve una coordenada X relativa a la vista, mientras que getRawX() devuelve una coordenada absoluta, relativa a la pantalla del dispositivo. stackoverflow.com/a/20636236/4258848

    – Amer Mograbi

    21 de diciembre de 2016 a las 8:27


  • Genius, acabo de agregar algunas comprobaciones de límites y funciona muy bien para el desplazamiento horizontal de un botón deslizante

    – Hombre malo

    6 de marzo de 2017 a las 15:14

  • Si bien esto funciona igual que la respuesta anterior, es mejor usar los métodos translationX y translationY en su evento de movimiento. Para hacer que la posición sea persistente, establezca las propiedades de diseño de la vista en el evento “arriba”. Los métodos de traducción utilizan la capa de hardware de su teléfono. Propiedades de diseño no.

    – Gillis Haasnoot

    28 de abril de 2017 a las 7:53


  • También podemos usar setX y setY directamente, en lugar de aplicar una animación de duración 0.

    – usuario1032613

    8 oct 2018 a las 19:31

android mover una vista al tocar mover ACTION MOVE
Viacheslav Shylkin

Algo como esto:

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;
}}

En main.xml sólo RelativeLayout con @+id/root

  • @appserv: ¡Buen trabajo! Pero me pregunto por qué pones layoutPrarms.rightMargin = -250 y lo mismo con bottomMargin!! ¿Puedes explicarlo? ¡¡De todos modos, muchas gracias!!

    – Martín pescador Phuoc

    8 de julio de 2012 a las 15:28

  • Si mi memoria no me falla, sin estos valores, la vista se comprimirá al moverla hacia la derecha o hacia abajo. Puedes intentar cambiarlos y ver qué pasa.

    – Viacheslav Shylkin

    8 de julio de 2012 a las 18:44

  • No tienen que ser definitivos. Los hice finales solo para evitar reasignar estas variables.

    – Viacheslav Shylkin

    8 de julio de 2013 a las 9:25

  • Funciona bien, pero ¿hay alguna forma de restringir el movimiento desde fuera de la pantalla, lo que significa que debe moverse solo dentro de los límites de la pantalla?

    –Daud Arfin

    19 de octubre de 2013 a las 4:34

  • @VyacheslavShilkin El único problema que encontré en este código es que no pude hacer diseños inflados desde un archivo xml para mover. ¿Es este realmente el problema del código o me estoy perdiendo debido a mi ignorancia?

    – usuario2498079

    30 de julio de 2014 a las 13:14

1646748314 226 android mover una vista al tocar mover ACTION MOVE
Abdul Basit Rishi

Toque el contenedor y la vista seguirá su dedo.

codigo 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>

codigo 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;
    }
}

1646748314 796 android mover una vista al tocar mover ACTION MOVE
julio gómez

Siguiendo el enfoque de @Andrey, si desea mover la vista desde su centro, solo tiene que restar la mitad de la altura y el ancho de la vista al movimiento.

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;
}

1646748315 909 android mover una vista al tocar mover ACTION MOVE
Misagh

Cree una clase de oyente táctil personalizada (en Kotlin):

(Este código impide que su vista se arrastre fuera de su vista principal)

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
    }
}

¿Cómo usarlo?

parentView.viewTreeObserver.addOnGlobalLayoutListener { view.setOnTouchListener(CustomTouchListener(parentView.width, parentView.height)) }

parentView es el padre de su vista.

  • ¡Genial!, y una solución simple para kotlin.

    – Arbaz.in

    28 de septiembre de 2020 a las 5:47

Misma implementación en 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
 })

  • ¡Genial!, y una solución simple para kotlin.

    – Arbaz.in

    28 de septiembre de 2020 a las 5:47

android mover una vista al tocar mover ACTION MOVE
jonny derecho

Recomiendo usar view.translationX y view.translationY para mover sus vistas.

Fragmento de Kotlin:

yourView.translationX = xTouchCoordinate
yourView.translationY = yTouchCoordinate

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad