Wyłączyć programowo ScrollView?

108

Chciałbym włączyć ScrollView i wyłączyć go jednym kliknięciem przycisku.
Disable oznacza tak, jakby ScrollView nie istniał ... a włączenie zwraca ScrollView.

Chcę tego, ponieważ mam galerię z obrazami tekstowymi, a po kliknięciu przycisku zmienia się orientacja ekranu, więc w orientacji poziomej tekst staje się większy. Chcę mieć ScrollView, aby obraz się nie rozciągał, a tekst stał się nieczytelny.

scrollview.Enabled=false / setVisibility(false) nic nie robi.

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>

Dzięki

Edycja1: Nie mogę użyć widoczności (zniknęła), ponieważ to również ukryłoby Galerię, chcę ukryć efekt ScrollView. Kiedy jest ScrollView, obrazy w Galerii stają się przewijane i nie mieszczą się na ekranie, więc musisz przewijać, aby zobaczyć cały obraz, nie chcę wyłączać / włączać tego jednym kliknięciem przycisku.

Próbowałem tego:

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

Ale nadal obrazy w Galerii można przewijać i nie mieszczą się na ekranie. Jakie jest na to rozwiązanie?

Omar
źródło

Odpowiedzi:

187

Na początek kilka punktów:

  1. Nie można wyłączyć przewijania ScrollView. Konieczne byłoby rozszerzenie do ScrollView i zastąpienie onTouchEventmetody zwracania, falsegdy zostanie dopasowany jakiś warunek.
  2. Składnik Gallery przewija w poziomie niezależnie od tego, czy znajduje się w ScrollView, czy nie - ScrollView zapewnia tylko przewijanie w pionie (potrzebujesz HorizontalScrollView do przewijania w poziomie)
  3. Wydaje się, że masz problem z rozciąganiem samego obrazu - nie ma to nic wspólnego z ScrollView, możesz zmienić sposób skalowania ImageView z android:scaleTypewłaściwością (XML) lub setScaleTypemetodą - na przykład ScaleType.CENTERnie rozciągnie obrazu i wyśrodkuj go w oryginalnym rozmiarze

Możesz zmodyfikować ScrollVieww następujący sposób, aby wyłączyć przewijanie

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

}

Wtedy użyłbyś

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

w pliku XML (właśnie zmieniłem na ScrollViewswój specjalny LockableScrollView).

Wtedy zadzwoń

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

aby wyłączyć przewijanie widoku.

Myślę, że masz więcej niż tylko kwestię wyłączenia przewijania, aby osiągnąć pożądany rezultat (galeria pozostanie przewijalna na przykład z powyższym kodem) - polecam zbadanie każdego z trzech komponentów (Galeria, ScrollView, ImageView), aby zobaczyć, jakie właściwości ma każdy z nich i jak się zachowuje.

Joseph Earl
źródło
Oto jak wygląda klasa: pastebin.com/dsWSWR4x Ale pojawia się błąd „Metoda onTouch (View, MotionEvent) typu LockableScrollView musi przesłonić lub zaimplementować metodę supertype”
Omar
Przepraszam, poprawiłem błędy w moim kodzie - powinno byćonTouchEvent(MotionEvent ev)
Joseph Earl
1
Ok, teraz kod jest zgodny, chociaż kiedy uruchamiam aplikację, ulega awarii ... a kiedy usuwam tę klasę i zwracam <ScrollView zamiast twojej klasy, aplikacja działa dobrze!
Omar
Cześć Omar, czy mógłbyś opublikować otrzymany błąd? Upewnij się, że zmień nazwę com.mypackagename w <com.mypackagename.LockableScrollView> na własną
Joseph Earl
1
Dobra odpowiedź. Jeśli zmienisz wielkość liter MotionEvent.ACTION_DOWN: na wielkość MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_DOWN: będziesz mógł również wyłączyć przewijanie również podczas przeciągania. Ale oczywiście od każdego zależy, jak powinien go używać.
luky
70

Poszedłem tą drogą:

        scrollView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            return isBlockedScrollView;
        }
    });
lilia
źródło
3
Prosty i działa świetnie. Kluczową kwestią jest użycie zmiennej (np. IsBlockedScrollView) do kontrolowania, kiedy chcesz włączyć przewijanie. Ustaw ją na true, gdy przewijanie powinno być dozwolone, a false, jeśli w przeciwnym razie.
PeteH,
5
@PeteH, nie mam pojęcia dlaczego, ale mój ListViewdziała odwrotnie: prawda, gdy przewijanie jest wyłączone, a fałsz, gdy jest włączone.
Machado
@Holmes: masz rację, prawda, kiedy chcesz zablokować przewijanie
lily
1
Działa pięknie, mam również widoki dzieci (przyciski) w widoku scrollview i nadal mogę z nimi wchodzić w interakcje, mimo że nie nadpisuję onInterceptTouchEvent ()! Eleganckie rozwiązanie.
Cody,
1
@Machado Powodem, dla którego musisz zwrócić wartość true, aby zablokować przewijanie, jest to, że odbiornik dotyku przyjmuje wartość logiczną zwróconą w celu określenia, czy zdarzenie dotknięcia powinno zostać wykorzystane, czy nie. Jeśli zwrócisz wartość false, widok przewijania przejdzie następnie do przekazania zdarzenia dotyku do jego odbiornika przewijania.
Vince
11

Znalazłem to proste rozwiązanie po prostu ustawione

ScrollView.requestDisallowInterceptTouchEvent(true);
JWqvist
źródło
5
requestDisallowInterceptTouchEventdziała tylko dla zablokowanego elementu podrzędnego Widoku. Więc byłoby bardziej jakmLinearLayout.requestDisallowInterceptTouchEvent(true);
Muz
6

Wyłącz ScrollView

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

na początek użyłem kodu zamieszczonego w pierwszym komentarzu, ale zmieniłem go w ten sposób:

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

}

wtedy zadzwoniłem w ten sposób

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

ponieważ próbowałem

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

ale powiedział, że setIsScrollable jest niezdefiniowane

mam nadzieję, że to Ci pomoże

Souhaieb
źródło
Uwaga: pierwsze dwa konstruktory są potrzebne, jeśli Twój ScrollViewjest głównym kontenerem układu Twojej klasy układu.
actaram
Jeśli dotkniesz przycisku lub czegoś innego, co najpierw przechwytuje dotknięcia, widok przewijania nadal będzie się przewijał
Cristi Băluță Kwietnia
3

Oto prostsze rozwiązanie. Zastąp onTouch()for the ScrollView OnTouchListeneri zwróć false, jeśli chcesz pominąć przewijanie dotykiem. Programowe przewijanie nadal działa i nie ma potrzeby rozszerzania ScrollViewklasy.

mScroller.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
  return isScrollable;
}
});
mikec
źródło
1
! isScrollable, ponieważ zwrócona wartość true oznacza, że ​​zdarzenie zostało przechwycone.
goRGon
3

Nie mam wystarczającej liczby punktów, aby skomentować odpowiedź, ale chciałem powiedzieć, że odpowiedź mikec działała dla mnie, z wyjątkiem tego, że musiałem ją zmienić, aby zwrócić!

mScroller.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      return !isScrollable;
    }
});
Dave
źródło
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
źródło
1

@JosephEarl +1 Ma tutaj świetne rozwiązanie, które działało idealnie dla mnie z kilkoma drobnymi modyfikacjami, aby robić to programowo.


Oto drobne zmiany, które wprowadziłem:

Klasa LockableScrollView:

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

Główna aktywność:

LockableScrollView sv;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    sv = new LockableScrollView(this);
    sv.setScrollingEnabled(false);
}
jnthnjns
źródło
1

Miałem układ nad NestedScrollView zużywający zdarzenie touch i wyłączający przewijanie:

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

i aby umożliwić:

progressBarLayout.setOnTouchListener(null);
SpyZip
źródło
1

Możesz utworzyć CustomScrollView, dla którego możesz wyłączyć jego interferencję z innymi widokami. Chociaż może to być czasami irytujące dla użytkownika końcowego. Używaj go ostrożnie.

To jest kod:

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

Jak korzystać z CustomScrollView?

Możesz dodać CustomScrollView jako element nadrzędny do ekranu, do którego chcesz dodać kolejny widok Scrollview jako widok podrzędny, a cały ekran można przewijać. Użyłem tego dla 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>

Zadziałało w moim przypadku.

Ankit Arora
źródło
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);
    }
}
Etykietka
źródło
0

czy to pomaga?

((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setOnTouchListener(null);
rajath
źródło
1
Nie sądzę, żeby to zrobiło jakąkolwiek różnicę, wciąż mam ten sam problem
Omar
0

Możesz rozszerzyć galerię i użyć jakiejś flagi, aby wyłączyć przewijanie, kiedy chcesz:

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
źródło
-3

Jak widać w dokumentacji , nie można ustawić widoczności na fałsz. W Twoim przypadku prawdopodobnie powinieneś użyć:

scrollview.setVisibility(Visibility.GONE);

źródło
2
Będzie to również ukryć Galerię więc jej nie rozwiązanie, ja edytowany post z większą liczbą szczegółów
Omar
-6

po prostu zrób odbiornik kliknięć przycisku

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

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

aby pasek przewijania nie był włączany po kliknięciu przycisku

Sumant
źródło
2
To chyba tylko ukrywa paski ... ale nie efekt przewijania
Omar,
1
nie pozwoli na przewijanie, nie będzie też ukrywać widoku galerii
Sumant,