Magic Marbles
Magic Marbles

Reputation: 403

Android - HorizontalScrollView scrolls to the right when keyboard is opened

I have a general layout for my app in place, which includes a horizontal scroll view. What I'm doing is adding 32 fragments to the scroll view (which inflates into a vertical linear layout with two buttons and an editText. They're going to be controls for an equalizer).

The problem is, when I try to edit one of the editText's, the scrollview scrolls all the way to the right - so you're unable to see what you're typing into, and have to scroll all the way back to that entry to view it.

Here's the main xml layout. It splits the screen up into 4 quadrants, with the horizontal scroll view going in the bottom right:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="horizontal"
    tools:context=".MainActivity"
    android:focusable="true"
    android:focusableInTouchMode="true">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:padding="4dp"
        android:orientation="vertical"
        android:layout_weight="2"
        >
        <TextView android:text="Hello World!" android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="4"
        android:padding="4dp"
        android:orientation="vertical"
        android:background="#FF0000"
        >
        <TextView android:text="Hello World!"      android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


        <HorizontalScrollView
            android:id="@+id/hsv_eqControls"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="2dp"
            android:background="#FFFFFF"
            android:descendantFocusability="beforeDescendants"
            android:focusable="true"
            android:focusableInTouchMode="true"
            >

            <LinearLayout
                android:id="@+id/layout_eqControls"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="horizontal">

            </LinearLayout>

        </HorizontalScrollView>
    </LinearLayout>

</LinearLayout>

And this is what I'm adding into the scrollview

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="3dp"
    android:orientation="vertical">
    <Button
        android:id="@+id/btn_eqUp"
        android:layout_width="60dp"
        android:layout_height="60dp" />
    <EditText
        android:id="@+id/etext_eq"
        android:layout_width="60dp"
        android:layout_height="wrap_content"
        android:inputType="numberDecimal|numberSigned"
        android:textAlignment="center"
        android:layout_gravity="center_horizontal"
        android:background="#EEEEEE"
        android:hint="32dB"/>
    <Button
        android:id="@+id/btn_eqDown"
        android:layout_width="60dp"
        android:layout_height="60dp" />
    <TextView
        android:id="@+id/vtext_eqLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAlignment="center"
        android:layout_gravity="center"
        android:text="1"/>
</LinearLayout>

This is the code I'm running to fill the scrollview:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // View eqControls = findViewById(R.id.hsv_eqControls);

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        for(int i = 1; i < 33; i++)
        {
            ft.add(R.id.layout_eqControls, new FragmentEQ(), "ch"+i);
        }

        ft.commit();
        getFragmentManager().executePendingTransactions();
        for(int i = 1; i < 33; i++)
        {
            FragmentEQ feq = (FragmentEQ) getFragmentManager().findFragmentByTag("ch"+i);
            if(feq != null)
                feq.setChannel(i);
        }

    }
}

And this is the code for my fragment:

public class FragmentEQ extends Fragment {
    protected int _channel = 0;
    protected ViewGroup _parent;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                            Bundle savedInstanceState)
    {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.activity_fragment_eq, container, false);
        TextView label = (TextView) view.findViewById(R.id.vtext_eqLabel);

        label.setText(Integer.toString(_channel));
        return view;
    }

    public int getChannel() { return _channel; }

    public void setChannel(int i)
    {
        _channel = i;
    }
}

I've tried creating a custom HorizontalScrollView, and overriding scrollTo() and onRequestFocusInDescendants() as blank methods that do nothing, but this changes nothing.

public class EQScrollView extends HorizontalScrollView {

    public EQScrollView( Context context, AttributeSet attrs)
    {
        super(context, attrs);
        setSmoothScrollingEnabled(false);
    }

    @Override
    public void scrollTo(int x, int y)
    {

    }

    @Override
    public boolean onRequestFocusInDescendants(int x, Rect y)
    {

        return false;
    }

}

Upvotes: 3

Views: 802

Answers (3)

caopeng
caopeng

Reputation: 944

HorizontalScrollView always scroll to the right when I try to click the EditText

I have fixed the similar by the way below:

In my scenario

    <HorizontalScrollView
        android:id="@+id/id_HorizontalScrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/border_left_black_bold">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/id_RecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
    </HorizontalScrollView>
  • RecyclerView's item view:
<LinearLayout>
    <EditText
        android:id="@+id/id_edit"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="@drawable/border_right_black"
        android:gravity="center"
        android:inputType="number" />
<LinearLayout/>
  • Solution in my way:

Customize HorizontalScrollView and override the requestChildRectangleOnScreen method

    @Override
    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
        return true;
    }
    @Override
    protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
        return 0;
    }

root causes

Let's back to the Android source code.

  1. when the soft keyboard pop up. the size of layout changed View.java protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    /**
     * Called from layout when this view should
     * assign a size and position to each of its children.
     * ....
     */
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    }
  1. Then HorizontalScrollView.java protected void onLayout(boolean changed, int left, int top, int right, int bottom)

In this method, mIsLayoutDirty = false;

  1. HorizontalScrollView.java public void requestChildFocus(View child, View focused)

  2. HorizontalScrollView.java private void scrollToChild(View child)

  3. HorizontalScrollView.java

int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
if(scrollDelta!=0){
    scrollBy(scrollDelta, 0);
}

Upvotes: 0

A.J.Bauer
A.J.Bauer

Reputation: 3001

Using "setRawInputType":

setRawInputType(InputType.TYPE_CLASS_NUMBER);

solved the issue for me at first. After realizing that some number keyboards don't provide decimal input I ended up using standard text input for EditText, extending HorizontalScrollView and overriding "onRequestFocusInDescendants", "requestChildRectangleOnScreen" and "getFocusables" like so:

public class HorizontalScrollViewEx extends HorizontalScrollView {
    public HorizontalScrollViewEx(Context context) {
        super(context);
    }

    public HorizontalScrollViewEx(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    public HorizontalScrollViewEx(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
        return true;
    }

    @Override
    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
        return true;
    }

    @Override
    public ArrayList<View> getFocusables(int direction) {
        return new ArrayList<View>();
    }
}

Upvotes: 2

jampez77
jampez77

Reputation: 5241

I have just encountered this problem and for me the scrolling to the end only happens when android:inputType is not set in the EditText. If you remove this then the issue should vanish.

FYI even using .setInputType(InputType.TYPE_CLASS_NUMBER); produces this error.

Admittedly this isn't a fix but it's worth noting the cause.

Upvotes: 1

Related Questions