kmshack / Android-ParallaxHeaderViewPager

DEPRECATED
Apache License 2.0
1.39k stars 336 forks source link

Scroll reset problem #2

Open alirahimpour89 opened 10 years ago

alirahimpour89 commented 10 years ago

maybe it is by design but the lists scroll position resets when changing tab

nikhilvishnu commented 10 years ago

I am also facing the same issue. When there is only few items in the list view it will scroll down to original position.

rameshvoltella commented 10 years ago

same for me too is there any solution i added dynamic footer but still have the issue

SwordBearer commented 9 years ago

me too , even when i just run the Demo on my phone

nasserprofessional commented 9 years ago

If you go inside SampleListFragment:

Go inside this function: public void adjustScroll(int scrollHeight) {

Comment out this line: mListView.setSelectionFromTop(1, scrollHeight);

It disables resetting the listview to the top when you change the tabs.

Good: Every tab saves its own scroll position. Bad: Every tab has its own header state. So if you scrolled up in the first tab and the header is minimized the next tab will have a full header. If you go back to the first tab it will still have its minimized header state.

Not the best solution. I can understand people who might want the header to be minimized/maximized across all tabs. Haven't figured out how to do it yet but hey at least it stores the scroll position for now I guess.

If anyone figures it out please let me know too. Hope this info helped someone :)

I did try creating a way to temporary disable the header but then the listviews scroll offset wasn't right. The offset was staying at bottom as if the header was still there. If anyone knows a way how I can change the listviews offset I can fix the problem of having a scrolled up or down header state across all tabs.

nasserprofessional commented 9 years ago

A way you can hack it to make it remember scroll position as well as keep track of the header state across all tabs.

Not the best solution but might give someone some ideas:

SampleListFragment: package com.kmshack.newsstand;

import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;

import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast;

public class SampleListFragment extends ScrollTabHolderFragment implements OnScrollListener {

private static final String ARG_POSITION = "position";

Map<String, String> map = new HashMap<String, String>();
int scrollh;

private ListView mListView;
private ArrayList<String> mListItems;

private int mPosition;

private int index = -1;
private int top = 0;

int sheight;
int mMinHeaderHeight;

int mHeaderHeight;
public static Fragment newInstance(int position) {
    SampleListFragment f = new SampleListFragment();
    Bundle b = new Bundle();
    b.putInt(ARG_POSITION, position);
    f.setArguments(b);
    return f;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mPosition = getArguments().getInt(ARG_POSITION);

    mListItems = new ArrayList<String>();

    for (int i = 1; i <= 100; i++) {
        mListItems.add(i + ". item - currnet page: " + (mPosition + 1));
    }

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_list, null);

    mListView = (ListView) v.findViewById(R.id.listView);
    mMinHeaderHeight = getResources().getDimensionPixelSize(R.dimen.min_header_height);
    mHeaderHeight = getResources().getDimensionPixelSize(R.dimen.header_height);
    View placeHolderView = inflater.inflate(R.layout.view_header_placeholder, mListView, false);
    mListView.addHeaderView(placeHolderView);

    return v;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    mListView.setOnScrollListener(this);
    mListView.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.list_item, android.R.id.text1, mListItems));

}

@Override
public void onResume() {
      super.onResume();

      if(index!=-1){
         //mListView.setSelectionFromTop(index, top);

      }

     // if(MainActivity.getscrollh()==288){

        //int nin =Integer.parseInt( map.get(""+mPosition+"n"+index));
        //mListView.setSelectionFromTop(nin, -mMinHeaderHeight+200);

        //mListView.setSelectionFromTop(nin, 1);
      //}

}

@Override
public void onPause() {
      super.onPause();
      try{
         index = mListView.getFirstVisiblePosition();
         View v = mListView.getChildAt(0);
         top = (v == null) ? 0 : v.getTop();

         map.put(""+mPosition+"n"+index, ""+index);

      }
      catch(Throwable t){
         t.printStackTrace();
      }

}

@Override
public void adjustScroll(int scrollHeight) {
scrollh=scrollHeight;

MainActivity.setscrollh(scrollHeight);
    if (scrollHeight == 0 && mListView.getFirstVisiblePosition() >= 0) {
        return;
    }

if(MainActivity.getscrollh()==288){

        int nin =Integer.parseInt( map.get(""+mPosition+"n"+index));
        mListView.setSelectionFromTop(nin, -mMinHeaderHeight+90);
    }else{

        mListView.setSelectionFromTop(1, scrollHeight);
    }

}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (mScrollTabHolder != null)

        mScrollTabHolder.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount, mPosition);

     try{

         index = mListView.getFirstVisiblePosition();
         View v = mListView.getChildAt(0);
         top = (v == null) ? 0 : v.getTop();

         map.put(""+mPosition+"n"+index, ""+index);
     }
         catch(Throwable t){
             t.printStackTrace();
          }

}

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

}

MainActivity: package com.kmshack.newsstand;

import android.annotation.TargetApi; import android.graphics.RectF; import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.util.SparseArrayCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBarActivity; import android.text.Spannable; import android.text.SpannableString; import android.util.TypedValue; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.AbsListView; import android.widget.ImageView;

import com.astuetz.PagerSlidingTabStrip; import com.flavienlaurent.notboringactionbar.AlphaForegroundColorSpan; import com.flavienlaurent.notboringactionbar.KenBurnsSupportView; import com.nineoldandroids.view.ViewHelper;

public class MainActivity extends ActionBarActivity implements ScrollTabHolder, ViewPager.OnPageChangeListener {

static int scrollh;

private static AccelerateDecelerateInterpolator sSmoothInterpolator = new AccelerateDecelerateInterpolator();

private KenBurnsSupportView mHeaderPicture;
private View mHeader;

private PagerSlidingTabStrip mPagerSlidingTabStrip;
private ViewPager mViewPager;
private PagerAdapter mPagerAdapter;

private int mActionBarHeight;
private int mMinHeaderHeight;
private int mHeaderHeight;
private int mMinHeaderTranslation;
private ImageView mHeaderLogo;

private RectF mRect1 = new RectF();
private RectF mRect2 = new RectF();

private TypedValue mTypedValue = new TypedValue();
private SpannableString mSpannableString;
private AlphaForegroundColorSpan mAlphaForegroundColorSpan;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mMinHeaderHeight = getResources().getDimensionPixelSize(R.dimen.min_header_height);
    mHeaderHeight = getResources().getDimensionPixelSize(R.dimen.header_height);
    mMinHeaderTranslation = -mMinHeaderHeight + getActionBarHeight();

    setContentView(R.layout.activity_main);

    mHeaderPicture = (KenBurnsSupportView) findViewById(R.id.header_picture);
    mHeaderPicture.setResourceIds(R.drawable.pic0, R.drawable.pic1);
    mHeaderLogo = (ImageView) findViewById(R.id.header_logo);
    mHeader = findViewById(R.id.header);

    mPagerSlidingTabStrip = (PagerSlidingTabStrip) findViewById(R.id.tabs);
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setOffscreenPageLimit(4);

    mPagerAdapter = new PagerAdapter(getSupportFragmentManager());
    mPagerAdapter.setTabHolderScrollingContent(this);

    mViewPager.setAdapter(mPagerAdapter);

    mPagerSlidingTabStrip.setViewPager(mViewPager);
    mPagerSlidingTabStrip.setOnPageChangeListener(this);
    mSpannableString = new SpannableString(getString(R.string.actionbar_title));
    mAlphaForegroundColorSpan = new AlphaForegroundColorSpan(0xffffffff);

    ViewHelper.setAlpha(getActionBarIconView(), 0f);

    getSupportActionBar().setBackgroundDrawable(null);
}

@Override
public void onPageScrollStateChanged(int arg0) {
    // nothing
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    // nothing
}

@Override
public void onPageSelected(int position) {
    SparseArrayCompat<ScrollTabHolder> scrollTabHolders = mPagerAdapter.getScrollTabHolders();
    ScrollTabHolder currentHolder = scrollTabHolders.valueAt(position);

    currentHolder.adjustScroll((int) (mHeader.getHeight() + ViewHelper.getTranslationY(mHeader)));
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount, int pagePosition) {
    if (mViewPager.getCurrentItem() == pagePosition) {
        int scrollY = getScrollY(view);
        ViewHelper.setTranslationY(mHeader, Math.max(-scrollY, mMinHeaderTranslation));
        float ratio = clamp(ViewHelper.getTranslationY(mHeader) / mMinHeaderTranslation, 0.0f, 1.0f);
        interpolate(mHeaderLogo, getActionBarIconView(), sSmoothInterpolator.getInterpolation(ratio));
        setTitleAlpha(clamp(5.0F * ratio - 4.0F, 0.0F, 1.0F));
    }
}

@Override
public void adjustScroll(int scrollHeight) {
    // nothing
}

public int getScrollY(AbsListView view) {
    View c = view.getChildAt(0);
    if (c == null) {
        return 0;
    }

    int firstVisiblePosition = view.getFirstVisiblePosition();
    int top = c.getTop();

    int headerHeight = 0;
    if (firstVisiblePosition >= 1) {
        headerHeight = mHeaderHeight;
    }

    return -top + firstVisiblePosition * c.getHeight() + headerHeight;
}

public static float clamp(float value, float max, float min) {
    return Math.max(Math.min(value, min), max);
}

private void interpolate(View view1, View view2, float interpolation) {
    getOnScreenRect(mRect1, view1);
    getOnScreenRect(mRect2, view2);

    float scaleX = 1.0F + interpolation * (mRect2.width() / mRect1.width() - 1.0F);
    float scaleY = 1.0F + interpolation * (mRect2.height() / mRect1.height() - 1.0F);
    float translationX = 0.5F * (interpolation * (mRect2.left + mRect2.right - mRect1.left - mRect1.right));
    float translationY = 0.5F * (interpolation * (mRect2.top + mRect2.bottom - mRect1.top - mRect1.bottom));

    ViewHelper.setTranslationX(view1, translationX);
    ViewHelper.setTranslationY(view1, translationY - ViewHelper.getTranslationY(mHeader));
    ViewHelper.setScaleX(view1, scaleX);
    ViewHelper.setScaleY(view1, scaleY);
}

private RectF getOnScreenRect(RectF rect, View view) {
    rect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
    return rect;
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public int getActionBarHeight() {
    if (mActionBarHeight != 0) {
        return mActionBarHeight;
    }

    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){
        getTheme().resolveAttribute(android.R.attr.actionBarSize, mTypedValue, true);
    }else{
        getTheme().resolveAttribute(R.attr.actionBarSize, mTypedValue, true);
    }

    mActionBarHeight = TypedValue.complexToDimensionPixelSize(mTypedValue.data, getResources().getDisplayMetrics());

    return mActionBarHeight;
}

private void setTitleAlpha(float alpha) {
    mAlphaForegroundColorSpan.setAlpha(alpha);
    mSpannableString.setSpan(mAlphaForegroundColorSpan, 0, mSpannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    getSupportActionBar().setTitle(mSpannableString);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private ImageView getActionBarIconView() {

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
        return (ImageView)findViewById(android.R.id.home);
    }

    return (ImageView)findViewById(android.support.v7.appcompat.R.id.home);
}

public class PagerAdapter extends FragmentPagerAdapter {

    private SparseArrayCompat<ScrollTabHolder> mScrollTabHolders;
    private final String[] TITLES = { "Page 1", "Page 2", "Page 3", "Page 4"};
    private ScrollTabHolder mListener;

    public PagerAdapter(FragmentManager fm) {
        super(fm);
        mScrollTabHolders = new SparseArrayCompat<ScrollTabHolder>();
    }

    public void setTabHolderScrollingContent(ScrollTabHolder listener) {
        mListener = listener;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return TITLES[position];
    }

    @Override
    public int getCount() {
        return TITLES.length;
    }

    @Override
    public Fragment getItem(int position) {
        ScrollTabHolderFragment fragment = (ScrollTabHolderFragment) SampleListFragment.newInstance(position);

        mScrollTabHolders.put(position, fragment);
        if (mListener != null) {
            fragment.setScrollTabHolder(mListener);
        }

        return fragment;
    }

    public SparseArrayCompat<ScrollTabHolder> getScrollTabHolders() {
        return mScrollTabHolders;
    }

}

public static void setscrollh(int h){
    scrollh=h;

}

public static int getscrollh(){

    return scrollh;
}

}

I added a hashmap that keeps track of the scrolling position for each listview. Views settings are automatically added to the hashmap and then their settings are loaded back when needed.

I also wrote a function in the activity that basically keeps track of the scroll height. Obviously the header height is changing in 1 listview and when we switch tabs we want to be able to ask the activity the height of the original header. We then do a check to see if it was the minimum header size or the full header size then we simply do some tweaking to align things a bit.

There are probably better ways to do it... this is just an idea that allows you to keep track of scroll positions across listviews and maintain headers.

:)

If anyone comes up with anything better or this helps in anyway do let me know.

hustwht commented 8 years ago

I found a solution for the problem, in the function below @Override public void adjustScroll(int scrollHeight) { if (scrollHeight == 0 && mListView.getFirstVisiblePosition() >= 1) { return; }

mListView.setSelectionFromTop(1, scrollHeight);

} the problem is the scrollHeight == 0 , if the fragment has a titlebar, then the value is not 0, should be the height of titlebar, because scrollHeight = header.height - header.translationY, I changed the value, the I keep the scroll position when across the tabs. I am so sorry for my English, I hope you understand me.