package com.kedzie.vbox.app; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.Transformation; import android.widget.FrameLayout; import android.widget.LinearLayout; import com.kedzie.vbox.R; import com.kedzie.vbox.app.Utils.AnimationAdapter; import com.nineoldandroids.view.animation.AnimatorProxy; /** * Animated collapsible Panel */ public class CollapsiblePanelView extends LinearLayout implements OnClickListener { private final int DEFAULT_COLLAPSE_ROTATION=90; /** * Animation for collapsing/expanding */ private class PanelAnimation extends Animation { private final int mStartHeight; private final int mDeltaHeight; private final int mStartRotation; private final int mDeltaRotation; public PanelAnimation(int startHeight, int endHeight) { setDuration(getResources().getInteger(android.R.integer.config_longAnimTime)); setInterpolator(new AccelerateInterpolator()); mStartHeight = startHeight; mDeltaHeight = endHeight - startHeight; if(isExpanding()) { mStartRotation = mCollapseRotation; mDeltaRotation = mCollapseRotation*-1; } else { mStartRotation = 0; mDeltaRotation = mCollapseRotation; } setAnimationListener(new AnimationAdapter() { @Override public void onAnimationEnd(Animation animation) { if(isCollapsing()) mFrame.setVisibility(View.GONE); } }); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { ViewGroup.LayoutParams lp = mContents.getLayoutParams(); lp.height = (int) (mStartHeight + mDeltaHeight * interpolatedTime); mContents.setLayoutParams(lp); AnimatorProxy.wrap(mCollapseButton).setRotation(mStartRotation + mDeltaRotation*interpolatedTime); } @Override public boolean willChangeBounds() { return true; } private boolean isExpanding() { return mStartHeight==0; } private boolean isCollapsing() { return !isExpanding(); } } private boolean mExpanded=true; protected View mTitleView; private FrameLayout mFrame; private LinearLayout mContents; private Drawable mIcon; private View mCollapseButton; private int mContentGravity; private int mContentHeight; private String mTitle; private int mCollapseRotation=DEFAULT_COLLAPSE_ROTATION; public CollapsiblePanelView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.Panel, 0, 0); try { mTitle = a.hasValue(R.styleable.Panel_name) ? a.getString(R.styleable.Panel_name) : ""; mIcon = a.getDrawable(R.styleable.Panel_headerIcon); mCollapseRotation = a.getInt(R.styleable.Panel_collapseRotation, DEFAULT_COLLAPSE_ROTATION); mExpanded = a.getBoolean(R.styleable.Panel_expanded, true); } finally { a.recycle(); } init(context); } public CollapsiblePanelView(Context context) { super(context); init(context); } protected void init(Context context) { LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); setOrientation(VERTICAL); mContents = new LinearLayout(context); mContents.setOrientation(VERTICAL); mContents.setGravity(mContentGravity); mFrame = new FrameLayout(context); mFrame.setBackgroundResource(R.drawable.panel_body); mFrame.addView(mContents, lp); super.addView(getTitleView(), lp); super.addView(mFrame, lp); if(!mExpanded) { mFrame.setVisibility(GONE); AnimatorProxy.wrap(mCollapseButton).setRotation(mCollapseRotation); } if(Utils.isVersion(Build.VERSION_CODES.HONEYCOMB)) setLayerType(LAYER_TYPE_HARDWARE, null); } /** * Override to create custom Panel header. Make sure to also override {@link CollapsiblePanelView#getCollapseButton}. * @return the initialized panel header */ public View getTitleView() { if(mTitleView==null) { mTitleView = (LinearLayout)LayoutInflater.from(getContext()).inflate(R.layout.panel_header, this, false); setCollapseButton(mTitleView.findViewById(R.id.group_collapse)); Utils.setImageView(mTitleView, R.id.panel_icon, mIcon); Utils.setTextView(mTitleView, R.id.group_title, mTitle); } return mTitleView; } protected void setCollapseButton(View view) { mCollapseButton = view; mCollapseButton.setOnClickListener(this); } @Override public void addView(View child) { mContents.addView(child); } @Override public void addView(View child, ViewGroup.LayoutParams params) { mContents.addView(child, params); } public List<View> getContentViews() { List<View> views = new ArrayList<View>(mContents.getChildCount()); for(int i=0; i<mContents.getChildCount(); i++) views.add(mContents.getChildAt(i)); return views; } @Override public void setGravity(int gravity) { mContentGravity=gravity; if(mContents!=null) mContents.setGravity(gravity); } @Override public void setPressed(boolean pressed) { super.setPressed(pressed); mTitleView.setPressed(pressed); mFrame.setPressed(pressed); } @Override public void setSelected(boolean selected) { super.setSelected(selected); mTitleView.setSelected(selected); mFrame.setSelected(selected); if(selected) for(int i=0; i<mContents.getChildCount(); i++) mContents.getChildAt(i).setSelected(false); } @Override public void onClick(View v) { if(mExpanded) collapse(); else expand(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mContentHeight == 0) { mContents.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED); mContentHeight = mContents.getMeasuredHeight(); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * Expand the panel */ public void expand() { if(mExpanded) return; mFrame.setVisibility(View.VISIBLE); mContents.startAnimation(new PanelAnimation(0, mContentHeight)); mExpanded = true; } /** * Collapse the panel */ public void collapse() { if(!mExpanded) return; if(mContents.getHeight()<mContentHeight) mContentHeight = mContents.getHeight(); mContents.startAnimation(new PanelAnimation(mContentHeight, 0)); mExpanded=false; } /** * @return <em>true</em> if panel is expanded, <em>false</em> otherwise */ public boolean isExpanded() { return mExpanded; } /** * @param rotation the rotation of the collapse button when the panel is collapsing */ public void setCollapseRotation(int rotation) { mCollapseRotation=rotation; } }