Android Touch-Based View Movement: Implementing ACTION_MOVE with RelativeLayout

Nov 24, 2025 · Programming · 8 views · 7.8

Keywords: Android Touch Events | RelativeLayout | View Dragging | ACTION_MOVE | LayoutParams

Abstract: This article provides an in-depth exploration of implementing view movement following finger touches in Android applications. By analyzing the optimal solution's implementation logic, it thoroughly examines core concepts including RelativeLayout container selection, touch event handling mechanisms, and view position calculation and updating. The article employs code refactoring and step-by-step explanations to help developers understand how to use onTouchListener to monitor ACTION_MOVE events and dynamically adjust view LayoutParams for smooth dragging effects. It also compares alternative approaches using ViewPropertyAnimator, offering references for implementations in different scenarios.

Technical Background and Problem Analysis

In Android application development, implementing view movement that follows user finger touches is a common interaction requirement. This functionality finds extensive application in scenarios such as game controls, custom sliders, and draggable elements. The core of the problem lies in accurately capturing touch events and updating view positions in real-time.

Container Selection and Layout Strategy

RelativeLayout is an ideal container choice for such requirements. Its relative positioning characteristics allow precise control over child view positions by adjusting margin parameters. Compared to other layouts, RelativeLayout offers more flexible position control methods, making it particularly suitable for scenarios requiring dynamic view position adjustments.

Core Implementation Mechanism

Implementing view dragging functionality requires handling several key aspects:

Touch Event Listener Setup

By implementing the View.OnTouchListener interface, you can register a touch event listener for the target view. Initialization is completed in the Activity's onCreate method:

dragView.setOnTouchListener(this);

Initial Position Recording

In the ACTION_DOWN event, you need to record the offset between the touch point and the view's current position:

case MotionEvent.ACTION_DOWN:
    RelativeLayout.LayoutParams currentParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
    initialXOffset = currentX - currentParams.leftMargin;
    initialYOffset = currentY - currentParams.topMargin;
    break;

Real-time Position Updates

In the ACTION_MOVE event, calculate the new view position based on the current touch position and initial offset:

case MotionEvent.ACTION_MOVE:
    RelativeLayout.LayoutParams newParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
    newParams.leftMargin = currentX - initialXOffset;
    newParams.topMargin = currentY - initialYOffset;
    view.setLayoutParams(newParams);
    break;

Detailed Code Implementation

The following complete implementation code includes necessary initialization and event handling logic:

public class DragActivity extends Activity implements View.OnTouchListener {
    TextView dragView;
    ViewGroup container;
    private int initialXOffset;
    private int initialYOffset;

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

        container = (ViewGroup) findViewById(R.id.container_layout);

        dragView = new TextView(this);
        dragView.setText("Draggable Text View");

        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(150, 50);
        params.leftMargin = 50;
        params.topMargin = 50;
        dragView.setLayoutParams(params);

        dragView.setOnTouchListener(this);
        container.addView(dragView);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        final int currentX = (int) event.getRawX();
        final int currentY = (int) event.getRawY();
        
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                RelativeLayout.LayoutParams currentParams = 
                    (RelativeLayout.LayoutParams) view.getLayoutParams();
                initialXOffset = currentX - currentParams.leftMargin;
                initialYOffset = currentY - currentParams.topMargin;
                break;
                
            case MotionEvent.ACTION_MOVE:
                RelativeLayout.LayoutParams newParams = 
                    (RelativeLayout.LayoutParams) view.getLayoutParams();
                newParams.leftMargin = currentX - initialXOffset;
                newParams.topMargin = currentY - initialYOffset;
                view.setLayoutParams(newParams);
                break;
        }
        
        container.invalidate();
        return true;
    }
}

Alternative Approach Analysis

In addition to the LayoutParams-based method described above, ViewPropertyAnimator can also be used to achieve similar functionality:

@Override
public boolean onTouch(View view, MotionEvent event) {
    float offsetX, offsetY;

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            offsetX = view.getX() - event.getRawX();
            offsetY = view.getY() - event.getRawY();
            break;

        case MotionEvent.ACTION_MOVE:
            view.animate()
                .x(event.getRawX() + offsetX)
                .y(event.getRawY() + offsetY)
                .setDuration(0)
                .start();
            break;
        default:
            return false;
    }
    return true;
}

Performance Optimization and Considerations

In practical development, the following optimization points should be considered:

Application Scenario Extensions

This technology can be extended to applications such as: custom progress bars, game character controls, drag functionality in image viewers, and custom keyboard layouts. By adjusting calculation logic and container types, various interaction requirements can be met.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.