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?

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.


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

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

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

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


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

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

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

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

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.


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

czy to pomaga?

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

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

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

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


2
To chyba tylko ukrywa paski ... ale nie efekt przewijania
— Omar,

1
nie pozwoli na przewijanie, nie będzie też ukrywać widoku galerii
— Sumant,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.