studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones android android-edittext scrollview autoscroll

android - programacion - Detener ScrollView del desplazamiento automático a un EditText



manual de programacion android pdf (20)

Parece ser un problema común sin una gran solución que he encontrado. El objetivo es evitar que un ScrollView desplace automáticamente a un EditText (o cualquier vista) que tenga el foco.

Tiene un montón de vistas ( Button s, TextView s, etc.) en un ScrollView , una de las cuales es un EditText . Al hacer clic en decir un botón dentro de ScrollView , ScrollView desplaza hacia abajo hasta EditText (no está en la pantalla). Esto no se desea, ya que hay otros elementos que no desea que se desplacen de la pantalla.

Ahora puedo evitar que esto suceda cuando la pantalla se muestra por primera vez al tener otros elementos enfocables en el ScrollView . Sin embargo, el problema general todavía existe. El usuario se desplaza hacia abajo manualmente hasta EditText , ingresa algunos números, luego se desplaza hacia arriba ( EditText fuera de la pantalla ahora), hace clic en un botón en el ScrollView y adivina qué? El ScrollView desplaza hacia abajo a ese maldito EditText .

Estoy pensando en extender el ScrollView y anular algunos de los métodos que existen como findFocusableViewInBounds , pero tengo la sensación de que me estaré metiendo en más problemas.

Por favor ayuda si puedes.

He jugado un poco con cosas como tener un EditText altura 0 en la parte superior de mi ScrollView , agregar las propiedades del siguiente elemento enfocable a los otros elementos en el ScrollView , etc. Supongo que un "truco" podría ser para que el EditText pierda el foco. Cuando el teclado virtual o manual se oculta o algo así.


A menudo tengo este problema cuando mis aplicaciones manejan el cambio de orientación.

En ese caso utilizo el siguiente tipo de código:

@Override protected void onCreate(Bundle savedInstanceState) { ... // to avoid the scrollview to scroll to this element automatically mEditTextSearch.setFocusable(false); // Get the saved scroll position final int scrolly = savedInstanceState.getInt("scrolly"); mScrollView.post(new Runnable() { @Override public void run() { mScrollView.scrollTo(0, scrolly); // Restore the initial state of the EditText mEditTextSearch.setFocusable(true); mEditTextSearch.setFocusableInTouchMode(true); mEditTextSearch.setClickable(true); } }); ... }


Añadiendo 2 parámetros en:

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

En qué diseño principal está allí.

<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">

Por este EditText no se enfocará automáticamente.


Aquí esta lo que hice

<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>

La razón es que, en tales casos, debe hacer que todas las demás vistas puedan enfocarse dentro de la vista de desplazamiento mediante un android:focusable="true" explícito android:focusable="true" y luego <requestFocus></requestFocus> . Esto debería funcionar siempre IMO


Cree un ScrollView personalizado (cree una clase y haga que extienda HorizontalScrollView) y haga un configurador de obtención para el desplazamiento. Luego, anule computeScrollDeltaToGetChildRectOnScreen.

Cómo funciona: cada vez que Android tiene un texto de edición o algo enfocado que está fuera de la pantalla, llama al método computeScrollDeltaToGetChildRectOnScreen para ponerlo a la vista. Si lo reemplaza y devuelve 0 cuando está desactivado, no se desplazará ...

Así que tendrás una vista de desplazamiento personalizada como esta:

public class TrackableHorizontalScrollView extends HorizontalScrollView { // true if we can scroll (not locked) // false if we cannot scroll (locked) private boolean mScrollable = true; public TrackableHorizontalScrollView(Context context) { super(context); } public TrackableHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public TrackableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setScrollingEnabled(boolean enabled) { mScrollable = enabled; } public boolean isScrollable() { return mScrollable; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // if we can scroll pass the event to the superclass if (mScrollable) return super.onTouchEvent(ev); // only continue to handle the touch event if scrolling enabled return mScrollable; // mScrollable is always false at this point default: return super.onTouchEvent(ev); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // Don''t do anything with intercepted touch events if // we are not scrollable if (!mScrollable) return false; else return super.onInterceptTouchEvent(ev); } @Override public void scrollTo(int x, int y){ if (!mScrollable) return; super.scrollTo(x, y); } //Custom smooth scroll method since norm is final and cannot be overridden public final void smooothScrollToIfEnabled(int x, int y){ if (!mScrollable) return; smoothScrollTo(x, y); } @Override protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect rect){ if (!mScrollable) return 0; return super.computeScrollDeltaToGetChildRectOnScreen(rect); } }

Puedes usar esto dentro de tu XML de esta manera:

<com.your.package.ui.widget.TrackableHorizontalScrollView android:id="@+id/wi_et_credit_scroller" android:layout_toRightOf="@id/wi_et_credit_iv" android:layout_width="fill_parent" android:scrollbars="none" android:layout_height="wrap_content" android:paddingRight="5dp" android:layout_gravity="center_vertical"> <!--Whatever you have inside the scrollview--> </com.your.package.ui.widget.TrackableHorizontalScrollView>


Después de luchar con ese problema durante bastante tiempo, he encontrado una solución que parece funcionar sin ser demasiado fea. En primer lugar, asegúrese de que cualquier grupo de ViewGroup (directamente) contenga su EditText tiene la EditText descendantFocusability establecida en "Antes de los descendientes", el conjunto focusable en "verdadero" y el modo de EditText en "verdadero". Este no será el ScrollView sí, sino el diseño en el que tiene sus distintas vistas. A continuación, agregue un onTouchListener a su ScrollView que elimine el foco del EditText cada vez que se toque, de esta manera:

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; } });

Dime si eso no lo arregla. Lo que debería suceder es que el diseño se centre en lugar del texto de EditText , por lo que no debería ocurrir ningún desplazamiento.


El problema no está en el código java, sino en el código manifiesto.

En su AndroidManifest.xml agregue un atributo a la Actividad:

<activity android:name=".MyActivity" android:windowSoftInputMode="adjustPan"> </activity>


Estaba teniendo un problema similar y finalmente lo puse a trabajar. Mi vista de desplazamiento contiene una serie de botones personalizados, seguidos de un texto de EditText (que normalmente tiene el foco, pero no quiero que pierda el foco). Cada vez que se hacía clic en los botones, la vista de desplazamiento se desplazaba automáticamente al EditText enfocado. La public boolean requestChildRectangleOnScreen(final View child, final Rect rectangle, final boolean immediate) y siempre devolviendo false (comportamiento predeterminado de un ViewGroup de ViewGroup ) hizo el truco. Espero que te ayude con tu situación también.



La mejor solución es agregar opciones de enfoque para el niño de su vista de desplazamiento:

android:descendantFocusability="beforeDescendants" android:focusable="true" android:focusableInTouchMode="true"

Entonces su archivo xml se verá como:

<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginRight="50dp" android:descendantFocusability="beforeDescendants" android:focusable="true" android:focusableInTouchMode="true" android:orientation="vertical" > <EditText android:id="@+id/editText_one" android:layout_width="match_parent" android:layout_height="100dp" android:text="TestApp 1" /> <EditText android:id="@+id/editText_two" android:layout_width="match_parent" android:layout_height="100dp" android:text="TestApp 2" /> <EditText android:id="@+id/editText_three" android:layout_width="match_parent" android:layout_height="100dp" android:text="TestApp 3" /> </LinearLayout> </ScrollView>


La respuesta de thomas88wp, https://.com/a/6486348/528746 funcionó para mí. Pero tuve dos problemas: 1. Al desplazarme, quería ocultar el teclado.
2. Tenía muchas vistas de EditText y no quería escribirlas para cada una de ellas.
(Obtuve Actividad () ya que estoy escribiendo esto dentro de un Fragmento y no una actividad)

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; } });


Mi solución a este error más horrible, (vale la pena señalar que esto es pre API11 solo cuando modificaron el método de lanzamiento para que no fuera estúpido).

El viejo método de lanzamiento encuentra el siguiente enfoque al que llegará ... lo que no es realmente tan útil. Las otras versiones de esta clase no funcionan realmente, ya que dejan de funcionar el enfoque cuando el usuario realmente cruza el formulario desde el teclado.

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; } }


Mi solución está a continuación, para rastrear el código fuente y anular alguna función para detener el desplazamiento automático por elemento centrado.

Puede verificar si focusedView es TextView o si su hijo es TextView, utilizando focusedView.findViewById(R.id.textview_id_you_defined) != null focusedView instanceof TextView == true o focusedView instanceof TextView == true .

public class StopAutoFocusScrollView extends ScrollView { private View focusedView; private ScrollMonitorListener listener; public interface ScrollMonitorListener { public boolean enableScroll(View view); } public StopAutoFocusScrollView(Context context) { super(context); } public StopAutoFocusScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public StopAutoFocusScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setScrollMonitorListener(ScrollMonitorListener listener) { this.listener = listener; } @Override public void requestChildFocus(View child, View focused) { focusedView = focused super.requestChildFocus(child, focused); } //flow : requestChildFocus -> scrollToChild -> scrollBy //Therefore, you can give listener to determine you want scroll to or not @Override public void scrollBy(int x, int y) { if (listener == null || listener.enableScroll(focusedView)) { super.scrollBy(x, y); } } }


Otra versión del código de 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; } });


Para mí, no funcionó anular ScrollView onTouch. Tampoco funcionó android: descendantFocusability = "beforeDescendants" android: focusableInTouchMode = "true" Esta y otras soluciones mencionadas solo funcionaron por primera vez, solo cuando EditText no está seleccionado, pero una vez que lo seleccionas, scrollview se vuelve a enrollar automáticamente.

Como ya había escrito un código para ocultar un teclado al tocar otras vistas, solo agregué dos líneas de código y funcionó como un campeón:

public static void setupUI(final Activity activity, final View view) { //view is the parent view in your layout OnTouchListener mTouchListener = new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { try { View vFocused = null; vFocused = activity.getCurrentFocus(); if (vFocused != null) { hideSoftKeyboard(activity, v); if (vFocused instanceof EditText) { vFocused.clearFocus();//this is the trick to avoid ScrollView autoscroll } } } catch (Exception e) { } return false; } }; // Set up touch listener for non-text box views to hide keyboard. if (!(view instanceof EditText) && !(view instanceof ViewGroup)) { view.setOnTouchListener(mTouchListener); } // If a layout container, iterate over children and seed recursion. if (view instanceof ViewGroup) { view.setOnTouchListener(mTouchListener); for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { View innerView = ((ViewGroup) view).getChildAt(i); setupUI(activity, innerView); } } } public static void hideSoftKeyboard(Context context, View v) { InputMethodManager inputMethodManager = (InputMethodManager) context .getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0); }

También agregó esto en la vista raíz:

android:descendantFocusability="beforeDescendants" android:focusableInTouchMode="true"

Tal vez no sea realmente una buena solución, pero está funcionando.


Podemos escribir un ScrollView personalizado y anular el método onScrollChanged , borrar el enfoque de la vista enfocada y, opcionalmente, ocultar el teclado.

@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); }


Prueba este :)

public class CustomHorizontalScrollView extends HorizontalScrollView { public CustomHorizontalScrollView(Context context) { super(context); } public CustomHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onTouchEvent(MotionEvent ev) { return super.onTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } @Override public void scrollTo(int x, int y) { super.scrollTo(x, y); } //Custom smooth scroll method since norm is final and cannot be overridden public final void smooothScrollToIfEnabled(int x, int y) { smoothScrollTo(x, y); } @Override protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect rect) { /* if (getContext() != null && getContext() instanceof Activity) { Activity activity = (Activity) getContext(); if (!activity.isFinishing()) { View view = activity.getCurrentFocus(); if (view != null) { if (view instanceof EditText) { return 0; } } } } return super.computeScrollDeltaToGetChildRectOnScreen(rect); */ return 0; } }


Sólo este código funciona para mí:

public static void preventScrollViewFromScrollingToEdiText(ScrollView view) { view.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); view.setFocusable(true); view.setFocusableInTouchMode(true); view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { v.requestFocusFromTouch(); return false; } }); }

Todos los créditos van a esta respuesta original .


Solo crea una vista vacía en la parte superior de linearlayout

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

Una sola línea resuelve el problema


Tuve una objeción ligeramente diferente a esta deficiente exasperación. Cada vez que pulsaba uno de varios RadioButtons debajo de EditTexts, la posición de desplazamiento saltaba para adaptarse a lo que Android determinó que era el EditText visible y enfocado.

Todos los intentos de conservar la posición de desplazamiento actual deseada a través de un Runnable que emitió ScrollView.scrollTo(x,y) fueron IGNORADOS debidamente por Android.

Comparto mi solución con la esperanza de que pueda ahorrarle a otra persona 8 (ocho) horas perdidas.

/* This interesting little ''hack'' prevents unwanted scroll ''jump'' occurring when user touches a RadioButton for example [ Causes focus to change - but maybe this is a lesser evil! ] */ mScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_UP) return false; mScrollView.clearFocus(); return false; } });


Yo tuve el mismo problema. Hay un truco que estoy usando para lidiar con este problema:

public void onClick(View v) { button.requestFocusFromTouch(); //prevents from loosing focus and scrolling view down .... }