Differences between getLeft ()/ getX ()/ getRawX () of Android Custom View

Keywords: Android Java xml Mobile

When customizing View, if it involves sliding to change the position of the control or setting the position of the control manually, it will inevitably come into contact with getLeft() getX() getRawX(), then what are the differences among the three methods? Let's look at a picture first.

Let's look at the View.java source annotations
 

/**
     * Left position of this view relative to its parent.
     *
     * @return The left edge of this view, in pixels.
     */
    @ViewDebug.CapturedViewProperty
    public final int getLeft() {
        return mLeft;
    }


/**
     * The visual x position of this view, in pixels. This is equivalent to the
     * {@link #setTranslationX(float) translationX} property plus the current
     * {@link #getLeft() left} property.
     *
     * @return The visual x position of this view, in pixels.
     */
    @ViewDebug.ExportedProperty(category = "drawing")
    public float getX() {
        return mLeft + getTranslationX();
    }

As you can see from the source comment, View.getLeft() gets the distance from the View to the left of its ParentView. getX() gets the distance from the View to the left of its ParentView + the offset of the View to the left of its ParentView, which is 0 in the initial state, so the values of getLeft() and getX() in the initial state are the same.
Let's look at the annotations for getX() getRawX() in MotionEvent.java

/**
     * {@link #getX(int)} for the first pointer index (may be an
     * arbitrary pointer identifier).
     *
     * @see #AXIS_X
     */
    public final float getX() {
        return nativeGetAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
    }

/**
     * Returns the X coordinate of this event for the given pointer
     * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
     * identifier for this index).
     * Whole numbers are pixels; the 
     * value may have a fraction for input devices that are sub-pixel precise. 
     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
     * (the first pointer that is down) to {@link #getPointerCount()}-1.
     *
     * @see #AXIS_X
     */
    public final float getX(int pointerIndex) {
        return nativeGetAxisValue(mNativePtr, AXIS_X, pointerIndex, HISTORY_CURRENT);
    }

/**
     * Returns the original raw X coordinate of this event.  For touch
     * events on the screen, this is the original location of the event
     * on the screen, before it had been adjusted for the containing window
     * and views.
     *
     * @see #getX(int)
     * @see #AXIS_X
     */
    public final float getRawX() {
        return nativeGetRawAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
    }

Here we can see that getRawX() gets the X coordinates of the touch point in the screen of the mobile phone, so getX() seems not to be very well understood, in fact, it is the distance between the touch point and its left boundary. To prove this, I specifically wrote a Demo test, Custom View, a Relative Layout with two ImageView s, and print getX and getRawX values in OnTouch Event. The custom View code is as follows

package com.shadow.shadowwalker;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

public class CustomView extends RelativeLayout {
    private final String TAG = "CustomView";
    private View iv_left, iv_right;

    public CustomView(Context context) {
        this(context, null);
    }

    public CustomView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        View view = View.inflate(getContext(), R.layout.custom_view, this);
        iv_left = view.findViewById(R.id.iv_left);
        iv_right = view.findViewById(R.id.iv_rigth);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"event.getX() : " + event.getX() + "event.getRawX() : " + event.getRawX());
        return true;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_left"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerVertical="true"
        android:scaleType="centerCrop"
        android:src="@mipmap/ic_launcher" />

    <ImageView
        android:id="@+id/iv_rigth"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:scaleType="centerCrop"
        android:src="@mipmap/ic_launcher" />
</RelativeLayout>

When testing, place the custom View in the xml file of MainActivity, the code is as follows

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.shadow.shadowwalker.MainActivity">

    <com.shadow.shadowwalker.CustomView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_marginLeft="100dp" />
</android.support.constraint.ConstraintLayout>

Here I tested it on a 1920*1080 mobile phone. The layout_marginLeft= "100dp" set in the CustomView code means that the CustomView should be 300 pixels from the left side of the screen. So the value we got through getRawX() should be 300 pixels larger than getX(). Is that true? Let's see the test results?

When we set the layout_marginLeft of CustomView to 0, getX() and getRawX() should get the same value. Let's see the test results directly.

Summary: 1. In View. java, getLeft() gets the distance from View to the left of the parent control, and getX() gets the distance from View to the left of the parent control (initial Left) + the offset of View to the left of the parent control.
2. In MotionEvent. java, getX() obtains the distance between the touch point and the left boundary of the View, and getRawX() obtains the absolute position x value of the touch point in the screen.

Posted by pink on Sat, 29 Dec 2018 09:54:07 -0800