I was having some problems implementing this because of it losing scroll position and not maintaining header size across tabs when I tried to get the scroll position working.
This is my solution:
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 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 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(){
}
}
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.