禁用列表视图中的滚动

Posted

技术标签:

【中文标题】禁用列表视图中的滚动【英文标题】:Disable scrolling in listview 【发布时间】:2011-11-28 11:49:01 【问题描述】:

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

谢谢

【问题讨论】:

是的,我只需要禁用滚动 2-3 秒 唯一的解决方案 ...danosipov.com/?p=604 【参考方案1】:

另一个不创建新的自定义 ListView 的选项是将 onTouchListener 附加到您的 ListView 并在运动事件操作为 ACTION_MOVE 时在 onTouch() 回调中返回 true。

listView.setOnTouchListener(new OnTouchListener() 

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

【讨论】:

或者,更短更简洁,return (event.getAction() == MotionEvent.ACTION_MOVE); 如果 ListView 包含任何按钮甚至是拉动刷新,则此 根本不起作用。它只是不起作用,如果用户碰巧滚动到其中一个按钮上 - 它会滚动。它根本不可用。【参考方案2】:

在您的 CustomListView 中:

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

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

【讨论】:

很久以前我就遇到了这个问题,但我认为这是正确的解决方案(我解决了管理可见性的问题) 看起来这个解决方案只是部分解决方案,并且在任何连接了外部键盘或 BT/USB 键盘的设备上都会失败。 不幸的是,这也根本行不通。如果您在按钮或任何东西上滑动,您仍然会获得滚动效果。 使用 Nikita 的解决方案,方法很简单【参考方案3】:

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

注意:这也会禁用行选择

【讨论】:

为我工作,我不知道为什么其他人都在走这么复杂的路线。 这个解决方案也为我解决了这个问题!谢谢。 这不起作用,因为它还会禁用列表视图行选择 为我工作,因为我尝试禁用所有列表视图 这是最好最简单的方法。【参考方案4】:

让你的CustomListView

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

false 上,孩子们将处理触摸事件,请确保您输入您的if condition 以检查您是否需要滚动。

【讨论】:

嗯,这是一个很好的提示,但对我不起作用。这是我在 onTouch 时需要禁用滚动的问题,并且在 onTouch 中返回 false 不会禁用滚动。 :( :),你不明白我的意思。我不能在 onInterceptTouchEvent 中返回 false,因为我需要调用所有其他方法,例如 onTouch btw 之类的方法(我正在制作拖放应用程序)。这就是为什么我按下了我调用的 onInterceptTouchEvent 但我没有松开我的手指并且 onTouch 被调用了很多次所以在这里我想禁用滚动.... @MoshErsan :你能解释一下我们如何禁用父 TochEvent 而孩子需要它进行内部滚动吗?我真的需要这个。【参考方案5】:

如果您将事件绑定到列表项,则使用这些解决方案中的任何一个拖动列表仍会触发该事件。您想使用以下方法来说明用户期望通过拖离所选项目来取消事件(改编自 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

【讨论】:

对我有帮助,很好!【参考方案6】:

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

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

【讨论】:

【参考方案7】:

在为列表视图上的滑动删除编写代码时,我想在检测到滑动后阻止垂直滚动。一旦满足滑动删除条件,我就会在 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);

【讨论】:

【参考方案8】:

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

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

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

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

【讨论】:

【参考方案9】:

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

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 到你的布局时,记得在它前面加上它的包名,否则当你尝试膨胀它时会抛出异常。

【讨论】:

【参考方案10】:

试试这个:

listViewObject.setTranscriptMode(0);

为我工作。

【讨论】:

以上是关于禁用列表视图中的滚动的主要内容,如果未能解决你的问题,请参考以下文章

MFsidemenu 禁用滚动表视图

禁用滚动视图中的反弹禁用 pageView 控制器中的水平滚动

如何根据文本视图内容大小设置滚动视图中的启用或禁用滚动?

自定义滚动谷歌颤动中的水平列表视图

iOS 中的动态布局

滚动视图中不可滚动的表视图