【问题标题】:Android: onScrollStateChanged SCROLL_STATE_IDLE sometimes doesn't fireAndroid:onScrollStateChanged SCROLL_STATE_IDLE 有时不会触发
【发布时间】:2011-11-15 17:35:50
【问题描述】:

我遇到了一些问题。我在做什么:我有一个 ListView,里面有一些图像。为了使滚动更流畅,我禁用了滚动时显示的图像。现在,Android 中似乎有一个bug,它有时会导致滚动状态不会从 SCROLL_STATE_FLING 变回 SCROLL_STATE_IDLE,这会导致我的图像不再显示。

我的第一个想法是设置一个 onTouchListener 并检查何时获得 ACTION_UP,但这无济于事,因为 SCROLL_STATE_FLING 状态显然是在那之后设置的。所以现在我想我可以在设置 SCROLL_STATE_FLING 状态时启动一个计时器,并在一段时间后检查该状态是否仍处于投掷模式,然后使我的视图无效。但我认为这不是一个很好的解决方案。

有没有人对我如何做到这一点有更好的想法?我已经看到this 的回复,但我需要 API 级别

这是我的代码:

    mList.setOnScrollListener(new OnScrollListener() {

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            mListAdapter.setIsScrolling(scrollState != SCROLL_STATE_IDLE);
            Log.i(this, "scrollStateChanged" + scrollState);
            if (scrollState == SCROLL_STATE_IDLE) {
                mList.invalidateViews();
            }
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        }
    });

谢谢, 玛丽亚

【问题讨论】:

    标签: android listview scroll


    【解决方案1】:

    我遇到了同样的问题,所以我的解决方案是检测滚动视图位置是否已到达最后一页,在这种情况下,无论滚动状态如何,始终加载图像(因为问题似乎总是在用户甩动时发生到列表视图的末尾)。所以修改你的代码你会:

    mList.setOnScrollListener(new OnScrollListener() {
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            mListAdapter.setIsScrolling(scrollState != SCROLL_STATE_IDLE);
            Log.i(this, "scrollStateChanged" + scrollState);
    
            int first = view.getFirstVisiblePosition();
            int count = view.getChildCount();
    
            if (scrollState == SCROLL_STATE_IDLE || (first + count > mListAdapter.getCount()) ) {
                mList.invalidateViews();
            }
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        }
    });
    

    【讨论】:

    • 不客气。我发现当您的手指仍在触摸屏幕时点击列表视图的末尾。所以这也可能发生在列表视图的顶部。我的代码可以修改为也总是加载第一页。
    • 是的,它也发生在顶部,但这是一个简单的改变。
    • @MariaNeumayer 这个简单的改变是什么?
    【解决方案2】:

    我在RecyclerView 遇到了同样的问题。

    Jason Burke's answer 是正确的,但我将提供另一种方法来检查您是否位于 RecyclerView/ListView 的开头/结尾。

    我在onScrolled 而不是onScrollStateChanged 中执行此操作,因为我不相信在您滚动/弹到RecyclerView 边缘的情况下我会收到状态更改事件。

    recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
    
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                updateUi()
            }
        }
    
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
    
            /* If the user scrolls to the edges of the recyclerview, we can't trust that we get the SCROLL_STATE_IDLE state.
             * Therefore we have to update the view here in onScrolled for these cases
             */
            if (!recyclerView.canScrollVertically(1) || !recyclerView.canScrollVertically(-1)) {
                updateUi()
            }
        }
    }
    

    在我的例子中,它实际上是一个水平的 RecyclerView,所以我不得不这样做:

    if (!recyclerView.canScrollHorizontally(1) || !recyclerView.canScrollHorizontally(-1)) {
        updateUi()
    }
    

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,并在bug list 上发布了解决方法:

      对于仍然遇到这个问题的任何人(就像我上周一样) 对我有用的解决方法如下:如果 android SDKInt == 7 在(Abs)ListView 上设置onTouchListener

      onTouchListener 中,当OnTouch 事件操作是 MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL你逼 一个onScrollStateChanged,首先是一个SCROLL_STATE_FLING,然后是一个 SCROLL_STATE_IDLE

      代码示例:在onCreate

        if(androidSDKInt <= 7){
            listViewDateSelector.setOnTouchListener(new FingerTracker(onScrollListener));       }
      

      然后添加一个私有类:

        private class FingerTracker implements View.OnTouchListener {
            private OnScrollListener myOnScrollListener;
      
            public FingerTracker(OnScrollListener onScrollListener){
                myOnScrollListener = onScrollListener;          }
      
            public boolean onTouch(View view, MotionEvent event) {
                final int action = event.getAction();
                boolean mFingerUp = action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL;
                if (mFingerUp) {
                    myOnScrollListener.onScrollStateChanged((AbsListView) view, OnScrollListener.SCROLL_STATE_FLING);
                    myOnScrollListener.onScrollStateChanged((AbsListView) view, OnScrollListener.SCROLL_STATE_IDLE);
                }
                return false;           }       }
      

      【讨论】:

      • 但这会导致空闲状态被设置,而它可能仍然在抛出,对吗?
      • 是的。没想到。它也会在投掷时调用空闲方法......这对我的实现来说没问题,因为投掷仍然会继续,完成后它会自动重置空闲状态,但我可以想象这可能不适用于所有人。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多