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

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

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

  • Android ProgressBar.setProgressDrawable only works once?
  • Save Image From WebView
  • Android Studio: Error Code 1: Gradle: Execution failed for task ':app:processDebugResources'
  • Being told project is not using the gradle build system when it is
  • java.lang.IllegalStateException: Failure saving state: active has cleared index in fragment
  • Place cursor at the end of text in EditText
  • I have started with the 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:

            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.

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

  • How do I programmatically determine if an app in the play store can be installed on current device?
  • Android: upgrading DB version and adding new table
  • How to save and reuse same instance of fragments?
  • Sqlite plugin for Eclipse: debug sqlite database on Android device live
  • How to update E-mail, Address, Nickname, etc of a contact in Android?
  • CharSequence to int
  • 8 Solutions collect form web for “Detecting the scrolling direction in the adapter (up/down)”

    Assign an OnScrollListener to 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 first visible item position equals to more or less than the previous first visible item position. Put that check inside 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 mIsScrollingUp is true or false in getView(), and assign the animations accordingly.

    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;
    
    }
    

    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;
              }
          }
          });
      

    The accepted answer doesn’t really “detect” scrolling up or down. It won’t work if the current visible item is really huge. Using onTouchListener is the way to go.

    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
        }
    });
    

    Try this . I hope it helps you . Logic From @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;
    
            }
        });
    

    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.

    listView.getChildAt(0).getTop()
    

    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) {
    
    
        }
    
    }
    
    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.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.