/*
* Copyright (c) 2015 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.douya.ui;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import butterknife.BindInt;
import butterknife.ButterKnife;
import me.zhanghai.android.douya.R;
import me.zhanghai.android.douya.util.ViewUtils;
/**
* A {@link LinearLayout} that manages showing and hiding the AppBar and its shadow with support.
*/
public class AppBarWrapperLayout extends LinearLayout {
@BindInt(android.R.integer.config_shortAnimTime)
int mAnimationDuration;
private View mAppbarView;
private View mShadowCompatView;
private boolean mShowing = true;
private AnimatorSet mAnimator;
public AppBarWrapperLayout(Context context) {
super(context);
init();
}
public AppBarWrapperLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AppBarWrapperLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AppBarWrapperLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setOrientation(VERTICAL);
ButterKnife.bind(this);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
ViewUtils.inflateInto(R.layout.appbar_shadow_compat, this);
if (getChildCount() != 2) {
throw new IllegalStateException("One and only one AppBar view should be wrapped " +
"inside this layout");
}
mAppbarView = getChildAt(0);
mShadowCompatView = getChildAt(1);
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.showing = mShowing;
return savedState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
if (!savedState.showing) {
hideImmediately();
}
}
public void hide() {
if (!mShowing) {
return;
}
mShowing = false;
cancelAnimator();
mAnimator = new AnimatorSet()
.setDuration(mAnimationDuration);
mAnimator.setInterpolator(new FastOutLinearInInterpolator());
AnimatorSet.Builder builder = mAnimator.play(ObjectAnimator.ofFloat(this, TRANSLATION_Y,
getTranslationY(), getHideTranslationY()));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
builder.before(ObjectAnimator.ofFloat(mShadowCompatView, ALPHA,
mShadowCompatView.getAlpha(), 0));
} else {
builder.before(ObjectAnimator.ofFloat(mAppbarView, TRANSLATION_Z,
mAppbarView.getTranslationZ(), -mAppbarView.getElevation()));
}
mAnimator.start();
}
public void hideImmediately() {
if (!mShowing) {
return;
}
float hideTranslationY = getHideTranslationY();
if (hideTranslationY != 0) {
mShowing = false;
setTranslationY(hideTranslationY);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
mShadowCompatView.setAlpha(0);
} else {
mAppbarView.setTranslationZ(-mAppbarView.getElevation());
}
} else {
ViewUtils.postOnPreDraw(this, new Runnable() {
@Override
public void run() {
hideImmediately();
}
});
}
}
private int getHideTranslationY() {
return -(getBottom() - mShadowCompatView.getHeight());
}
public void show() {
if (mShowing) {
return;
}
mShowing = true;
cancelAnimator();
mAnimator = new AnimatorSet()
.setDuration(mAnimationDuration);
mAnimator.setInterpolator(new FastOutSlowInInterpolator());
AnimatorSet.Builder builder = mAnimator.play(ObjectAnimator.ofFloat(this, TRANSLATION_Y,
getTranslationY(), 0));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
builder.with(ObjectAnimator.ofFloat(mShadowCompatView, ALPHA,
mShadowCompatView.getAlpha(), 1));
} else {
builder.with(ObjectAnimator.ofFloat(mAppbarView, TRANSLATION_Z,
mAppbarView.getTranslationZ(), 0));
}
mAnimator.start();
}
public void showImmediately() {
if (mShowing) {
return;
}
mShowing = true;
setTranslationY(0);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
mShadowCompatView.setAlpha(1);
} else {
mAppbarView.setTranslationZ(0);
}
}
private void cancelAnimator() {
if (mAnimator != null) {
mAnimator.cancel();
mAnimator = null;
}
}
private static class SavedState extends BaseSavedState {
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel source) {
return new SavedState(source);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
public boolean showing;
public SavedState(Parcel in) {
super(in);
showing = in.readByte() != 0;
}
public SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeByte(showing ? (byte) 1 : (byte) 0);
}
}
}