禁用列表视图中的滚动

发布于 2024-12-07 07:07:40 字数 112 浏览 0 评论 0原文

我有一个列表视图,根据某些逻辑我想暂时禁用滚动。 view.setOnScrollListener(null);对我没有帮助,我想我需要编写一些代码,有人可以给我一个历史记录或一些片段吗?

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

婴鹅 2024-12-14 07:07:40

在您的 CustomListView 中:

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

然后 ListView 将对点击做出反应,但不会更改滚动位置。

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.

城歌 2024-12-14 07:07:40

无需创建新的自定义 ListView 的另一种选择是将 onTouchListener 附加到 ListView,并在 onTouch() 回调中返回 true(如果运动事件操作为 ACTION_MOVE)

listView.setOnTouchListener(new OnTouchListener() {

    public boolean onTouch(View v, MotionEvent event) {
        return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
});

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);
    }
});
时光是把杀猪刀 2024-12-14 07:07:40

使用 listview.setEnabled(false) 禁用列表视图滚动

注意:这也会禁用行选择

use listview.setEnabled(false) to disable listview scrolling

Note: This also disables row selections

爱情眠于流年 2024-12-14 07:07:40

将您的 CustomListView 设置

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

false ,子级将处理触摸事件,请确保您设置了 if 条件 来检查是否需要滚动。

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.

梦行七里 2024-12-14 07:07:40

如果您有一个事件绑定到列表项,则使用任何这些解决方案拖动列表仍将触发该事件。您希望使用以下方法来满足用户通过拖动所选项目来取消事件的期望(改编自 Pointer Null 的答案):

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

可以使用完整的自定义视图类: https://gist.github.com/danosipov/6498490

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

逆蝶 2024-12-14 07:07:40

对我来说最好的答案是 Dan Osipov 的答案。
我会像这样改进它。 (触发取消操作事件而不是手动擦除按下状态)。

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

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);
}
伴随着你 2024-12-14 07:07:40

在编写用于在列表视图上滑动删除的代码时,我想在检测到滑动后阻止垂直滚动。一旦满足滑动删除条件,我就会在 ACTION_MOVE 部分设置一个布尔标志。 dispatchTouchEvent 方法检查该条件并阻止滚动工作。在 ACTION_UP 中,我将标志设置回 false 以重新启用滚动。

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

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);
}
财迷小姐 2024-12-14 07:07:40

我的回答对于 Xamarin 和 MvvmCross 用户来说会很有趣。主要概念与之前的文章相同,因此主要步骤是:

  1. 静音滚动事件
  2. 动态更改列表高度

这里您是帮助器类,它允许在列表视图中禁用滚动:

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

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 ();
        }
    }
}
甜中书 2024-12-14 07:07:40

这是 Joe Blow(对 OP 帖子的评论)在 http://danosipov.com/?p= 上指出的代码604 但我将其发布在这里是为了保留它,以防链接被孤立:

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

当您将此 ListView 添加到布局中时,请记住在其前面加上其包名称,否则当您尝试膨胀时将引发异常它。

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.

没有你我更好 2024-12-14 07:07:40

试试这个:

listViewObject.setTranscriptMode(0);

对我有用。

Try this:

listViewObject.setTranscriptMode(0);

Works for me.

泪意 2024-12-14 07:07:40

将 listView 放入nestedScrollView 中,并使用以下选项之一禁用滚动:

yourListView.stopNestedScroll()

yourListView.isNestedScrollingEnabled = false

yourListView.transcriptMode = 0

android:descendantFocusability="blocksDescendants"

android:nestedScrollingEnabled="false"

注意:使用以下选项之一就足够了。
注意:只有将 listView 放入nestedScrollView 中时,此方法才有效。如果您不希望 listView 位于nestedScrollView 内并且仍想禁用滚动,那么您需要按照接受的答案中的建议创建 CustomListView 。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文