androidandroid-activityandroid-edittextadjustpansetx

View.setX prevents adjustPan from working


I am programmatically setting the x value of an edittext. However, in doing so the adjust pan function does not work. Any ideas on how to make this work. The activity is not in full-screen mode and this only happens in APIs > 23.

Ex.

Edittext editext = findViewById(R.id.edittext);
edittext.setX(200);

//Clicking on edittext now, gets covered by the soft keyboard if it low enough on screen

Note: this also happens with setY()

Here is an example to reproduce the error:

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

        //Get edittext from layout file and set X and Y to the bottom
        //left of screen
        EditText edittext = findViewById(R.id.editText);
        edittext.setX(0);

        //Getting device frame to make sure its below keyboard, Not
        //necessary can just guess any value 
        edittext.setY(getDeviceFrame(context).getHeight() / 1.2f);
    }

With a layout of :

<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="Name"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

And a manifest of :

<activity android:name=".MainActivity"
    android:windowSoftInputMode="adjustPan">
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category 
                android:name="android.intent.category.LAUNCHER"/>
         </intent-filter>
</activity>

Resulting in a layout : Edittext after programmatic setX and setY

And after clicking on editext we get : Hidden editext

Which you can see is hidden by the keyboard.

UPDATE : I have tried to use the different variations to moving the EditText with still no avail.

Ex.

edittext.animate().x(200);

UPDATE 2: I have yet to solve this issue. I have been getting closer as I have done some test and it appears that using layout params to control the positioning of the view works to an extent.

Ex.

ConstraintLayout.LayoutParams layoutParams = 
    (ConstraintLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = 200;  //Your X Coordinate
layoutParams.topMargin = 200;  //Your Y Coordinate
view.setLayoutParams(layoutParams);

By some extent, I mean I have messed around with the functionality of these methods in a test library and it seems to work doing the above from onCreate(). However, in my app, I am doing the call in a callback. SetX works fine without me having to set it in a 'post' thread or 'runOnMainUI' thread. So I am not sure why this is not working.


Solution

  • Okay, so I figured out how to solve the issue. Using the answer from my "Update 2" above I was able to get the solution with a little tweaking.

    This code:

    ConstraintLayout.LayoutParams layoutParams = 
        (ConstraintLayout.LayoutParams) view.getLayoutParams();
    layoutParams.leftMargin = 200;  //Your X Coordinate
    layoutParams.topMargin = 200;  //Your Y Coordinate
    view.setLayoutParams(layoutParams);
    

    (You can use whatever Layout you are using instead of Constraint)

    Is an alternative to setX() and setY() and allows adjustPan to work. However, getting the views x or y positioning with :

    view.getX();
    view.getY();
    

    Will not return the visual positioning of the view. You need to get the view's position by getting the layout params associated with the view and getting its margins.

    Now what I came to realize and is key for the Constraint Layout is that you MUST have the constraint defined in xml or via code.

    Ex.

    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    

    Having this allows the margins to have a reference to what it was extended from, without this, the positioning of the view with not move.