1

I've seen several posts discussing about scrolling and header resizing and saw @MathieuMaree's answer in this post which give me a first idea about how to resize my header while scrolling on my ListView.

So here is my implementation :

I have a FragmentActivity with a ViewPager containing 3 tabs with ExpandableListView.

Here is the activity's layout :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <bla.bla.bla.views.HeaderFicheEquipe
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >
    </bla.bla.bla.views.HeaderFicheEquipe>

    <RelativeLayout
        android:id="@+id/tabView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_below="@+id/Header" >

        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >

            <android.support.v4.view.PagerTabStrip
                android:id="@+id/titleStrip"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="@style/PagerTabStripText" />
        </android.support.v4.view.ViewPager>
    </RelativeLayout>

</RelativeLayout>

First of all, I set the OnScrollListener on my ExpandableListView :

list.setOnScrollListener((CardActivity) getActivity());

Then, I've implemented OnScrollListener on my FragmentActivity :

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    int totalSize = 0;
    View v = view.getChildAt(0);

    if (v != null) {
        if (elementSizes.size() > 0 && firstVisibleItem <= elementSizes.size()) {
            for (int i = 0; i < firstVisibleItem; ++i) {
                totalSize += elementSizes.get(i);
            }
            totalSize -= (v.getTop() - view.getPaddingTop());
            if (totalSize > (maxHeightHeader - minHeightHeader))
                totalSize = maxHeightHeader - minHeightHeader;
        } else {
            totalSize = maxHeightHeader - minHeightHeader;
        }
        header.getLayoutParams().height = maxHeightHeader - totalSize;
        header.requestLayout();
    }
}

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

elementsSize being a list filled with the size of the first elements of my list. The header is actually reducing as wished but my onScroll is called way too much : when the header is reduced, my list goes up and if the user keep his finger on the screen it's making Android call onScroll again but with incorrect infos. My header is changing size a lot of times during a short period (jumping from the size I want to the max height and from max height to wanted size) until i've arrived to the minimum size where it's working great again.

I don't know if my implementation is correct right now and if it's only the situation making it not working or if i'm missing something. I saw some applications doing header resize while scrolling but they seem to work differently : they reduce the header and only after having the header at the minimum size they start to scroll into the list.

How is it possible to "block" the scroll of the list while the header isn't at its minimum size? Or is there an issue with my code that could be resolved?

Thanks in advance for your Help

Thomas

Community
  • 1
  • 1
  • The main issue is caused by the ViewPager here. I've tried to change `header.getLayoutParams().height` to `header.translationY(translation)` but the ViewPager stays at the same place and if I move the Layout containing the ViewPager to follow the translation, the size doesn't change and its not filling the screen entirely. – Thomas D'Hulst May 13 '15 at 10:12
  • did you manage to make it work? – kb_14 Nov 04 '15 at 08:30
  • Sadly, no. But I'll have to find a solution since I am developping a new app right now and this is required. – Thomas D'Hulst Nov 04 '15 at 09:33
  • 1
    check [this](http://flavienlaurent.com/blog/2013/11/20/making-your-action-bar-not-boring/) out – Ebrahim Karimi Jan 29 '18 at 01:36

1 Answers1

0

I had the same issue and it took me a while to find a solution.

I also got that "incorrect values" you mentioned when you scroll slowly or keep your finger on the screen. That caused my header image to size up and down and it flickered.

The trick is to register an onTouchListener on your listview, observe the move event to know if you are actually scrolling up or down. On your onScroll listener you may just resize the header if the scrollposition direction matches with the direction from the Move Event of the onTouch listener.

private float mCurrentYPositionOnScreen;
private float mSavedYPositionOnScreen;
private int mLastScrollYPosition;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
{

    listView.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    mCurrentYPositionOnScreen = event.getRawY();

                    break;

                case MotionEvent.ACTION_UP:
                    mCurrentYPositionOnScreen = 0;

                    break;
            }

            return false;
        }

    });



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

            View c = listView.getChildAt(0);

            if(c == null)
                return;

            if(mSavedYPositionOnScreen == mCurrentYPositionOnScreen &&  mCurrentYPositionOnScreen != 0)
                return;

            boolean needToScrollDown = mCurrentYPositionOnScreen < mSavedYPositionOnScreen;

            int currentScrollYPosition = -c.getTop();
            listViewItemHeights.put(listView.getFirstVisiblePosition(), c.getHeight());
            for (int i = 0; i < listView.getFirstVisiblePosition(); ++i) {
                if (listViewItemHeights.get(i) != null)
                    currentScrollYPosition += listViewItemHeights.get(i);
            }

            boolean scrollingDown = currentScrollYPosition > mLastScrollYPosition;

            if(needToScrollDown && !scrollingDown && mLastScrollYPosition != 0 &&  mCurrentYPositionOnScreen != 0)
                return;

            if(!needToScrollDown && scrollingDown && mLastScrollYPosition != 0 &&  mCurrentYPositionOnScreen != 0)
                return;

            mLastScrollYPosition = currentScrollYPosition;

            final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(mOriginalBannerImageViewWidth, mOriginalBannerImageViewHeight);

            int height = mOriginalBannerImageViewHeight - currentScrollYPosition;

            if(height < 0)
                height = 0;

            final int finalHeight = height;

            mBannerImageView.setLayoutParams(layoutParams);
            mBannerImageView.getLayoutParams().height = finalHeight;
            mBannerImageView.requestLayout();

            mSavedYPositionOnScreen = mCurrentYPositionOnScreen;


        }
    });

    return view;
}
JayTee
  • 1,114
  • 2
  • 11
  • 18