Android 检测适配器中的滚动方向(上/下)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12114963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:47:02  来源:igfitidea点击:

Detecting the scrolling direction in the adapter (up/down)

androidlistviewanimationscrolldirection

提问by Waza_Be

I am trying to mimic the Google Plus application in my project, as it seems to be the reference now.

我试图在我的项目中模仿 Google Plus 应用程序,因为它现在似乎是参考。

The listview effect when scrolling is really nice and I would like to do something similar.

滚动时的列表视图效果非常好,我想做类似的事情。

I have started with the LayoutAnimationController http://android-er.blogspot.be/2009/10/listview-and-listactivity-layout.html

我已经开始使用 LayoutAnimationController http://android-er.blogspot.be/2009/10/listview-and-listactivity-layout.html

LayoutAnimationController controller 
   = AnimationUtils.loadLayoutAnimation(
     this, R.anim.list_layout_controller);
  getListView().setLayoutAnimation(controller);

and that seems bad, as not all the elements are animated:

这看起来很糟糕,因为并非所有元素都是动画的:

So I ended up by using the getView of the adapter and using this:

所以我最终使用了适配器的 getView 并使用了这个:

        AnimationSet set = new AnimationSet(true);

        Animation animation = new AlphaAnimation(0.0f, 1.0f);
        animation.setDuration(800);
        set.addAnimation(animation);

        animation = new TranslateAnimation(
            Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, 1.0f,Animation.RELATIVE_TO_SELF, 0.0f
        );
        animation.setDuration(600);
        set.addAnimation(animation);

        row.startAnimation(set);

The result is awesome and I am really happy with it!

结果很棒,我真的很满意!

Unfortunately, it only works when I scroll from top to bottom of the list!

不幸的是,它只有在我从列表的顶部滚动到底部时才有效!

I want to make it work when scrolling on the other side, I need to change a little bit the TranslateAnimation.

我想让它在另一边滚动时工作,我需要稍微改变一下 TranslateAnimation。

So my question, is there a way to detect if I scroll upwards or downwards in my adapter?

所以我的问题是,有没有办法检测我是在适配器中向上还是向下滚动?

采纳答案by Dennis Murage

This is the easiest and simplest method I came across. And it works like a charm.

这是我遇到的最简单、最简单的方法。它就像一个魅力。

view.addOnScrollListener(new View.OnScrollListener() {
                @Override
                public void onScrolled(@NonNull View view, int dx, int dy) {
                    if (dy > 0) {
                        //Scrolling down
                    } else if (dy < 0) {
                        //Scrolling up
                    }
                }
            });

回答by Wroclai

Assign an OnScrollListenerto your ListView. Create a flag which indicates whether the user is scrolling up or down. Set an appropriate value to the flag by checking if the current firstvisible item position equals to more or less than the previous firstvisible item position. Put that check inside onScrollStateChanged().

分配OnScrollListener给你的ListView。创建一个标志,指示用户是向上还是向下滚动。通过检查当前的第一个可见项位置是否大于或小于先前的第一个可见项位置,为标志设置适当的值。把那张支票放在里面onScrollStateChanged()

Sample code:

示例代码:

private int mLastFirstVisibleItem;
private boolean mIsScrollingUp;

public void onScrollStateChanged(AbsListView view, int scrollState) {
    final ListView lw = getListView();

    if (view.getId() == lw.getId()) {
        final int currentFirstVisibleItem = lw.getFirstVisiblePosition();

        if (currentFirstVisibleItem > mLastFirstVisibleItem) {
            mIsScrollingUp = false;
        } else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
            mIsScrollingUp = true;
        }

        mLastFirstVisibleItem = currentFirstVisibleItem;
    } 
}

Check if mIsScrollingUpis true or false in getView(), and assign the animations accordingly.

检查 中是否mIsScrollingUp为真或假getView(),并相应地分配动画。

回答by Waza_Be

I ended up by doing this:

我最终这样做了:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Log.i("",position+" - "+lastposition);

    if (position >= lastposition)
        animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
                0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
                Animation.RELATIVE_TO_SELF, 1.0f,
                Animation.RELATIVE_TO_SELF, 0.0f);
    else
        animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
                0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
                Animation.RELATIVE_TO_SELF, -1.0f,
                Animation.RELATIVE_TO_SELF, 0.0f);

    animation.setDuration(600);
    set.addAnimation(animation);

    row.startAnimation(set);

    lastposition = position;

}

回答by recoilme

More complex solution (working with long items height in listview)

更复杂的解决方案(在列表视图中使用长项目高度)

  1. Create custom listview

    public class ScrollDetectingListView extends ListView {
        public ScrollDetectingListView(Context context) {
            super(context);
        }
    
        public ScrollDetectingListView(Context context, AttributeSet attrs) {
            super(context,attrs);
        } 
    
        public ScrollDetectingListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        //we need this protected method for scroll detection
        public int getVerticalScrollOffset() {
            return computeVerticalScrollOffset();
        }
    }
    
  2. Override onScroll

        listView.setOnScrollListener(new AbsListView.OnScrollListener() {
    
        private int mInitialScroll = 0;
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            int scrolledOffset = listView.getVerticalScrollOffset();
            if (scrolledOffset!=mInitialScroll) {
                //if scroll position changed
                boolean scrollUp = (scrolledOffset - mInitialScroll) < 0;
                mInitialScroll = scrolledOffset;
            }
        }
        });
    
  1. 创建自定义列表视图

    public class ScrollDetectingListView extends ListView {
        public ScrollDetectingListView(Context context) {
            super(context);
        }
    
        public ScrollDetectingListView(Context context, AttributeSet attrs) {
            super(context,attrs);
        } 
    
        public ScrollDetectingListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        //we need this protected method for scroll detection
        public int getVerticalScrollOffset() {
            return computeVerticalScrollOffset();
        }
    }
    
  2. 覆盖 onScroll

        listView.setOnScrollListener(new AbsListView.OnScrollListener() {
    
        private int mInitialScroll = 0;
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            int scrolledOffset = listView.getVerticalScrollOffset();
            if (scrolledOffset!=mInitialScroll) {
                //if scroll position changed
                boolean scrollUp = (scrolledOffset - mInitialScroll) < 0;
                mInitialScroll = scrolledOffset;
            }
        }
        });
    

回答by maverick97

The accepted answer doesn't really "detect" scrolling up or down. It won't work if the current visible item is really huge. Using onTouchListeneris the way to go.

接受的答案并没有真正“检测”向上或向下滚动。如果当前可见的项目真的很大,它将不起作用。使用onTouchListener是要走的路。

This is the code snippet I used:

这是我使用的代码片段:

listView.setOnTouchListener(new View.OnTouchListener() {
    float initialY, finalY;
    boolean isScrollingUp;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = MotionEventCompat.getActionMasked(event);

        switch(action) {
            case (MotionEvent.ACTION_DOWN):
                initialY = event.getY();
            case (MotionEvent.ACTION_UP):
                finalY = event.getY();

                if (initialY < finalY) {
                    Log.d(TAG, "Scrolling up");
                    isScrollingUp = true;
                } else if (initialY > finalY) {
                    Log.d(TAG, "Scrolling down");
                    isScrollingUp = false;
                }
            default:
        }

        if (isScrollingUp) {
            // do animation for scrolling up
        } else {
            // do animation for scrolling down
        }

        return false; // has to be false, or it will freeze the listView
    }
});

回答by IntelliJ Amiya

Try this . I hope it helps you . Logic From @Gal Rom Answer .

尝试这个 。我希望它可以帮助你。来自@Gal Rom Answer 的逻辑。

lv.setOnScrollListener(new OnScrollListener() {
        private int mLastFirstVisibleItem;

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {

        }

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

            if(mLastFirstVisibleItem<firstVisibleItem)
            {
                Log.i("SCROLLING DOWN","TRUE");
            }
            if(mLastFirstVisibleItem>firstVisibleItem)
            {
                Log.i("SCROLLING UP","TRUE");
            }
            mLastFirstVisibleItem=firstVisibleItem;

        }
    });

回答by Nelson Ramirez

Here's my approach: It gets you more immediate feedback on how much you've scrolled: OnScroll, you can just get the Top position of the first item in your list. It's a pretty reliable to get actual scroll position information immediately.

这是我的方法:它可以让你更直接地反馈你滚动了多少: OnScroll,你可以只获得列表中第一项的顶部位置。立即获取实际滚动位置信息是非常可靠的。

listView.getChildAt(0).getTop()

回答by Vaiden

I've used this much simpler solution:

我使用了这个更简单的解决方案:

public class ScrollDetectingListView extends ListView

...

...

setOnScrollListener( new OnScrollListener() 
{

    private int mInitialScroll = 0;

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

        boolean scrollUp = scrolledOffset > mInitialScroll;
        mInitialScroll = scrolledOffset;
    }


    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {


    }

}

回答by Karthik Rk

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

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            if(last_item<firstVisibleItem+visibleItemCount-1){
                System.out.println("List is scrolling upwards");
            }
            else if(last_item>firstVisibleItem+visibleItemCount-1){
                System.out.println("List is scrolling downwards");
            }
             last_item = firstVisibleItem+visibleItemCount-1;
        }
    });

Based on the position of the last visible item i decide whether Listview is going up or down.

根据最后一个可见项目的位置,我决定 Listview 是向上还是向下。

回答by Damon

General solution that doesn't rely on positions of views/etc. Just check the vertical scroll offset and compare it to the previous scroll offset. If the new value is greater than the old the user is scrolling down, and vice-versa.

不依赖于视图/等位置的通用解决方案。只需检查垂直滚动偏移并将其与之前的滚动偏移进行比较。如果新值大于旧值,则用户向下滚动,反之亦然。

// [START check vertical scroll direction]
int oldScrollOffset = 0;

listView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
        @Override
        public void onScrollChange(View view, int i, int i1, int i2, int i3) {

            Boolean scrollDirectionDown;

            int newScrollOffset = listView.computeVerticalScrollOffset();

            if (newScrollOffset > oldScrollOffset) {
                scrollDirectionDown = true;
            } else {
                scrollDirectionDown = false;
            }

            oldScrollOffset = newScrollOffset;

            if (scrollDirectionDown) {
                // Update accordingly for scrolling down
                Log.d(TAG, "scrolling down");
            } else {
                // Update accordingly for scrolling up
                Log.d(TAG, "scrolling up");
            }

    });
// [END check vertical scroll direction]