Отключить прокрутку в списке
У меня есть представление списка и в зависимости от какой-то логики я хочу временно отключить прокрутку. view.setOnScrollListener(нуль); мне не помогает, я думаю, мне нужно написать код, кто-то может дать мне историю или какой-нибудь фрагмент?
Спасибо
11 ответов
В вашем CustomListView:
@Override
public boolean dispatchTouchEvent(MotionEvent ev){
if(ev.getAction()==MotionEvent.ACTION_MOVE)
return true;
return super.dispatchTouchEvent(ev);
}
Тогда ListView будет реагировать на нажатия, но не будет изменять положение прокрутки.
Другим вариантом без создания нового пользовательского ListView будет прикрепление onTouchListener
к вашему ListView и верните true в onTouch()
обратный вызов, если действие события движения ACTION_MOVE
,
listView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
Используйте listview.setEnabled(false), чтобы отключить прокрутку списка.
Примечание: это также отключает выбор строки
Сделай свой CustomListView
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(needToStop){
return false;}
return super.onInterceptTouchEvent(ev);
}
на false
дети будут обрабатывать событие касания, убедитесь, что вы поставили if condition
чтобы проверить нужно прокрутить или нет.
Если у вас есть событие, связанное с элементами списка, то перетаскивание списка с любым из этих решений все равно вызовет событие. Вы хотите использовать следующий метод для учета ожиданий пользователей отменить событие, перетаскивая его из выбранного элемента (адаптировано из ответа 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
Лучший ответ для меня - это тот, что дан Даном Осиповым. Я бы улучшил это так. (запуск события действия ОТМЕНА вместо ручного стирания нажатого состояния).
@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);
}
При написании кода для удаления для просмотра в виде списка, я хотел предотвратить вертикальную прокрутку после обнаружения удара. Я установил логический флаг в разделе 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);
}
Мой ответ будет интересен пользователям Xamarin и MvvmCross. Основная концепция та же, что и в предыдущих постах, поэтому основными шагами являются:
- События Mute Scroll
- Динамически изменять высоту списка
Вот вам вспомогательный класс, который позволяет отключить прокрутку в виде списка:
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 ();
}
}
}
Это код, на который указал Джо Блоу (комментарий к сообщению ОП) на 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 в свой макет, не забудьте добавить к нему имя пакета, в противном случае при попытке его раздувания возникнет исключительная ситуация.
Попробуй это:
listViewObject.setTranscriptMode(0);
Работает для меня.
Поместите listView внутри вложенногоScrollView и отключите прокрутку, используя один из следующих вариантов:
yourListView.stopNestedScroll()
yourListView.isNestedScrollingEnabled = false
yourListView.transcriptMode = 0
android:descendantFocusability="blocksDescendants"
android:nestedScrollingEnabled="false"
Примечание. Достаточно использовать один из следующих вариантов. Примечание: это работает только в том случае, если listView помещен внутри вложенногоScrollView. Если вы не хотите, чтобы ваш listView находился внутри вложенногоScrollView, и все еще хотите отключить прокрутку, вам нужно создать CustomListView, как предложено в принятом ответе.