【问题标题】:Android ListView current scroll location Y pixelsAndroid ListView 当前滚动位置 Y 像素
【发布时间】:2012-10-04 12:44:10
【问题描述】:

我正在尝试检测列表视图何时滚动超过以像素为单位的某个固定阈值(第一项的一半)。不幸的是,listview 的 getScrollY() 似乎总是返回 0 而不是滚动位置。有没有办法按像素获取实际的滚动位置?

这是我尝试使用的代码,但如前所述,它只返回 0。

getListView().setOnScrollListener(new AbsListView.OnScrollListener() {
    public void onScroll(AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
        Log.d("scroll", "scroll: " + getListView().getScrollY());
    }

    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == 0)
        Log.d("scroll", "scrolling stopped");
    }
});

【问题讨论】:

标签: android listview scroll scroll-offset


【解决方案1】:

Android 中的 ListView 没有 Y 滚动的概念,因为内容的总高度是未知的。只有显示内容的高度是已知的。

但是,可以使用以下 hack 获取可见项目的当前位置/Y 滚动:

getListView().getChildAt(0).getTop();

【讨论】:

  • 这不再起作用了。您必须将第一个可见视图的所有先前项目的高度添加到该代码段。一些内部 api 的东西最近发生了变化。我希望 api 会包含一个简单的函数来在某个时候获取这个值。现有的所有解决方案都是骇人听闻的,并且必然会与未来的 API 版本发生冲突。永远不要弄乱列表视图的子视图
【解决方案2】:

Malachiasz 答案的重构代码。该函数用于动态行高。

调用 onScroll 监听器

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (mCardsListView.getChildCount() > 0) {
                    int scrollY = getScrollY();
                }
            }
        });

getScrollY 函数

private Dictionary<Integer, Integer> mListViewItemHeights = new Hashtable<Integer, Integer>(); 
private int getScrollY() {
        View child = mCardsListView.getChildAt(0); //this is the first visible row
        if (child == null) return 0;

        int scrollY = -child.getTop();

        mListViewItemHeights.put(mCardsListView.getFirstVisiblePosition(), child.getHeight());

        for (int i = 0; i < mCardsListView.getFirstVisiblePosition(); ++i) {
            Integer hei = mListViewItemHeights.get(i);

            //Manual add hei each row into scrollY
            if (hei != null)
                scrollY += hei;
        }

        return scrollY;
    }

【讨论】:

    【解决方案3】:

    你需要两件事来精确定义 listView 的滚动位置:

    获取当前位置:

    int firstVisiblePosition = listView.getFirstVisiblePosition(); 
    int topEdge=listView.getChildAt(0).getTop(); //This gives how much the top view has been scrolled.
    

    设置位置:

    listView.setSelectionFromTop(firstVisiblePosition,0);
    // Note the '-' sign...  
    listView.scrollTo(0,-topEdge);
    

    【讨论】:

      【解决方案4】:

      您可以尝试实现OnTouchListener 并覆盖其onTouch(View v, MotionEvent event) 并使用event.getX()event.getY() 获取x 和y。我刚刚创建了一个在 ListView 行上滑动的演示,它将启用一个删除按钮,用于从 ListView 中删除特定项目。你可以在我的 github 上查看源代码ListItemSwipe

      【讨论】:

      • 这不是 y 轴的选项,因为 ListView 滚动取决于 MotionEvent 速度。
      【解决方案5】:

      也许它对某人有用。快速滚动列表时,先前答案的代码将不起作用。因为在这种情况下 firstVisiblePosition 可能会发生不规则的变化。在我的代码中,我不使用数组来存储位置

      fun setOnTouchScrollListener(lv: AbsListView, onTouchScrollListener: (isDown: Boolean, offset: Int?, isScrollWorking: Boolean) -> Unit) {
      
          var lastItemPosition: Int = -1
          var lastItemTop: Int? = null
          var lastItemHeight: Int? = null
          var lastScrollState: Int? = AbsListView.OnScrollListener.SCROLL_STATE_IDLE
      
          lv.setOnScrollListener(object : AbsListView.OnScrollListener {
      
              override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
                  val child = lv.getChildAt(0)
                  var offset: Int? = null
                  var isDown: Boolean? = if (firstVisibleItem == lastItemPosition || lastItemPosition == -1) null else firstVisibleItem > lastItemPosition
                  val dividerHeight = if (lv is ListView) lv.dividerHeight else 0
                  val columnCount = if (lv is GridView) lv.numColumns else 1
      
                  if (child != null) {
                      if (lastItemPosition != -1) {
                          when (firstVisibleItem - lastItemPosition) {
                              0 -> {
                                  isDown = if (lastItemTop == child.top) null else lastItemTop!! > child.top
                                  offset = Math.abs(lastItemTop!! - child.top)
                              }
                              columnCount -> offset = lastItemHeight!! + lastItemTop!! - child.top + dividerHeight
                              -columnCount -> offset = child.height + child.top - lastItemTop!! + dividerHeight
                          }
                      }
      
                      lastItemPosition = firstVisibleItem
                      lastItemHeight = child.height
                      lastItemTop = child.top
      
                      if (isDown != null && (offset == null || offset != 0)
                              && lastScrollState != AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                          onTouchScrollListener(isDown, offset, true)
                      }
                  }
              }
      
              override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
                  lastScrollState = scrollState
                  if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                      onTouchScrollListener(true, 0, false)
                      lastItemPosition = -1
                      lastItemHeight = null
                      lastItemTop = null
                  }
              }
          })
      }
      

      然后我们可以在列表视图滚动超过阈值时使用

      private var lastThresholdOffset = 0
      private var thresholdHeight = some value
      
      setOnTouchScrollListener(listView) { isDown: Boolean, offset: Int?, isScrollWorking: Boolean ->
          val offset = offset ?: if (isDown) 0 else thresholdHeight
          lastThresholdOffset = if (isDown) Math.min(thresholdHeight, lastThresholdOffset + offset)
          else Math.max(0, lastThresholdOffset - offset)
      
          val result = lastThresholdOffset > thresholdHeight
      }
      

      isScrollWorking - 可用于动画

      【讨论】:

        猜你喜欢
        • 2018-02-23
        • 1970-01-01
        • 2015-07-29
        • 1970-01-01
        • 1970-01-01
        • 2011-01-23
        • 1970-01-01
        • 2022-08-20
        • 2015-10-27
        相关资源
        最近更新 更多