开发者

Disable scrolling in listview

开发者 https://www.devze.com 2023-04-09 08:00 出处:网络
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 giv开发者_Sta

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 giv开发者_StackOverflowe me a hist or some snippet ?

Thanks


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.


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


use listview.setEnabled(false) to disable listview scrolling

Note: This also disables row selections


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.


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


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


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


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


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.


Try this:

listViewObject.setTranscriptMode(0);

Works for me.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号