Остановить ScrollView от автоматической прокрутки до EditText - PullRequest
41 голосов
/ 30 мая 2011

Кажется, это обычная проблема без отличного решения, которое я нашел.Цель состоит в том, чтобы остановить ScrollView от автоматической прокрутки до EditText (или любого представления в этом отношении) с фокусом.

У вас есть несколько просмотров (Button s, TextView)s и т. д.) в ScrollView, одним из которых является EditText.При нажатии, скажем, на кнопку в пределах ScrollView, ScrollView прокручивается вниз до EditText (вне экрана).Это нежелательно, так как есть другие элементы, которые вы не хотите прокручивать с экрана.

Теперь я могу не допустить этого, когда на экране впервые появятся другие фокусируемые элементы в ScrollView.Тем не менее, общая проблема все еще существует.Пользователь прокручивает вручную до EditText, вводит некоторые цифры, затем прокручивает вверх (вверху экрана EditText), нажимает кнопку в ScrollView, и угадайте, что?ScrollView прокручивается до этого проклятого EditText.

Я думаю о расширении ScrollView и переопределении некоторых из методов, таких как findFocusableViewInBounds, но у меня есть ощущение, что я простоУ меня больше проблем.

Пожалуйста, помогите, если можете.

Я поиграл с такими вещами, как наличие высоты 0 EditText в верхней части моего ScrollView, добавление свойств элемента Next Focusable к другим элементам в ScrollView и т. Д. Я полагаю, один«Взломать» может означать, что EditText потеряет фокус, когда виртуальная или ручная клавиатура будет скрыта или что-то в этом роде.

Ответы [ 21 ]

35 голосов
/ 26 июня 2011

Поработав с этой проблемой в течение достаточно долгого времени, я нашел решение, которое, кажется, работает, не будучи слишком уродливым. Во-первых, убедитесь, что все, что ViewGroup (непосредственно) содержит ваше EditText, имеет descendantFocusability, установленное в значение «Перед потомками», focusable, установленное в значение «истина» и focusableInTouchMode, установленное в значение «истина». Это будет не сам ScrollView, а макет внутри, где у вас есть различные виды. Затем добавьте onTouchListener к вашему ScrollView, который удаляет фокус с EditText при каждом прикосновении, например:

ScrollView scroll = (ScrollView)findViewById(R.id.scrollView1);
scroll.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (myEditText.hasFocus()) {
            myEditText.clearFocus();
        }
        return false;
    }
});

Скажи мне, если это не исправит. Что должно произойти, так это то, что Layout получает фокус вместо EditText, поэтому прокрутка не должна происходить.

20 голосов
/ 26 июля 2013

Просто создайте пустое представление в верхней части линейного макета

<View android:layout_width="fill_parent" android:id="@+id/focus_view" android:layout_height="0dp" android:focusable="true" android:focusableInTouchMode="true"><requestFocus/></View>

Одна строка решает проблему

9 голосов
/ 30 мая 2011

У меня была такая же проблема.Есть одна хитрость, которую я использую для решения этой проблемы:

public void onClick(View v) {
    button.requestFocusFromTouch(); //prevents from loosing focus and scrolling view down
    ....
}
8 голосов
/ 28 мая 2013

Проблема не в коде Java, а в коде манифеста.

В вашем AndroidManifest.xml добавьте атрибут в Activity:

        <activity android:name=".MyActivity" android:windowSoftInputMode="adjustPan"> </activity>
7 голосов
/ 23 июня 2016

При добавлении 2-х параметров в:

android:focusable="true"
android:focusableInTouchMode="true"

В котором находится основной макет.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layMain"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background"
    android:focusable="true"
    android:focusableInTouchMode="true">

При этом EditText не будет автоматически фокусироваться.

4 голосов
/ 11 сентября 2011

Вот что я сделал

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" style="@style/measurementTableRowStyle"
    android:focusable="true" android:layout_height="fill_parent">
    <requestFocus></requestFocus>
    <LinearLayout android:id="@+id/linearLayout1"
        android:orientation="horizontal" android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView android:id="@+id/desc_text" android:text="Value : "
            style="@style/attributeNameTextStyle" android:layout_width="wrap_content"
            android:focusable="true" android:layout_height="wrap_content">
            <requestFocus></requestFocus>
        </TextView>

        <TextView style="@style/attributeValueStyle" android:id="@+id/value_text"
            android:text="TextView" android:layout_width="wrap_content"
            android:layout_height="wrap_content"></TextView>
    </LinearLayout>

Причина в том, что в таких случаях вы должны сделать все другие виды фокусируемыми внутри прокрутки с помощью явного android:focusable="true", а затем <requestFocus></requestFocus>.Это должно работать каждый раз, когда ИМО

2 голосов
/ 04 декабря 2013

Мое исправление этой самой ужасной ошибки (стоит отметить, что это было до API11 только там, где они изменили метод fling, чтобы не быть глупым).

Старый метод fling находит следующий фокус, который он получитк ... что не очень полезно.Другие версии этого класса на самом деле не работают, так как перестают работать с фокусом, когда пользователь искренне пересекает форму с клавиатуры.

public class NonFocusingScrollView extends ScrollView {

    private boolean mBlockRequestFocusOnFling = false;

    public NonFocusingScrollView(Context context) {
        super(context);
    }

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

    public NonFocusingScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

    @Override
    public void requestChildFocus(View child, View focused) {
        if(!mBlockRequestFocusOnFling)
        super.requestChildFocus(child, focused);
    }


    @Override
    public void fling(int velocityY) {
        mBlockRequestFocusOnFling = true;
        super.fling(velocityY);
        mBlockRequestFocusOnFling = false;
    }
}
2 голосов
/ 14 августа 2012

thomas88wp answer, https://stackoverflow.com/a/6486348/528746 работал для меня. Но у меня было две проблемы: 1. При прокрутке я хотел спрятать клавиатуру
2. У меня было много просмотров EditText, и я не хотел писать его для каждого из них
(Я делаю getActivity (), так как пишу это внутри фрагмента, а не действия)

    ScrollView scroll = (ScrollView)view.findViewById(R.id.layout_scroll);
    scroll.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // Check if the view with focus is EditText
            if (getActivity().getCurrentFocus() instanceof EditText)
            {
                EditText ed = (EditText)getActivity().getCurrentFocus();
                if (ed.hasFocus()) {

                    // Hide the keyboard
                    InputMethodManager inputManager = (InputMethodManager)
                            getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); 
                    inputManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
                            InputMethodManager.HIDE_NOT_ALWAYS);
                    // Clear the focus
                    ed.clearFocus();
                }
            }
            return false;
        }

    });
1 голос
/ 04 апреля 2013

Другая версия кода thomas88wp:

ScrollView scroll = (ScrollView)getActivity().findViewById(R.id.scrollView_addNewBill);
    scroll.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) {        
            View focussedView = getCurrentFocus(); 
            if( focussedView != null ) focussedView.clearFocus();
                
            return false;
    }
});
1 голос
/ 31 декабря 2011

Мы можем написать собственный ScrollView и переопределить метод onScrollChanged , очистить фокус от сфокусированного вида и дополнительно скрыть клавиатуру.

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    View v = getFocusedChild();
    if (v != null) {
        InputMethodManager imm = (InputMethodManager) getContext()
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
        v.clearFocus();
    }
    super.onScrollChanged(l, t, oldl, oldt);
}
...