package com.noshufou.android.su.widget;
import com.noshufou.android.su.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.animation.Animation.AnimationListener;
import android.widget.Button;
public class SlidingPanel extends ViewGroup {
// private static final String TAG = "Su.SlidingPanel";
private int mButtonId;
private View mButton;
private int mAnchorId;
private View mAnchor;
private int mContentId;
private View mContent;
private int mOpenOverlap;
private int mClosedLimit;
private boolean mAnimating = false;
private int mFillOffset = 0;
private boolean mExpanded = true;
public SlidingPanel(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingPanel(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingPanel,
defStyle, 0);
int buttonId = a.getResourceId(R.styleable.SlidingPanel_button, 0);
if (buttonId == 0) {
throw new IllegalArgumentException("The button attribute is required and must refer" +
" to a valid child");
}
int anchorId = a.getResourceId(R.styleable.SlidingPanel_anchor, 0);
if (anchorId == buttonId) {
throw new IllegalArgumentException("The anchor attribute is required and must refer" +
" to a different child");
}
int contentId = a.getResourceId(R.styleable.SlidingPanel_content, 0);
if (contentId == anchorId || contentId == buttonId) {
throw new IllegalArgumentException("The content attribute is required and must refer" +
" to a different child");
}
mOpenOverlap = a.getDimensionPixelSize(R.styleable.SlidingPanel_openOverlap, 0);
mClosedLimit = a.getDimensionPixelSize(R.styleable.SlidingPanel_closedLimit, 0);
a.recycle();
mButtonId = buttonId;
mAnchorId = anchorId;
mContentId = contentId;
}
@Override
protected void onFinishInflate() {
mButton = findViewById(mButtonId);
((Button)mButton).setText(">");
if (mButton == null) {
throw new IllegalArgumentException("The handle attribute must refer to a child");
}
mAnchor = findViewById(mAnchorId);
if (mAnchor == null) {
throw new IllegalArgumentException("The anchor attribute must refer to a child");
}
mContent = findViewById(mContentId);
if (mContent == null) {
throw new IllegalArgumentException("The content attribute must refer to a child");
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = View.resolveSize(0, widthMeasureSpec);
int height = View.resolveSize(0, heightMeasureSpec);
final View anchor = mAnchor;
measureChild(anchor, widthMeasureSpec, heightMeasureSpec);
final View button = mButton;
measureChild(button, MeasureSpec.makeMeasureSpec(anchor.getMeasuredWidth(),
MeasureSpec.EXACTLY),
heightMeasureSpec);
button.setOnClickListener(new Toggler());
final View content = mContent;
int contentWidth = width - mClosedLimit;
content.measure(MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final View button = mButton;
button.layout(0, 0, button.getMeasuredWidth(), button.getMeasuredHeight());
final View anchor = mAnchor;
anchor.layout(0, button.getMeasuredHeight(), anchor.getMeasuredWidth(),
button.getMeasuredHeight() + anchor.getMeasuredHeight());
final View content = mContent;
int contentLeft;
if (mAnimating) {
contentLeft = content.getLeft();
} else if (mExpanded) {
contentLeft = mClosedLimit;
} else {
contentLeft = anchor.getRight() - mOpenOverlap;
}
content.layout(contentLeft, 0,
contentLeft + content.getMeasuredWidth(),
content.getMeasuredHeight());
}
public void toggle() {
final View content = mContent;
final View anchor = mAnchor;
final int offset = anchor.getMeasuredWidth() - mOpenOverlap - mClosedLimit;
TranslateAnimation anim;
if (mExpanded) {
anim = new TranslateAnimation(0, offset, 0, 0);
mFillOffset = offset;
} else {
anim = new TranslateAnimation(0, -offset, 0, 0);
mFillOffset = -offset;
}
mExpanded = !mExpanded;
anim.setFillEnabled(true);
anim.setFillBefore(true);
anim.setDuration(300);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.setAnimationListener(new AnimationFiller());
content.startAnimation(anim);
}
private class Toggler implements OnClickListener {
@Override
public void onClick(View v) {
if (!mAnimating) {
toggle();
}
}
}
private class AnimationFiller implements AnimationListener {
@Override
public void onAnimationEnd(Animation animation) {
mAnimating = false;
final View content = mContent;
content.offsetLeftAndRight(mFillOffset);
final Button button = (Button) mButton;
if (mExpanded) {
button.setText(">");
} else {
button.setText("<");
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
mAnimating = true;
}
}
}