Désactiver ScrollView par programme?


108

Je voudrais activer ScrollView et le désactiver par un clic de bouton.
Désactiver signifie comme si le ScrollView n'était pas là ... et l'activer renvoie le ScrollView.

Je veux cela parce que j'ai une galerie avec des images de texte, et sur un bouton cliquez sur l'orientation de l'écran change, donc dans Paysage le texte devient plus grand. Et je veux le ScrollView pour que l'image ne s'étire pas d'elle-même et que le texte devienne illisible.

scrollview.Enabled=false / setVisibility(false) ne fait rien.

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>

Merci

Edit1: Je ne peux pas utiliser la visibilité (partie) car cela masquerait également la galerie, ce que je veux, c'est masquer l'effet du ScrollView. Lorsqu'il y a ScrollView, les images de la Galerie deviennent scrollabale et ne rentrent pas dans l'écran, vous devez donc faire défiler pour voir l'image entière, je ne veux pas désactiver / activer cela en cliquant sur un bouton.

J'ai essayé ceci:

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

Mais les images de la Galerie sont toujours défilantes et ne correspondent pas à l'écran. Quelle est la solution à cela?

Réponses:


187

Plusieurs points pour commencer:

  1. Vous ne pouvez pas désactiver le défilement d'un ScrollView. Vous devez étendre à ScrollView et remplacer la onTouchEventméthode à renvoyer falselorsqu'une condition est remplie.
  2. Le composant Galerie défile horizontalement, qu'il soit dans un ScrollView ou non - un ScrollView fournit uniquement un défilement vertical (vous avez besoin d'un HorizontalScrollView pour le défilement horizontal)
  3. Vous semblez dire que vous avez un problème avec l'image qui s'étire elle-même - cela n'a rien à voir avec le ScrollView, vous pouvez changer la façon dont un ImageView se met à l'échelle avec la android:scaleTypepropriété (XML) ou la setScaleTypeméthode - par exemple , n'étireront ScaleType.CENTERpas votre image et centrez-le à sa taille d'origine

Vous pouvez modifier ScrollViewcomme suit pour désactiver le défilement

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

}

Vous utiliseriez alors

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

dans votre fichier XML (juste changé le ScrollViewen votre spécial LockableScrollView).

Puis appelez

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

pour désactiver le défilement de la vue.

Je pense que vous avez plus que le problème de désactiver le défilement pour obtenir le résultat souhaité (la galerie restera défilable avec le code ci-dessus par exemple) - je vous recommande de faire plus de recherche sur chacun des trois composants (Galerie, ScrollView, ImageView) pour voir quelles propriétés chacun possède et comment il se comporte.


Voici à quoi ressemble la classe: pastebin.com/dsWSWR4x Mais j'obtiens l'erreur `` La méthode onTouch (View, MotionEvent) de type LockableScrollView doit remplacer ou implémenter une méthode de supertype ''
Omar

Excuses, corrigé les erreurs dans mon code - cela aurait dû êtreonTouchEvent(MotionEvent ev)
Joseph Earl

1
Ok maintenant, le code est conforme, mais lorsque j'exécute l'application, il se bloque ... et lorsque je supprime cette classe et renvoie le <ScrollView au lieu de votre classe, l'application fonctionne bien!
Omar

Salut Omar, pourriez-vous poster l'erreur que vous obtenez? Assurez-vous de changer le nom de com.mypackagename dans <com.mypackagename.LockableScrollView> par le vôtre
Joseph Earl

1
Bonne réponse. Si vous modifiez la casse MotionEvent.ACTION_DOWN: à la casse MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_DOWN: vous pourrez également désactiver le défilement également en faisant glisser. Mais c'est bien sûr sur chacun comment il doit l'utiliser.
luky

70

J'étais allé par ici:

        scrollView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            return isBlockedScrollView;
        }
    });

3
Simple et fonctionne très bien. Le point clé est d'utiliser une variable (par exemple, isBlockedScrollView) pour contrôler le moment où vous souhaitez activer le défilement. Définissez-le sur true lorsque le défilement doit être autorisé et sur false dans le cas contraire.
PeteH

5
@PeteH, je ne sais pas pourquoi, mais mon ListViewfonctionne dans le sens inverse: true lorsque le défilement est désactivé et false lorsqu'il est activé.
Machado

@Holmes: vous avez raison, vrai quand vous voulez bloquer le défilement
Lily

1
Fonctionne à merveille De plus, j'ai des vues enfants (boutons) dans la vue de défilement et je peux toujours interagir avec elles même si je ne remplace pas onInterceptTouchEvent ()! Solution élégante.
Cody

1
@Machado La raison pour laquelle vous devez retourner true pour bloquer le défilement est que l'écouteur tactile prend la valeur booléenne renvoyée afin de déterminer si l'événement tactile doit être consommé ou non. Si vous retournez false, la vue de défilement passera alors l'événement tactile à son écouteur de défilement.
Vince

11

J'ai trouvé cette solution simple juste définie

ScrollView.requestDisallowInterceptTouchEvent(true);

5
requestDisallowInterceptTouchEventfonctionne uniquement pour que l' enfant de la vue soit verrouillé. Donc, ce serait plutôtmLinearLayout.requestDisallowInterceptTouchEvent(true);
Muz

6

Désactiver ScrollView

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

5

pour commencer, j'ai utilisé le code publié dans le premier commentaire mais je l'ai changé comme ceci:

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

}

alors je l'ai appelé de cette façon

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

parce que j'ai essayé

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

mais il a dit que setIsScrollable n'est pas défini

J'espère que cela t'aidera


Remarque: les deux premiers constructeurs sont nécessaires si vous êtes ScrollViewle conteneur de disposition principal de votre classe de disposition.
actaram

Si vous touchez un bouton ou quelque chose d'autre qui intercepte les touches en premier, la vue de défilement défilera toujours
Cristi Băluță

3

Voici une solution plus simple. Remplacez onTouch()pour ScrollView OnTouchListeneret retournez false si vous souhaitez contourner le défilement au toucher. Le défilement programmatique fonctionne toujours et il n'est pas nécessaire d'étendre la ScrollViewclasse.

mScroller.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
  return isScrollable;
}
});

1
! isScrollable car la valeur de retour vraie signifie que l'événement a été intercepté.
goRGon

3

Je n'ai pas assez de points pour commenter une réponse, mais je voulais dire que la réponse de mikec a fonctionné pour moi sauf que j'ai dû la changer pour revenir! IsScrollable comme ceci:

mScroller.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      return !isScrollable;
    }
});

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

1

@JosephEarl +1 Il a une excellente solution ici qui a parfaitement fonctionné pour moi avec quelques modifications mineures pour le faire par programme.


Voici les modifications mineures que j'ai apportées:

Classe LockableScrollView:

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

Activité principale:

LockableScrollView sv;

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

1

J'avais une disposition sur le NestedScrollView consommant l'événement tactile et désactivant le défilement:

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

et pour activer:

progressBarLayout.setOnTouchListener(null);

1

Vous pouvez créer un CustomScrollView, pour lequel vous pouvez désactiver son interférence avec d'autres vues. Bien que cela puisse parfois être irritant pour l'utilisateur final. Utilisez-le avec prudence.

Voici le code:

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

Comment utiliser le CustomScrollView?

Vous pouvez ajouter CustomScrollView en tant que parent à l'écran dans lequel vous souhaitez ajouter un autre Scrollview en tant que vue enfant, et tout l'écran peut faire défiler. J'ai utilisé ceci pour 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>

Cela a fonctionné pour mon cas.


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

0

est-ce que cela aide?

((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setOnTouchListener(null);

1
Je ne pense pas que cela ait fait de différence, j'ai toujours le même problème
Omar

0

Vous pouvez étendre la galerie et utiliser un indicateur pour désactiver le défilement quand vous le souhaitez:

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

-3

Comme vous pouvez le voir dans la documentation , vous ne pouvez pas définir la visibilité sur false. Dans votre cas, vous devriez probablement utiliser:

scrollview.setVisibility(Visibility.GONE);

2
Cela masquera également la galerie, donc ce n'est pas la solution, j'ai édité le message avec plus de détails
Omar

-6

sur le bouton, cliquez sur l'auditeur

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

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

pour que la barre de défilement ne soit pas activée lors d'un clic sur le bouton


2
Cela ne cache que les barres je suppose .. mais pas l'effet du scrollview
Omar

1
il ne vous permettra pas de faire défiler et ne
masquera
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.