Desativar ScrollView programaticamente?

108

Gostaria de ativar o ScrollView e desativá-lo com um clique de botão.
Desativar significa como se o ScrollView não estivesse lá ... e ativá-lo retorna o ScrollView.

Eu quero isso porque eu tenho uma galeria com imagens de texto, e com um botão clique a orientação da tela muda, então em Paisagem o texto fica maior. E eu quero o ScrollView para que a imagem não se estique e o texto se torne ilegível.

scrollview.Enabled=false / setVisibility(false) não faz 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>

obrigado

Edit1: Não posso usar Visibility (ido), pois isso também ocultaria a Galeria, o que eu quero é ocultar o efeito do ScrollView. Quando há ScrollView, as imagens na Galeria se tornam roláveis ​​e não cabem na tela, então você tem que rolar para ver a imagem inteira, não quero desabilitar / habilitar isso com um clique de botão.

Eu tentei isso:

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

Mas ainda assim as imagens na Galeria são roláveis ​​e não cabem na tela .. qual é a solução para isso?

Omar
fonte

Respostas:

187

Vários pontos para começar:

  1. Você não pode desativar a rolagem de um ScrollView. Você precisaria estender para ScrollView e substituir o onTouchEventmétodo para retornar falsequando alguma condição for correspondida.
  2. O componente Gallery rola horizontalmente, independentemente de estar em um ScrollView ou não - um ScrollView fornece apenas rolagem vertical (você precisa de um HorizontalScrollView para rolagem horizontal)
  3. Você parece dizer que tem um problema com o alongamento da imagem em si - isso não tem nada a ver com o ScrollView, você pode alterar como um ImageView é dimensionado com a android:scaleTypepropriedade (XML) ou o setScaleTypemétodo - por exemplo ScaleType.CENTER, não alongará sua imagem e centralize em seu tamanho original

Você pode modificar ScrollViewo seguinte para desativar a rolagem

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

}

Você então usaria

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

no seu arquivo XML (apenas altere o ScrollViewpara o seu especial LockableScrollView).

Então ligue

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

para desativar a rolagem da visualização.

Acho que você tem mais do que apenas o problema de desativar a rolagem para obter o resultado desejado (a galeria permanecerá rolável com o código acima, por exemplo) - eu recomendo fazer mais pesquisas sobre cada um dos três componentes (Galeria, ScrollView, ImageView) para ver quais propriedades cada um possui e como se comporta.

Joseph Earl
fonte
Esta é a aparência da classe: pastebin.com/dsWSWR4x Mas recebo o erro 'O método onTouch (View, MotionEvent) do tipo LockableScrollView deve substituir ou implementar um método de supertipo'
Omar
Desculpe, corrigiu os erros no meu código - deveria ter sidoonTouchEvent(MotionEvent ev)
Joseph Earl
1
Ok, agora o código está em conformidade, embora quando eu execute o aplicativo ele trava ... e quando eu removo essa classe e retorno o <ScrollView em vez de sua classe, o aplicativo funciona bem!
Omar
Oi Omar você poderia postar o erro que você obteve? Certifique-se de alterar o com.mypackagename em <com.mypackagename.LockableScrollView> para o seu próprio
Joseph Earl
1
Boa resposta. Se você alterar o case MotionEvent.ACTION_DOWN: para o case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_DOWN: você também poderá desativar a rolagem ao arrastar. Mas é claro que todos sabem como ele precisa usá-lo.
luky
70

Eu tinha ido por este caminho:

        scrollView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            return isBlockedScrollView;
        }
    });
lírio
fonte
3
Simples e funciona muito bem. O ponto principal é usar uma variável (por exemplo, isBlockedScrollView) para controlar quando você deseja habilitar a rolagem. Defina-o como verdadeiro quando a rolagem for permitida e falso caso contrário.
PeteH
5
@PeteH, não tenho ideia do porquê, mas ListViewfunciona da maneira oposta: verdadeiro quando a rolagem está desabilitada e falso quando está habilitada.
Machado
@Holmes: você está certo, é verdade quando deseja bloquear a rolagem
lily
1
Funciona perfeitamente. Além disso, tenho visualizações filhos (botões) na visualização de rolagem e ainda posso interagir com eles, apesar de não substituir onInterceptTouchEvent ()! Solução elegante.
Cody,
1
@Machado O motivo pelo qual você deve retornar verdadeiro para bloquear a rolagem é porque o ouvinte de toque pega o valor booleano retornado para determinar se o evento de toque deve ou não ser consumido. Se você retornar false, a visualização de rolagem continuará passando o evento de toque para seu ouvinte de rolagem.
Vince
11

Encontrei esta solução simples, acabei de definir

ScrollView.requestDisallowInterceptTouchEvent(true);
JWqvist
fonte
5
requestDisallowInterceptTouchEventsó funciona para o filho da Visualização a ser bloqueado. Então seria mais comomLinearLayout.requestDisallowInterceptTouchEvent(true);
Muz
6

Desativar ScrollView

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

para começar, usei o código postado no primeiro comentário, mas mudei assim:

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

}

então eu chamei desta forma

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

porque eu tentei

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

mas disse que setIsScrollable é indefinido

Eu espero que isso te ajude

Souhaieb
fonte
Observação: os dois primeiros construtores são necessários se você ScrollViewfor o contêiner de layout principal de sua classe de layout.
actaram
Se você tocar em um botão ou outra coisa que intercepte os toques primeiro, a visualização em rolagem ainda rolará
Cristi Băluță
3

Aqui está uma solução mais simples. Substitua o onTouch()por ScrollView OnTouchListenere retorne falso se quiser ignorar a rolagem pelo toque. A rolagem programática ainda funciona e não há necessidade de estender a ScrollViewaula.

mScroller.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
  return isScrollable;
}
});
mikec
fonte
1
! isScrollable, pois o valor de retorno verdadeiro significa que o evento foi interceptado.
goRGon
3

Não tenho pontos suficientes para comentar uma resposta, mas gostaria de dizer que a resposta de mikec funcionou para mim, exceto que eu tive que alterá-la para retornar! IsScrollable assim:

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

@JosephEarl +1 Ele tem uma ótima solução aqui que funcionou perfeitamente para mim com algumas pequenas modificações para fazê-lo programaticamente.


Aqui estão as pequenas alterações que fiz:

Classe LockableScrollView:

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

Atividade principal:

LockableScrollView sv;

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

Eu tinha um layout sobre o NestedScrollView consumindo o evento de toque e desabilitando a rolagem:

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

e para habilitar:

progressBarLayout.setOnTouchListener(null);
SpyZip
fonte
1

Você pode fazer um CustomScrollView, para o qual você pode desabilitar sua interferência com outras visualizações. Embora isso às vezes possa ser irritante para o usuário final. Use-o com cuidado.

Este é o 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;
    }
}

Como usar o CustomScrollView?

Você pode adicionar CustomScrollView como um pai à tela na qual deseja adicionar outro Scrollview como um filho, e toda a tela é rolável. Eu usei isso para um 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>

Funcionou para o meu caso.

Ankit Arora
fonte
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);
    }
}
Täg
fonte
0

Isso ajuda?

((ScrollView)findViewById(R.id.QuranGalleryScrollView)).setOnTouchListener(null);
Rajath
fonte
1
Não acho que tenha feito diferença, ainda tenho o mesmo problema
Omar,
0

Você pode estender a galeria e usar algum sinalizador para desativar a rolagem quando quiser:

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

Como você pode ver na documentação , você não pode definir a visibilidade como falsa. No seu caso, você provavelmente deve usar:

scrollview.setVisibility(Visibility.GONE);

fonte
2
Isso também ocultará a Galeria, então não é a solução, editei o post com mais detalhes
Omar
-6

no ouvinte do clique do botão apenas faça

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

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

para que a barra de rolagem não seja habilitada no clique do botão

Sumant
fonte
2
Isso apenas esconde as barras, eu acho ... mas não o efeito do scrollview
Omar
1
não permitirá que você role e não ocultará a visualização da galeria
Sumant