禁用列表视图中的滚动
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);
为我工作。
【讨论】:
以上是关于禁用列表视图中的滚动的主要内容,如果未能解决你的问题,请参考以下文章