Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to Keep Track of Scroll Position and Header Size Across Tabs (Enhancement) :) #11

Open
nasserprofessional opened this issue Nov 23, 2014 · 3 comments

Comments

@nasserprofessional
Copy link

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

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
Copy link

hustwht commented Jan 26, 2016

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.

@hustwht
Copy link

hustwht commented Jan 26, 2016

@nasserprofessional

@Sakshamgupta20
Copy link

when activity is destroyed we have to store the scrollable position so for that

public static int index = -1;
public static int top = -1;

@OverRide
public void onPause() {
super.onPause();
index =list.getFirstVisiblePosition();
View v = list.getChildAt(0);
top = (v == null) ? 0 : (v.getTop() - list.getPaddingTop());
}
@OverRide
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("index",index);
outState.putInt("top",top);
}

and then in onloadfinished/in oncreateview add
if(index != -1)
{
list.setSelectionFromTop( index, top);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants