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; } } }