¿Deshabilitar ScrollView mediante programación?

108

Me gustaría habilitar ScrollView y deshabilitarlo con un clic de botón.
Deshabilitar significa como si ScrollView no estuviera allí ... y habilitarlo devuelve ScrollView.

Quiero eso porque tengo una galería con imágenes de texto, y en un botón, haga clic en los cambios de orientación de la pantalla, por lo que en Paisaje el texto se agranda. Y quiero ScrollView para que la imagen no se estire y el texto se vuelva ilegible.

scrollview.Enabled=false / setVisibility(false) no hace nada.

xml:

<ScrollView 
android:id="@+id/QuranGalleryScrollView" 
android:layout_height="fill_parent" 
android:layout_width="fill_parent">
<Gallery android:id="@+id/Gallery" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent"
android:scrollbars="horizontal"></Gallery>
</ScrollView>

Gracias

Edit1: No puedo usar Visibility (desaparecido) ya que eso también ocultaría la Galería, lo que quiero es ocultar el efecto de ScrollView. Cuando hay ScrollView, las imágenes en la Galería se vuelven desplazables y no caben en la pantalla, por lo que debe desplazarse para ver la imagen completa, no quiero deshabilitar / habilitar eso con un clic de botón.

Probé esto:

((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setOnTouchListener(null);
                        ((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setHorizontalScrollBarEnabled(false);
                        ((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setVerticalScrollBarEnabled(false);
                        ((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setEnabled(false);

Pero aún así, las imágenes de la Galería se pueden desplazar y no se ajustan a la pantalla. ¿Cuál es la solución a esto?

Omar
fuente

Respuestas:

187

Varios puntos para empezar:

  1. No puede deshabilitar el desplazamiento de un ScrollView. Debería extenderse a ScrollView y anular el onTouchEventmétodo para volver falsecuando se cumple alguna condición.
  2. El componente Galería se desplaza horizontalmente independientemente de si está en un ScrollView o no: un ScrollView proporciona solo desplazamiento vertical (necesita un HorizontalScrollView para el desplazamiento horizontal)
  3. Parece decir que tiene un problema con el estiramiento de la imagen en sí; esto no tiene nada que ver con el ScrollView, puede cambiar cómo un ImageView se escala con la android:scaleTypepropiedad (XML) o el setScaleTypemétodo; por ejemplo ScaleType.CENTER, no estirará su imagen y lo hará céntrelo en su tamaño original

Puede modificar de la ScrollViewsiguiente manera para deshabilitar el desplazamiento

class LockableScrollView extends ScrollView {

    ...

    // true if we can scroll (not locked)
    // false if we cannot scroll (locked)
    private boolean mScrollable = true;

    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
                return mScrollable && super.onTouchEvent(ev);
            default:
                return super.onTouchEvent(ev);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // Don't do anything with intercepted touch events if
        // we are not scrollable
        return mScrollable && super.onInterceptTouchEvent(ev);
    }

}

Entonces usarías

<com.mypackagename.LockableScrollView 
    android:id="@+id/QuranGalleryScrollView" 
    android:layout_height="fill_parent" 
    android:layout_width="fill_parent">

    <Gallery android:id="@+id/Gallery" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:scrollbars="horizontal">
    </Gallery>

</com.mypackagename.LockableScrollView>

en su archivo XML (acaba de cambiar ScrollViewa su especial LockableScrollView).

Luego llame

((LockableScrollView)findViewById(R.id.QuranGalleryScrollView)).setScrollingEnabled(false);

para deshabilitar el desplazamiento de la vista.

Creo que tiene algo más que el problema de deshabilitar el desplazamiento para lograr el resultado deseado (la galería seguirá siendo desplazable con el código anterior, por ejemplo); recomendaría investigar un poco más sobre cada uno de los tres componentes (Galería, ScrollView, ImageView) para ver qué propiedades tiene cada uno y cómo se comporta.

Joseph Earl
fuente
Así es como se ve la clase: pastebin.com/dsWSWR4x Pero aparece el error 'El método onTouch (View, MotionEvent) de tipo LockableScrollView debe anular o implementar un método de supertipo'
Omar
Disculpas, corregí los errores en mi código - debería haber sidoonTouchEvent(MotionEvent ev)
Joseph Earl
1
Ok, ahora el código cumple, aunque cuando ejecuto la aplicación se bloquea ... y cuando elimino esta clase y devuelvo <ScrollView en lugar de su clase, ¡la aplicación funciona bien!
Omar
Hola Omar, ¿podrías publicar el error que recibes? Asegúrese de cambiar com.mypackagename en <com.mypackagename.LockableScrollView> por el suyo propio
Joseph Earl
1
Buena respuesta. Si cambia mayúsculas y minúsculas MotionEvent.ACTION_DOWN: a case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_DOWN: también podrá desactivar el desplazamiento mientras arrastra. Pero, por supuesto, todo el mundo tiene que usarlo.
luky
70

Yo había ido de esta manera:

        scrollView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            return isBlockedScrollView;
        }
    });
lirio
fuente
3
Simple y funciona muy bien. El punto clave es usar una variable (por ejemplo, isBlockedScrollView) para controlar cuándo desea habilitar el desplazamiento. Configúrelo en verdadero cuando se debe permitir el desplazamiento y en falso en caso contrario.
PeteH
5
@PeteH, no tengo idea de por qué, pero mi ListViewfunciona de manera opuesta: verdadero cuando el desplazamiento está deshabilitado y falso cuando está habilitado.
Machado
@Holmes: tiene razón, es cierto cuando quiere bloquear el desplazamiento
lily
1
Funciona maravillosamente. Además, tengo vistas de niños (botones) dentro de la vista de desplazamiento y aún puedo interactuar con ellos a pesar de no anular onInterceptTouchEvent (). Solución elegante.
Cody
1
@Machado La razón por la que debe devolver verdadero para bloquear el desplazamiento es porque el oyente táctil toma el valor booleano devuelto para determinar si el evento táctil debe consumirse o no. Si devuelve falso, la vista de desplazamiento pasará el evento táctil a su oyente de desplazamiento.
Vince
11

Encontré esta solución simple

ScrollView.requestDisallowInterceptTouchEvent(true);
JWqvist
fuente
5
requestDisallowInterceptTouchEventsolo funciona para que el elemento secundario de la Vista esté bloqueado. Entonces sería más comomLinearLayout.requestDisallowInterceptTouchEvent(true);
Muz
6

Deshabilitar ScrollView

ScrollView sw = (ScrollView) findViewById(R.id.scrollView1);
sw.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return true;
    }
});
BelaSzombathelyi
fuente
5

para empezar, utilicé el Código publicado en el primer comentario, pero lo cambié así:

    public class LockableScrollView extends ScrollView {

    public LockableScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
    }
    public LockableScrollView(Context context, AttributeSet attrs) 
    {
        super(context, attrs);
    }

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

    // true if we can scroll (not locked)
    // false if we cannot scroll (locked)
    private boolean mScrollable = true;

    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) {
    switch (ev.getAction()) {     
    case MotionEvent.ACTION_DOWN:         
        // if we can scroll pass the event to the superclass      
        if (mScrollable) return super.onInterceptTouchEvent(ev);      
        // only continue to handle the touch event if scrolling enabled    
        return mScrollable; // mScrollable is always false at this point     
        default:          
            return super.onInterceptTouchEvent(ev);      
            }
    }

}

luego lo llamé de esta manera

((LockableScrollView)findViewById(R.id.scrollV)).setScrollingEnabled(false);

porque lo intenté

((LockableScrollView)findViewById(R.id.scrollV)).setIsScrollable(false);

pero decía que setIsScrollable no está definido

Espero que esto ayude

Souhaieb
fuente
Nota: los dos primeros constructores son necesarios si su ScrollViewes el contenedor de diseño principal de su clase de diseño.
actaram
Si toca un botón o algo más que intercepta los toques primero, la vista de desplazamiento seguirá desplazándose
Cristi Băluță
3

He aquí una solución más sencilla. Reemplace el onTouch()para ScrollView OnTouchListenery devuelva falso si desea omitir el desplazamiento táctil. El desplazamiento programático sigue funcionando y no es necesario ampliar la ScrollViewclase.

mScroller.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
  return isScrollable;
}
});
mikec
fuente
1
! isScrollable ya que el valor de retorno verdadero significa que el evento fue interceptado.
goRGon
3

No tengo suficientes puntos para comentar sobre una respuesta, pero quería decir que la respuesta de mikec funcionó para mí, excepto que tuve que cambiarla para regresar. IsScrollable así:

mScroller.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      return !isScrollable;
    }
});
Dave
fuente
1
@Override  
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {     
    case MotionEvent.ACTION_DOWN:         
        // if we can scroll pass the event to the superclass      
        if (mScrollable) return super.onInterceptTouchEvent(ev);      
        // only continue to handle the touch event if scrolling enabled    
        return mScrollable; // mScrollable is always false at this point     
        default:          
            return super.onInterceptTouchEvent(ev);      
            }
    }
Mohammad
fuente
1

@JosephEarl +1 Tiene una gran solución aquí que funcionó perfectamente para mí con algunas modificaciones menores para hacerlo programáticamente.


Estos son los cambios menores que hice:

Clase LockableScrollView:

public boolean setScrollingEnabled(boolean enabled) {
    mScrollable = enabled;
    return mScrollable;
}

Actividad principal:

LockableScrollView sv;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    sv = new LockableScrollView(this);
    sv.setScrollingEnabled(false);
}
jnthnjns
fuente
1

Tenía un diseño sobre NestedScrollView que consumía el evento táctil y deshabilitaba el desplazamiento:

progressBarLayout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                return true;
            }
        });

y para habilitar:

progressBarLayout.setOnTouchListener(null);
SpyZip
fuente
1

Puede hacer un CustomScrollView, para lo cual puede deshabilitar su interferencia con otras vistas. Aunque esto a veces puede resultar irritante para el usuario final. Úselo con precaución.

Este es el código:

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewParent;

public class CustomScrollView extends android.widget.ScrollView {

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

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

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        /* Prevent parent controls from stealing our events once we've gotten a touch down */
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN)
        {
            ViewParent p = getParent();
            if (p != null)
                p.requestDisallowInterceptTouchEvent(true);
        }

        return false;
    }
}

¿Cómo utilizar CustomScrollView?

Puede agregar CustomScrollView como principal a la pantalla en la que desea agregar otra Scrollview como vista secundaria, y toda la pantalla se puede desplazar. Usé esto para un RelativeLayout.

<?xml version="1.0" encoding="utf-8"?>
<**package.**CustomScrollView 
xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/some_id"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    xmlns:tools="http://schemas.android.com/tools">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    #**Inside this I had a TableLayout and TableRow. Inside the TableRow,**
    #**I had a TextView which I made scrollable from Java Code.**
    #**textView.setMovementMethod(new ScrollingMovementMethod());**
    </RelativeLayout>
</ankit.inventory.ankitarora.inventorymanagementsimple.CustomScrollView>

Funcionó para mi caso.

Ankit Arora
fuente
1
public class LockableScrollView extends ScrollView {

    private boolean mScrollable = true;

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

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

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public LockableScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public void setScrollable(boolean enabled) {
        mScrollable = enabled;
    }

    public boolean isScrollable() {
        return mScrollable;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return mScrollable && super.onTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mScrollable && super.onInterceptTouchEvent(ev);
    }
}
Etiqueta
fuente
0

¿Esto ayuda?

((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setOnTouchListener(null);
Rajath
fuente
1
No creo que haya hecho ninguna diferencia, todavía tengo el mismo problema
Omar
0

Puede extender la galería y usar alguna bandera para deshabilitar el desplazamiento cuando lo desee:

public class MyGallery extends Gallery {

public boolean canScroll;

public MyGallery(Context context, AttributeSet attrs) {
    canScroll = true;
    super(context, attrs);
}

public void setCanScroll(boolean flag)
{
    canScroll = flag;
}

@Override
public boolean onScroll(android.view.MotionEvent e1, android.view.MotionEvent e2, float distanceX, float distanceY) {
    if (canScroll)
        return super.onScroll(e1,e2,distancex,distancey);
    else
        return false;
}

@Override
public boolean onSingleTapUp(MotionEvent e)
{
    if (canScroll)
        return super.onSingleTapUp(ey);
    else
        return false;
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
    if (canScroll)
        return super.onFling(e1,e2,velocityX,velocityY);
    else
        return false;
}
}
Megarushing
fuente
-3

Como puede ver en la documentación , no puede establecer la visibilidad en falso. En su caso, probablemente debería usar:

scrollview.setVisibility(Visibility.GONE);

fuente
2
Esto también ocultará la Galería, por lo que no es la solución, edité la publicación con más detalles
Omar
-6

en el botón haga clic en el oyente simplemente haga

ScrollView sView = (ScrollView)findViewById(R.id.ScrollView01);

sView.setVerticalScrollBarEnabled(false);
sView.setHorizontalScrollBarEnabled(false);

para que la barra de desplazamiento no esté habilitada al hacer clic en el botón

Sumant
fuente
2
Esto solo oculta las barras, supongo ... pero no el efecto de la vista de desplazamiento
Omar
1
no le permitirá desplazarse, tampoco ocultará la vista de la galería
Sumant