I have a long itemView in RecyclerView adapter and what I want is a listener to check if a view in itemView is visible or not, while scrolling recyclerView.
What I need is somthing like "onRecyclerViewScrolled()" in this example code:
public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {
#Override
public void onBindViewHolder(#NonNull final ViewHolder myViewHolder, int
position) {
onRecyclerViewScrolled() {
if (!isVisible(myViewHolder.myView)) {
//do something
}
}
}
}
public static boolean isVisible(final View view) {
if (view == null) {
return false;
}
if (!view.isShown()) {
return false;
}
final Rect actualPosition = new Rect();
view.getGlobalVisibleRect(actualPosition);
final Rect screen = new Rect(0, 0, getScreenWidth(), getScreenHeight());
return actualPosition.intersect(screen);
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
You can set addOnScrollListener on your RecyclerView to get notified when the user scrolls, and you can get the first/last visible views from LinearLayoutMangar or GridLayoutManager:
RecyclerView recycler = findViewById(R.id.recycler_view);
reycler.setAdapter(YOUR_ADAPTER);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recycler.setLayoutManager(layoutManager);
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//First visible item position.
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
//Last visible item position.
int lastVisiblePosition = layoutManager.findLastVisibleItemPosition();
/*If you really need to access your visible views,
Loop through all the visible views*/.
for (int position = firstVisiblePosition; position == lastVisiblePosition; position++) {
View lastVisibleView = layoutManager.getChildAt(firstVisiblePosition);
//do something
}
dataList.get(firstVisiblePosition);
}
});
More info from documentation RecyclerView.OnScrollListener have to functions:
onScrolled(RecyclerView recyclerView, int dx, int dy)
Callback method to be invoked when the RecyclerView has been scrolled.
onScrollStateChanged(RecyclerView recyclerView, int newState)
Callback method to be invoked when RecyclerView's scroll state changes.
Apparently, onScrolled is called when the scroll is completed.
For more info see Yigit answer`s
I need to implement animations in RecyclerView which has a slide up effect for every item. I have searched for this and tried many different things. It works when you scroll but it is not working when the page loads for the first time. I have uploaded a video on this link.
I have tried this code
#Override
public void onBindViewHolder(ViewHolderHelper holder, int position, List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
setAnimation(holder.itemView, position);
}
private void setAnimation(View viewToAnimate, int position) {
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(mcontext, R.anim.slide_in_bottom_list_item);
animation.setInterpolator(new AccelerateInterpolator());
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
Also tried
animation.setStartOffset(position * 100);
but that is missing an item on fast scrolling
Can anyone help me ?
After searching on internet i decided to do a hacky solution.
animation.setStartOffset(position * 100);
Many post has this suggestion. But this is messing when you scroll fast in the recyclerview.
So i decided to do this offset for onlt first few visible items and then animation applies to other rows correctly without offset.
#Override
public void onBindViewHolder(ViewHolderHelper holder, int position, List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
setAnimation(holder.itemView, position);
}
private void setAnimation(View viewToAnimate, int position)
{
if (position > lastPosition)
{
Animation animation = AnimationUtils.loadAnimation(mcontext, R.anim.slide_in_bottom_list_item);
animation.setInterpolator(new DecelerateInterpolator());
if(position < 4)
animation.setStartOffset(position * 200);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
Hope this helps someone.
I am using a RecyclerView with a custom RecyclerViewOnScrollListener.
I'd like to change the RecyclerView item height when scrolling down and go back to the original height when scrolling up.
I am already animating a bottomBar in the same listener, but I can't understand how to animate every item in RecyclerView. I've tried with a for loop but I don't think is the right idea.
public abstract class RecyclerViewOnScrollListener extends RecyclerView.OnScrollListener {
private LinearLayout bottomBarContainer;
private boolean animateItems = false;
CardStackLayoutManager cardStackLayoutManager;
public RecyclerViewOnScrollListener(LinearLayout bottomBarContainer) {
this.bottomBarContainer = bottomBarContainer;
}
public RecyclerViewOnScrollListener(LinearLayout bottomBarContainer, boolean animateItems, CardStackLayoutManager cardStackLayoutManager) {
this.bottomBarContainer = bottomBarContainer;
this.animateItems = animateItems;
this.cardStackLayoutManager = cardStackLayoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (bottomBarContainer==null || dy==0 ) {
return;
}
long ANIMATION_DURATION = 200L;
if (dy>0) { // Scrolling to bottom
if (mIsScrollDirectionLocked && mScrollingDirection!=0) return;
if (bottomBarContainer.getVisibility()== View.GONE || mIsAnimatingOff) {
return;
} else {
for(int i = 0;i < cardStackLayoutManager.getChildCount();i++)
{
View view = cardStackLayoutManager.getChildAt(i);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"y",0f,200f);
objectAnimator.setDuration(150);
objectAnimator.start();
}
mScrollingDirection = SCROLLING_DOWN;
mIsAnimatingOff = !mIsAnimatingOff;
ViewCompat.setTranslationY(bottomBarContainer, 0F);
ViewCompat.animate(bottomBarContainer)
.translationY(bottomBarContainer.getHeight())
.setDuration(ANIMATION_DURATION)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
#Override
public void onAnimationEnd(View view) {
mIsAnimatingOff = !mIsAnimatingOff;
bottomBarContainer.setVisibility(View.GONE);
}
}).start();
}
} else { // Scrolling to top
if (mIsScrollDirectionLocked && mScrollingDirection!=0) return;
if (bottomBarContainer.getVisibility()!=View.VISIBLE && !mIsAnimatingOn) {
mScrollingDirection = SCROLLING_UP;
mIsAnimatingOn = !mIsAnimatingOn;
bottomBarContainer.setVisibility(View.VISIBLE);
for(int i = 0;i < cardStackLayoutManager.getChildCount();i++)
{
View view = cardStackLayoutManager.getChildAt(i);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"y",200f,0f);
objectAnimator.setDuration(150);
objectAnimator.start();
}
ViewCompat.setTranslationY(bottomBarContainer, bottomBarContainer.getHeight());
ViewCompat.animate(bottomBarContainer)
.translationY(0F)
.setDuration(ANIMATION_DURATION)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
#Override
public void onAnimationEnd(View view) {
mIsAnimatingOn = !mIsAnimatingOn;
}
}).start();
}
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!mIsScrollDirectionLocked) return;
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
mScrollingDirection = 0;
break;
default:
break;
}
}
private static final int SCROLLING_UP = 1;
private static final int SCROLLING_DOWN = 2;
private int mScrollingDirection = 0;
private boolean mIsScrollDirectionLocked = false;
private boolean mIsAnimatingOff = false;
private boolean mIsAnimatingOn = false;
}
Define a method to animate your ConvertView like below:
private void setAnimation(View viewToAnimate,int position) {
if (position > lastPosition) {
lastPosition = position;
Animation animation = AnimationUtils.loadAnimation(activity, R.anim.anim_content);
viewToAnimate.startAnimation(animation);
}
}
And in your Adapter's onBindViewHolder method call your animation method:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// Do your initialization
setAnimation(holder.convertView, position);
}
Here's the animation: (anime_content.xml)
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromYDelta="25%p"
android:toYDelta="0%p"
android:duration="300"
android:interpolator="#android:anim/decelerate_interpolator" />
This example will animate your last inflated recycler view row from down to up. You can change your animation how ever you want.
Good Luck!
I'm using the new RecyclerView-Layout in a SwipeRefreshLayout and experienced a strange behaviour. When scrolling the list back to the top sometimes the view on the top gets cut in.
If i try to scroll to the top now - the Pull-To-Refresh triggers.
If i try and remove the Swipe-Refresh-Layout around the Recycler-View the Problem is gone. And its reproducable on any Phone (not only L-Preview devices).
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<android.support.v7.widget.RecyclerView
android:id="#+id/hot_fragment_recycler"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
That's my layout - the rows are built dynamically by the RecyclerViewAdapter (2 Viewtypes in this List).
public class HotRecyclerAdapter extends TikDaggerRecyclerAdapter<GameRow> {
private static final int VIEWTYPE_GAME_TITLE = 0;
private static final int VIEWTYPE_GAME_TEAM = 1;
#Inject
Picasso picasso;
public HotRecyclerAdapter(Injector injector) {
super(injector);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position, int viewType) {
switch (viewType) {
case VIEWTYPE_GAME_TITLE: {
TitleGameRowViewHolder holder = (TitleGameRowViewHolder) viewHolder;
holder.bindGameRow(picasso, getItem(position));
break;
}
case VIEWTYPE_GAME_TEAM: {
TeamGameRowViewHolder holder = (TeamGameRowViewHolder) viewHolder;
holder.bindGameRow(picasso, getItem(position));
break;
}
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
switch (viewType) {
case VIEWTYPE_GAME_TITLE: {
View view = inflater.inflate(R.layout.game_row_title, viewGroup, false);
return new TitleGameRowViewHolder(view);
}
case VIEWTYPE_GAME_TEAM: {
View view = inflater.inflate(R.layout.game_row_team, viewGroup, false);
return new TeamGameRowViewHolder(view);
}
}
return null;
}
#Override
public int getItemViewType(int position) {
GameRow row = getItem(position);
if (row.isTeamGameRow()) {
return VIEWTYPE_GAME_TEAM;
}
return VIEWTYPE_GAME_TITLE;
}
Here's the Adapter.
hotAdapter = new HotRecyclerAdapter(this);
recyclerView.setHasFixedSize(false);
recyclerView.setAdapter(hotAdapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
contentView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
loadData();
}
});
TypedArray colorSheme = getResources().obtainTypedArray(R.array.main_refresh_sheme);
contentView.setColorSchemeResources(colorSheme.getResourceId(0, -1), colorSheme.getResourceId(1, -1), colorSheme.getResourceId(2, -1), colorSheme.getResourceId(3, -1));
And the code of the Fragment containing the Recycler and the SwipeRefreshLayout.
If anyone else has experienced this behaviour and solved it or at least found the reason for it?
write the following code in addOnScrollListener of the RecyclerView
Like this:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int topRowVerticalPosition =
(recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop();
swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0);
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
Before you use this solution:
RecyclerView is not complete yet, TRY NOT TO USE IT IN PRODUCTION UNLESS YOU'RE LIKE ME!
As for November 2014, there are still bugs in RecyclerView that would cause canScrollVertically to return false prematurely. This solution will resolve all scrolling problems.
The drop in solution:
public class FixedRecyclerView extends RecyclerView {
public FixedRecyclerView(Context context) {
super(context);
}
public FixedRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FixedRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean canScrollVertically(int direction) {
// check if scrolling up
if (direction < 1) {
boolean original = super.canScrollVertically(direction);
return !original && getChildAt(0) != null && getChildAt(0).getTop() < 0 || original;
}
return super.canScrollVertically(direction);
}
}
You don't even need to replace RecyclerView in your code with FixedRecyclerView, replacing the XML tag would be sufficient! (The ensures that when RecyclerView is complete, the transition would be quick and simple)
Explanation:
Basically, canScrollVertically(boolean) returns false too early,so we check if the RecyclerView is scrolled all the way to the top of the first view (where the first child's top would be 0) and then return.
EDIT:
And if you don't want to extend RecyclerView for some reason, you can extend SwipeRefreshLayout and override the canChildScrollUp() method and put the checking logic in there.
EDIT2:
RecyclerView has been released and so far there's no need to use this fix.
I came across the same problem recently. I tried the approach suggested by #Krunal_Patel, But It worked most of the times in my Nexus 4 and didn't work at all in samsung galaxy s2. While debugging, recyclerView.getChildAt(0).getTop() is always not correct for RecyclerView. So, After going through various methods, I figured that we can make use of the method findFirstCompletelyVisibleItemPosition() of the LayoutManager to predict whether the first item of the RecyclerView is visible or not, to enable SwipeRefreshLayout.Find the code below. Hope it helps someone trying to fix the same issue. Cheers.
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0);
}
});
This is how I have resolved this issue in my case. It might be useful for someone else who end up here for searching solutions similar to this.
recyclerView.addOnScrollListener(new OnScrollListener()
{
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
// TODO Auto-generated method stub
super.onScrolled(recyclerView, dx, dy);
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
{
// TODO Auto-generated method stub
//super.onScrollStateChanged(recyclerView, newState);
int firstPos=linearLayoutManager.findFirstCompletelyVisibleItemPosition();
if (firstPos>0)
{
swipeLayout.setEnabled(false);
}
else {
swipeLayout.setEnabled(true);
}
}
});
I hope this might definitely help someone who are looking for similar solution.
Source Code
https://drive.google.com/open?id=0BzBKpZ4nzNzURkRGNVFtZXV1RWM
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0);
}
});
None of the answers worked for me, but I managed to implement my own solution by making a custom implementation of LinearLayoutManager. Posting it here in case someone else needs it.
class LayoutManagerScrollFixed(context: Context) : LinearLayoutManager(context) {
override fun smoothScrollToPosition(
recyclerView: RecyclerView?,
state: RecyclerView.State?,
position: Int
) {
super.smoothScrollToPosition(recyclerView, state, position)
val child = getChildAt(0)
if (position == 0 && recyclerView != null && child != null) {
scrollVerticallyBy(child.top - recyclerView.paddingTop, recyclerView.Recycler(), state)
}
}
Then, you just call
recyclerView?.layoutManager = LayoutManagerScrollFixed(requireContext())
And it's working!
unfortunately, this is a known bug in LinearLayoutManager. It does not computeScrollOffset properly when the first item is visible.
will be fixed when it is released.
I have experienced same issue. I solved it by adding scroll listener that will wait until expected first visible item is drawn on the RecyclerView. You can bind other scroll listeners too, along this one. Expected first visible value is added to use it as threshold position when the SwipeRefreshLayout should be enabled in cases where you use header view holders.
public class SwipeRefreshLayoutToggleScrollListener extends RecyclerView.OnScrollListener {
private List<RecyclerView.OnScrollListener> mScrollListeners = new ArrayList<RecyclerView.OnScrollListener>();
private int mExpectedVisiblePosition = 0;
public SwipeRefreshLayoutToggleScrollListener(SwipeRefreshLayout mSwipeLayout) {
this.mSwipeLayout = mSwipeLayout;
}
private SwipeRefreshLayout mSwipeLayout;
public void addScrollListener(RecyclerView.OnScrollListener listener){
mScrollListeners.add(listener);
}
public boolean removeScrollListener(RecyclerView.OnScrollListener listener){
return mScrollListeners.remove(listener);
}
public void setExpectedFirstVisiblePosition(int position){
mExpectedVisiblePosition = position;
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
notifyScrollStateChanged(recyclerView,newState);
LinearLayoutManager llm = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstVisible = llm.findFirstCompletelyVisibleItemPosition();
if(firstVisible != RecyclerView.NO_POSITION)
mSwipeLayout.setEnabled(firstVisible == mExpectedVisiblePosition);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
notifyOnScrolled(recyclerView, dx, dy);
}
private void notifyOnScrolled(RecyclerView recyclerView, int dx, int dy){
for(RecyclerView.OnScrollListener listener : mScrollListeners){
listener.onScrolled(recyclerView, dx, dy);
}
}
private void notifyScrollStateChanged(RecyclerView recyclerView, int newState){
for(RecyclerView.OnScrollListener listener : mScrollListeners){
listener.onScrollStateChanged(recyclerView, newState);
}
}
}
Usage:
SwipeRefreshLayoutToggleScrollListener listener = new SwipeRefreshLayoutToggleScrollListener(mSwiperRefreshLayout);
listener.addScrollListener(this); //optional
listener.addScrollListener(mScrollListener1); //optional
mRecyclerView.setOnScrollLIstener(listener);
I run into the same problem. My solution is overriding onScrolled method of OnScrollListener.
Workaround is here:
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int offset = dy - ydy;//to adjust scrolling sensitivity of calling OnRefreshListener
ydy = dy;//updated old value
boolean shouldRefresh = (linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0)
&& (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) && offset > 30;
if (shouldRefresh) {
swipeRefreshLayout.setRefreshing(true);
} else {
swipeRefreshLayout.setRefreshing(false);
}
}
});
Here's one way to handle this, which also handles ListView/GridView.
public class SwipeRefreshLayout extends android.support.v4.widget.SwipeRefreshLayout
{
public SwipeRefreshLayout(Context context)
{
super(context);
}
public SwipeRefreshLayout(Context context,AttributeSet attrs)
{
super(context,attrs);
}
#Override
public boolean canChildScrollUp()
{
View target=getChildAt(0);
if(target instanceof AbsListView)
{
final AbsListView absListView=(AbsListView)target;
return absListView.getChildCount()>0
&&(absListView.getFirstVisiblePosition()>0||absListView.getChildAt(0)
.getTop()<absListView.getPaddingTop());
}
else
return ViewCompat.canScrollVertically(target,-1);
}
}
The krunal's solution is good, but it works like hotfix and does not cover some specific cases, for example this one:
Let's say that the RecyclerView contains an EditText at the middle of screen. We start application (topRowVerticalPosition = 0), taps on the EditText. As result, software keyboard shows up, size of the RecyclerView is decreased, it is automatically scrolled by system to keep the EditText visible and topRowVerticalPosition should not be 0, but onScrolled is not called and topRowVerticalPosition is not recalculated.
Therefore, I suggest this solution:
public class SupportSwipeRefreshLayout extends SwipeRefreshLayout {
private RecyclerView mInternalRecyclerView = null;
public SupportSwipeRefreshLayout(Context context) {
super(context);
}
public SupportSwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setInternalRecyclerView(RecyclerView internalRecyclerView) {
mInternalRecyclerView = internalRecyclerView;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mInternalRecyclerView.canScrollVertically(-1)) {
return false;
}
return super.onInterceptTouchEvent(ev);
}
}
After you specify internal RecyclerView to SupportSwipeRefreshLayout, it will automatically send touch event to SupportSwipeRefreshLayout if RecyclerView cannot be scrolled up and to RecyclerView otherwise.
Single line solution.
setOnScrollListener is deprecated.
You can use setOnScrollChangeListener for same purspose like this :
recylerView.setOnScrollChangeListener((view, i, i1, i2, i3) -> swipeToRefreshLayout.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0));
In case of someone find this question and is not satisfied by the answer :
It seems that SwipeRefreshLayout is not compatible with adapters that have more than 1 item type.
If you are using recyclerview without scrollview you can do this and it will work
recyclerview.isNestedScrollingEnabled = true
How to do scrolling effect like twitter when scroll Up hide viewpager tab (Home, Discover, activity). Or effect like facebook scrolling, while scroll up hide option view(status, photo, checkin) when scroll down show option view. Any example link will do please help.
Easy solution:
public abstract class OnScrollObserver implements AbsListView.OnScrollListener {
public abstract void onScrollUp();
public abstract void onScrollDown();
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
int last = 0;
boolean control = true;
#Override
public void onScroll(AbsListView view, int current, int visibles, int total) {
if (current < last && !control) {
onScrollUp();
control = true;
} else if (current > last && control) {
onScrollDown();
control = false;
}
last = current;
}
Usage:
listView.setOnScrollListener(new OnScrollObserver() {
#Override
public void onScrollUp() {
}
#Override
public void onScrollDown() {
}
});
EDIT: better, you have this library https://github.com/ksoichiro/Android-ObservableScrollView
You can look at this https://github.com/LarsWerkman/QuickReturnListView
Source: https://stackoverflow.com/a/25304575/244702
That's my own implementation:
notice:
View to be hidden should be fixed height
We are not hiding the view by Visiblity.GONE
We are setting the final height to 0px
Here is the code:
//Your view which you would like to animate
final RelativeLayout yourViewToHide = (yourViewToHideativeLayout) findViewById(R.id.topWrapper);
//The initial height of that view
final int initialViewHeight = yourViewToHide.getLayoutParams().height;
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//Try catch block for NullPointerExceptions
try{
//Here is a simple delay. If user scrolls ListView from the top of the screen to the bottom then continue
if(firstVisibleItem % visibleItemCount == 0) {
//Here we initialize the animator, doesn't matter what values You will type in
ValueAnimator animator = ValueAnimator.ofInt(0, 1);
//if Scrolling up
if (fastScrollSB.getProgress() > view.getFirstVisiblePosition()){
//Getting actual yourViewToHide params
ViewGroup.LayoutParams params = yourViewToHide.getLayoutParams();
if (!animator.isRunning()) {
//Setting animation from actual value to the initial yourViewToHide height)
animator.setIntValues(params.height, initialViewHeight);
//Animation duration
animator.setDuration(500);
//In this listener we update the view
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams params = yourViewToHide.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
yourViewToHide.setLayoutParams(params);
}
});
//Starting the animation
animator.start();
}
System.out.println("Scrolling up!");
//If not scrolling
} else if (fastScrollSB.getProgress() == view.getFirstVisiblePosition()) {
System.out.println("Not Scrolling!");
//If scrolling down
} else if (fastScrollSB.getProgress() < view.getFirstVisiblePosition()){
//Getting actual yourViewToHide params
ViewGroup.LayoutParams params = yourViewToHide.getLayoutParams();
if (!animator.isRunning()) {
//Setting animation from actual value to the target value (here 0, because we're hiding the view)
animator.setIntValues(params.height, 0);
//Animation duration
animator.setDuration(500);
//In this listener we update the view
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams params = yourViewToHide.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
yourViewToHide.setLayoutParams(params);
}
});
//Starting the animation
animator.start();
}
System.out.println("Scrolling down!");
}
}
}catch (Exception e){
e.printStackTrace();
}
}
});`
Hope it fits your needs :)
there is no quick example for this. But what you can do is keep track which way you are scrolling and show or hide the view accordingly
For example get first visible position of the ListView keep track of this and if it is smaller then before you know you are scrolling up this way you can show the view. In case it is bigger then hide the view.
This is a simple approach in case you want to have more precise you need to work with onTouchListeners and y coordinates of the movement.
http://developer.android.com/reference/android/widget/ListView.html