首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重复调用OnScrollListener

重复调用OnScrollListener
EN

Stack Overflow用户
提问于 2019-10-14 12:54:52
回答 1查看 74关注 0票数 0

我有两个listview控件,每个控件都显示列表的部分数据。它们在UI片段中上下排列。显示的数据是汽车的轮胎信息,因此顶部的列表视图显示前轮的数据,下方的列表视图显示后轮的数据(它们之间有一个汽车图像)。对列表视图进行配置,使每个视图中的数据列表反映另一个视图中的数据。因此,顶部列表的顶部行与底部列表中的底部行具有相同的数据集。当用户滚动其中一个列表时,另一个列表以镜像方式滚动。这使得用户能够滚动数据,使得他们感兴趣的数据位于汽车图像的正上方和正下方(顶部列表的底部行,底部列表的顶部行)

为此,我在一个listview上响应OnScrollListener-OnScroll事件,进行位置计算,并在另一个listview上调用listview.setSelectionFromTop( position,sety)来更新其位置。

当我第一次发布该应用程序时,这在Android 4.xx中运行良好。现在在Android7和更高版本中,似乎正在发生竞争条件,在一个列表视图上设置位置会触发另一个列表视图上的OnScroll,然后事情就会在一系列永无止境的OnScroll事件中变得糟糕。

我尝试在OnScroll函数上添加一个标志,这样当它位于来自另一个列表视图的OnScroll调用中时,它就不会触发。这不起作用,因为从调用setSelectionFromTop触发的OnScroll事件似乎是异步的,因此它们发生在标记区域之外。

我注意到的一件事是,列表视图的大小似乎很关键,它们需要完全相同的大小。在原始布局(Android4.x)中,我已经设置了它们的layoutHeight=120dp来固定它们的大小。然而,当前的安卓系统似乎并不尊重layoutHeight的值,并且结果UI将它们显示为不同的大小,这可能是解开这个难题的关键。

下面是其中一个列表视图的onScroll代码,另一个列表视图的代码是相同的,只需将lvTop替换为lvBottom

代码语言:javascript
复制
OnScrollListener lTop=new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
    }

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

        if (fInBottomScrollListener)
            return;

        fInTopScrollListener=true;

        // Get position of this lv top
        View cTop = lvTop.getChildAt(0);
        View cBottom = lvBottom.getChildAt(0);
        if (cTop==null || cBottom==null) return;

        int topOffset = cTop.getTop();
        int itemHeight = cTop.getHeight();
        int firstVisPos = lvTop.getFirstVisiblePosition();

        int setposition = totalItemCount - (visibleItemCount - (topOffset!=0 ? 1:0)) - firstVisPos-1;
        int sety= -(itemHeight + (topOffset>0 ? 0:topOffset));

        lvBottom.setSelectionFromTop(setposition, sety);
        fInTopScrollListener=false;
    }
};

我在日志中看到一个连续的onScroll事件列表,当在Android4.x上运行时,这个列表在滚动完成后停止,而在7.x和更高版本上,它继续,滚动在两个列表视图上基本上是冻结的,直到我刷新片段

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-18 22:58:37

我认为你对位置和偏移量的计算是不正确的,所以2个ListViews是因为一个小的偏移量误差而跳动。

对于相同高度的ListViews:

代码语言:javascript
复制
AbsListView.OnScrollListener lTop = new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {}

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

        if (!fInBottomScrollListener) {
            fInTopScrollListener = true;
            View cTop = lvTop.getChildAt(visibleItemCount - 1);
            if (cTop == null) return;
            int setposition = totalItemCount - visibleItemCount - firstVisibleItem;
            int sety = view.getHeight() - cTop.getBottom();
            lvBottom.setSelectionFromTop(setposition, sety);
            fInTopScrollListener = false;
        }
    }
};

AbsListView.OnScrollListener lBottom = new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {}

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

        if (!fInTopScrollListener) {
            fInBottomScrollListener = true;
            View cBottom = lvBottom.getChildAt(visibleItemCount - 1);
            if (cBottom == null) return;
            int setposition = totalItemCount - visibleItemCount - firstVisibleItem;
            int sety = view.getHeight() - cBottom.getBottom();
            lvTop.setSelectionFromTop(setposition, sety);
            fInBottomScrollListener = false;
        }
    }
};

更新:

这是另一种方法,不管列表视图的高度是否相同:

代码语言:javascript
复制
final private static int SCROLL_DELAY = 100;
long timestampScroll;

AbsListView.OnScrollListener lTop = new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {}

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

        if (!fInBottomScrollListener) {
            fInTopScrollListener = true;
            View cTop = lvTop.getChildAt(0);
            View cBot = lvBottom.getChildAt(0);
            if (cTop == null || cBot == null) return;
            int lvTopMovableRange = (cTop.getHeight() + lvTop.getDividerHeight()) * totalItemCount
                    - lvTop.getDividerHeight() - lvTop.getHeight();
            int lvBotMovableRange = (cBot.getHeight() + lvBottom.getDividerHeight()) * totalItemCount
                    - lvBottom.getDividerHeight() - lvBottom.getHeight();
            int lvTopPointer = (cTop.getHeight() + lvTop.getDividerHeight()) * firstVisibleItem
                    - cTop.getTop();
            int lvBotPointer = (int)((float)(lvTopMovableRange - lvTopPointer)/lvTopMovableRange*lvBotMovableRange);
            int setposition = lvBotPointer / (cBot.getHeight() + lvBottom.getDividerHeight());
            int sety = -lvBotPointer + setposition * (cBot.getHeight() + lvBottom.getDividerHeight());
            timestampScroll = System.currentTimeMillis();
            lvBottom.setSelectionFromTop(setposition, sety);
            lvTop.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (System.currentTimeMillis() - timestampScroll > (SCROLL_DELAY - 10)) fInTopScrollListener = false;
                }
            }, SCROLL_DELAY);
        }
    }
};

AbsListView.OnScrollListener lBottom = new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {}

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

        if (!fInTopScrollListener) {
            fInBottomScrollListener = true;
            View cTop = lvTop.getChildAt(0);
            View cBot = lvBottom.getChildAt(0);
            if (cTop == null || cBot == null) return;
            int lvTopMovableRange = (cTop.getHeight() + lvTop.getDividerHeight()) * totalItemCount
                    - lvTop.getDividerHeight() - lvTop.getHeight();
            int lvBotMovableRange = (cBot.getHeight() + lvBottom.getDividerHeight()) * totalItemCount
                    - lvBottom.getDividerHeight() - lvBottom.getHeight();
            int lvBotPointer = (cBot.getHeight() + lvBottom.getDividerHeight()) * firstVisibleItem
                    - cBot.getTop();
            int lvTopPointer = (int)((float)(lvBotMovableRange - lvBotPointer)/lvBotMovableRange*lvTopMovableRange);
            int setposition = lvTopPointer / (cTop.getHeight() + lvTop.getDividerHeight());
            int sety = -lvTopPointer + setposition * (cTop.getHeight() + lvTop.getDividerHeight());
            timestampScroll = System.currentTimeMillis();
            lvTop.setSelectionFromTop(setposition, sety);
            lvBottom.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (System.currentTimeMillis() - timestampScroll > (SCROLL_DELAY - 10)) fInBottomScrollListener = false;
                }
            }, SCROLL_DELAY);
        }
    }
};

希望这能有所帮助!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58370288

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档