Disable scrolling in listview
Asked Answered
G

11

44

I have a list view and depending on some logic I want to temporary disable the scrolling. view.setOnScrollListener(null); doesn't helps me I guess I need to write some code, can someone give me a hist or some snippet ?

Thanks

Gorski answered 30/9, 2011 at 13:28 Comment(2)
yes, all I need is to disable scrolling for 2-3 secondsGorski
THE ONLY SOLUTION ... danosipov.com/?p=604Skricki
P
46

In your CustomListView:

@Override
public boolean dispatchTouchEvent(MotionEvent ev){
   if(ev.getAction()==MotionEvent.ACTION_MOVE)
      return true;
   return super.dispatchTouchEvent(ev);
}

Then ListView will react to clicks, but will not change scroll position.

Pile answered 21/6, 2012 at 15:15 Comment(4)
it was long ago when I had this problem , but I think this is the right solution (I solved my problem with managing the visibility )Gorski
Looks like this solution is just partial and will fail on any device with external keyboard or BT/USB keyboard attached.Circumrotate
Unfortunately this, also, simply doesn't work. You still get scrolling effects if you swipe over a button, or anything.Skricki
use Nikita's Solution, that is simple wayTaxi
B
44

Another option without creating a new custom ListView would be to attach an onTouchListener to your ListView and return true in the onTouch() callback if the motion event action is ACTION_MOVE.

listView.setOnTouchListener(new OnTouchListener() {

    public boolean onTouch(View v, MotionEvent event) {
        return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
});
Bedesman answered 3/10, 2012 at 13:43 Comment(2)
Or, which is shorter and cleaner, return (event.getAction() == MotionEvent.ACTION_MOVE);Qp
this DOES NOT WORK AT ALL if the ListView contains ANY buttons or indeed even a pull to refresh. It simply does not work, if the users happens to scroll over one of the buttons - it scrolls. It's not usable at all.Skricki
C
33

use listview.setEnabled(false) to disable listview scrolling

Note: This also disables row selections

Coverage answered 1/12, 2014 at 9:2 Comment(5)
Worked for me, I don't know why everybody else are taking such complex routes.Oligochaete
This won't work because it also disables listview row selectionsBettor
Worked for me, because i trying disabled all listviewCerebrospinal
This is the best and the simplest method.Orlene
after this, can not be click. :(Guildhall
I
9

make your CustomListView

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
  if(needToStop){
    return false;}
    return super.onInterceptTouchEvent(ev); 
}

on false the childs will handle the touch event, make sure you put your if condition to check you need to scroll or not.

Insane answered 2/10, 2011 at 9:0 Comment(3)
Well this is very good hint by doesn't work for me. Here is the problem I need to disable scroll while I am in onTouch, and return false in onTouch doesn't disable scroll. :(Gorski
:), you didn't understand me. I can't return false in onInterceptTouchEvent, cause I need all others method to be called, methods like onTouch btw(I am makeing drag and drop app ). That is why ones I pressed the onInterceptTouchEvent i called but I do not release my finger and the onTouch is called many times so here I want to disable scrolling....Gorski
@MoshErsan : Can you explain how we can disable parent TochEvent while the child need it for inner scrolling? I really need this.Vesuvianite
V
8

If you have an event bound to the list items, then dragging the list with any of these solutions will still trigger the event. You want to use the following method to account for users expectation to cancel the event by dragging away from the selected item (adapted from Pointer Null's answer):

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    final int actionMasked = ev.getActionMasked() & MotionEvent.ACTION_MASK;

    if (actionMasked == MotionEvent.ACTION_DOWN) {
        // Record the position the list the touch landed on
        mPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
        return super.dispatchTouchEvent(ev);
    }

    if (actionMasked == MotionEvent.ACTION_MOVE) {
        // Ignore move events
        return true;
    }

    if (actionMasked == MotionEvent.ACTION_UP) {
        // Check if we are still within the same view
        if (pointToPosition((int) ev.getX(), (int) ev.getY()) == mPosition) {
            super.dispatchTouchEvent(ev);
        } else {
            // Clear pressed state, cancel the action
            setPressed(false);
            invalidate();
            return true;
        }
    }

    return super.dispatchTouchEvent(ev);
}

Full custom view class is available: https://gist.github.com/danosipov/6498490

Varanasi answered 9/9, 2013 at 17:9 Comment(1)
helpful for me, nice!Furfural
E
5

The best answer for me is the One from Dan Osipov. I'd improve it like this. (firing a CANCEL action event instead of manually erasing the pressed state).

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    final int actionMasked = ev.getActionMasked() & MotionEvent.ACTION_MASK;

    if (actionMasked == MotionEvent.ACTION_DOWN) {
        // Record the position the list the touch landed on
        mPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
        return super.dispatchTouchEvent(ev);
    }

    if (actionMasked == MotionEvent.ACTION_MOVE) {
        // Ignore move events
        return true;
    }

    if (actionMasked == MotionEvent.ACTION_UP) {
        // Check if we are still within the same view
        if (pointToPosition((int) ev.getX(), (int) ev.getY()) != mPosition) {
            // Clear pressed state, cancel the action
            ev.setAction(MotionEvent.ACTION_CANCEL);
        }
    }

    return super.dispatchTouchEvent(ev);
}
Euplastic answered 22/10, 2014 at 16:21 Comment(0)
T
2

When writing code for swipe to delete on a list view, I wanted to prevent the vertical scrolling once the swipe had been detected. I set a boolean flag in the ACTION_MOVE section once the swipe to delete conditions had been met. The dispatchTouchEvent method checks that condition and prevents the scroll from working. In the ACTION_UP I set the flag back to false to re-enable the scroll.

private float mY = Float.NaN;
private boolean mStopScroll = false;

@Override
public boolean onTouch(View view, MotionEvent event) {

   if(!mStopScroll) {
       mY = event.getY();
   }

   switch (event.getAction()) {

        case MotionEvent.ACTION_MOVE:

            if(<condition that stops the vertical scroll>) {
                mStopScroll = true;
            }

            break;

        case MotionEvent.ACTION_UP:

            mStopScroll = false;

            // your code here
            return true;

        default:

    }

    return false;

}

@Override
public boolean dispatchTouchEvent(MotionEvent motionEvent) {

    if(mStopScroll) {
        motionEvent.setLocation(motionEvent.getX(), mY);
    }
    return super.dispatchTouchEvent(motionEvent);
}
Trioxide answered 6/8, 2014 at 15:40 Comment(0)
S
1

My answer will be interesting for Xamarin and MvvmCross users. Main concept is the same like in previous posts, so main steps are:

  1. Mute scroll events
  2. Change dynamically list height

Here you are helper class, that allows to disable scroll in list view:

using System;
using Cirrious.MvvmCross.Binding.Droid.Views;
using Android.Content;
using Android.Util;
using Android.Views;
using Android.Database;

namespace MyProject.Android.Helpers
{
    public class UnscrollableMvxListView
        : MvxListView
    {
        private MyObserver _myObserver;

        public UnscrollableMvxListView (Context context, IAttributeSet attrs, MvxAdapter adapter)
            : base(context, attrs, adapter)
        {
        }

        protected override void OnAttachedToWindow ()
        {
            base.OnAttachedToWindow ();
            var dtso = new MyObserver(this);
            _myObserver = dtso;
            Adapter.RegisterDataSetObserver (dtso);
        }

        protected override void OnDetachedFromWindow ()
        {
            Log.Debug ("UnscrollableMvxListView", "OnDetachedFromWindow");
            if (_myObserver != null) {
                Adapter.UnregisterDataSetObserver (_myObserver);
                _myObserver = null;
            }
            base.OnDetachedFromWindow ();
        }

        //Make List Unscrollable
        private int _position;
        public override bool DispatchTouchEvent (MotionEvent ev)
        {
            MotionEventActions actionMasked = ev.ActionMasked & MotionEventActions.Mask;

            if (actionMasked == MotionEventActions.Down) {
                // Record the position the list the touch landed on
                _position = PointToPosition((int) ev.GetX (), (int) ev.GetY());
                return base.DispatchTouchEvent(ev);
            }

            if (actionMasked == MotionEventActions.Move) {
                // Ignore move events
                return true;
            }

            if (actionMasked == MotionEventActions.Up) {
                // Check if we are still within the same view
                if (PointToPosition((int) ev.GetX(), (int) ev.GetY()) == _position) {
                    base.DispatchTouchEvent(ev);
                } else {
                    // Clear pressed state, cancel the action
                    Pressed = false;
                    Invalidate();
                    return true;
                }
            }

            return base.DispatchTouchEvent(ev);
        }

        //Make List Flat
        public void JustifyListViewHeightBasedOnChildren () {
            if (Adapter == null) {
                return;
            }
            var vg = this as ViewGroup;
            int totalHeight = 0;
            for (int i = 0; i < Adapter.Count; i++) {
                View listItem = Adapter.GetView(i, null, vg);
                listItem.Measure(0, 0);
                totalHeight += listItem.MeasuredHeight;
            }

            ViewGroup.LayoutParams par = LayoutParameters;
            par.Height = totalHeight + (DividerHeight * (Adapter.Count - 1));
            LayoutParameters = par;
            RequestLayout();
        }
    }

    internal class MyObserver
        : DataSetObserver 
    {
        private readonly UnscrollableMvxListView _unscrollableMvxListView;

        public MyObserver (UnscrollableMvxListView lst)
        {
            _unscrollableMvxListView = lst;
        }

        public override void OnChanged() {
            Log.Debug("UnscrollableMvxListView", "OnChanged");
            base.OnChanged ();
            _unscrollableMvxListView.JustifyListViewHeightBasedOnChildren ();
        }
    }
}
Selie answered 20/10, 2014 at 8:42 Comment(0)
L
1

This is the code Joe Blow (comment on OP post) pointed at on http://danosipov.com/?p=604 but I'm posting it here to preserve it in case the link is orphaned:

public class ScrollDisabledListView extends ListView {

private int mPosition;

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

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

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

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    final int actionMasked = ev.getActionMasked() & MotionEvent.ACTION_MASK;

    if (actionMasked == MotionEvent.ACTION_DOWN) {
        // Record the position the list the touch landed on
        mPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
        return super.dispatchTouchEvent(ev);
    }

    if (actionMasked == MotionEvent.ACTION_MOVE) {
        // Ignore move events
        return true;
    }

    if (actionMasked == MotionEvent.ACTION_UP) {
        // Check if we are still within the same view
        if (pointToPosition((int) ev.getX(), (int) ev.getY()) == mPosition) {
            super.dispatchTouchEvent(ev);
        } else {
            // Clear pressed state, cancel the action
            setPressed(false);
            invalidate();
            return true;
        }
    }

    return super.dispatchTouchEvent(ev);
}
}

When you add this ListView to your layout remember to precede it with its package name, otherwise an exception will be thrown when you try to inflate it.

Libration answered 8/5, 2015 at 19:52 Comment(0)
C
0

Try this:

listViewObject.setTranscriptMode(0);

Works for me.

Celsacelsius answered 21/7, 2015 at 6:15 Comment(0)
M
0

Put your listView inside nestedScrollView and disable scroll using one of the following options:

yourListView.stopNestedScroll()

yourListView.isNestedScrollingEnabled = false

yourListView.transcriptMode = 0

android:descendantFocusability="blocksDescendants"

android:nestedScrollingEnabled="false"

Note: using one of the following option is enough. Note: this works only if listView is put inside nestedScrollView. If you don't want your listView located inside nestedScrollView and still want disable scroll, then you need to create CustomListView as suggested in accepted answer.

Mitrewort answered 19/9, 2023 at 5:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.