Skip to content

Instantly share code, notes, and snippets.

@NikolaDespotoski
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NikolaDespotoski/009595717408e7854efd to your computer and use it in GitHub Desktop.
Save NikolaDespotoski/009595717408e7854efd to your computer and use it in GitHub Desktop.
FadingActionBar is great library, but it lacks ability to bind listeners to track how much ActionBarDrawable has been faded in/out.
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.AbsListView;
import android.widget.ListView;
import com.manuelpeinado.fadingactionbar.FadingActionBarHelper;
import java.lang.reflect.Field;
/**
* Created by Nikola on 10/15/2014.
*/
public class NotifyingFadingActionBar extends FadingActionBarHelper {
private final Context mContext;
private AbsListView.OnScrollListener mInternalScrollListener;
private ActionBarDrawableAlphaCallback mAlphaCallback;
private ListView mListView;
private int mInitialBottom;
private float mPreviousRatio;
private boolean hasDispatchedCompleted = false;
private View mHeaderView;
private boolean isActionBarCompat = false;
private android.support.v7.app.ActionBar mSupportActionBar;
private List<AbsListView.OnScrollListener> mListeners = new ArrayList<AbsListView.OnScrollListener>();
public enum ScrollDirection{
DOWN, UP;
}
public interface ActionBarDrawableAlphaCallback{
void onAlphaComplete();
void onAlphaChanged(ScrollDirection direction, float fadingFactor);
}
public NotifyingFadingActionBar(Context c) {
mContext = c;
mPreviousRatio = 0.0f;
try {
Field scrollField = getClass().getSuperclass().getSuperclass().getDeclaredField("mOnScrollListener");
scrollField.setAccessible(true);
mInternalScrollListener = (AbsListView.OnScrollListener)scrollField.get(this);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public NotifyingFadingActionBar headerLayoutResId(int resId){
mHeaderView = LayoutInflater.from(mContext).inflate(resId, null);
super.headerView(mHeaderView);
return this;
}
@Override
public void initActionBar(Activity activity){
checkForCompat(activity);
super.initActionBar(activity);
final View contentView = activity.findViewById(android.R.id.content);
ViewTreeObserver vto = contentView.getViewTreeObserver();
if(vto != null && vto.isAlive()){
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
removeGlobalLayoutListener(contentView, this);
findListView(contentView);
}
});
}else{
findListView(contentView);
}
}
public NotifyingFadingActionBar addOnScrollListener(AbsListView.OnScrollListener listener){
addPartnerScrollListener(listener);
return this;
}
private void addPartnerScrollListener(AbsListView.OnScrollListener listener){
if(!mListeners.contains(listener)){
mListeners.add(listener);
}
}
private void notifyAllOnScrollListeners(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount){
for(AbsListView.OnScrollListener listener : mListeners){
listener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
}
private void notifyAllOnScrollStateChangedListeners(AbsListView view, int scrollState){
for(AbsListView.OnScrollListener listener : mListeners){
listener.onScrollStateChanged(view, scrollState);
}
}
private void checkForCompat(Activity activity) {
isActionBarCompat = activity instanceof ActionBarActivity && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
if(isActionBarCompat) {
mSupportActionBar = ((ActionBarActivity)activity).getSupportActionBar();
}
}
private void findListView(View contentView){
mListView = (ListView)contentView.findViewById(android.R.id.list);
mListView.setOnScrollListener(new NotifyingScrollListener());
mInitialBottom = mHeaderView.getBottom();
mHeaderView = (View)mHeaderView.getParent();
}
public class NotifyingScrollListener implements AbsListView.OnScrollListener{
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.i("Fader", "OnScrollStateChanged()");
if(mInternalScrollListener != null){
mInternalScrollListener.onScrollStateChanged(view, scrollState);
}
notifyAllOnScrollStateChangedListeners(view, scrollState);
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(mInternalScrollListener != null){
mInternalScrollListener.onScroll(view, firstVisibleItem,visibleItemCount,totalItemCount);
}
if( mHeaderView.getBottom() == mHeaderView.getBottom()/2 && !hasDispatchedCompleted){
hasDispatchedCompleted = true;
if( mAlphaCallback != null)
mAlphaCallback.onAlphaComplete();
}else if(mHeaderView.getBottom() > mHeaderView.getBottom()/2 ){
hasDispatchedCompleted = false;
int scrolled = mInitialBottom - mHeaderView.getBottom();
float ratio = (float) scrolled/ mInitialBottom;
ratio*=2;
dispatchRatioChanged(ratio);
}
notifyAllOnScrollListeners(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
}
private void dispatchRatioChanged(float ratio) {
Log.i(TAG, "dispatchRatio() "+ratio + " old: "+mPreviousRatio);
if(ratio != mPreviousRatio) {
if( mAlphaCallback != null)
mAlphaCallback.onAlphaChanged(mPreviousRatio > ratio ? ScrollDirection.DOWN : ScrollDirection.UP, ratio);
mPreviousRatio = ratio;
}
}
public NotifyingFadingActionBar withCallback(ActionBarDrawableAlphaCallback callback){
mAlphaCallback = callback;
return this;
}
@Override
protected void setActionBarBackgroundDrawable(Drawable drawable) {
if(!isActionBarCompat)
super.setActionBarBackgroundDrawable(drawable);
else
mSupportActionBar.setBackgroundDrawable(drawable);
}
@SuppressLint("NewApi")
@Override
protected int getActionBarHeight() {
return isActionBarCompat ? mSupportActionBar.getHeight() : super.getActionBarHeight();
}
@Override
protected boolean isActionBarNull() {
return isActionBarCompat? mSupportActionBar == null : super.isActionBarNull();
}
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public static void removeGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
if (Build.VERSION.SDK_INT < 16) {
v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
} else {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment