Created
November 8, 2012 11:06
-
-
Save atermenji/4038192 to your computer and use it in GitHub Desktop.
A layout that expands/collapses its content by pressing on some view
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<declare-styleable name="ExpandablePanel"> | |
<attr name="handle" format="reference" /> | |
<attr name="content" format="reference" /> | |
<attr name="contentContainer" format="reference" /> | |
<attr name="animationDuration" format="integer"/> | |
</declare-styleable> | |
</resources> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package some.awesome.package; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.view.animation.Animation; | |
import android.view.animation.Animation.AnimationListener; | |
import android.view.animation.Transformation; | |
import android.widget.RelativeLayout; | |
public class ExpandablePanel extends RelativeLayout { | |
private static final int DEFAULT_ANIM_DURATION = 500; | |
private final int mHandleId; | |
private final int mContentContainerId; | |
private final int mContentId; | |
private View mHandle; | |
private View mContentContainer; | |
private View mContent; | |
private boolean mExpanded = false; | |
private boolean mFirstOpen = true; | |
private int mCollapsedHeight; | |
private int mContentHeight; | |
private int mContentWidth; | |
private int mAnimationDuration = 0; | |
private OnExpandListener mListener; | |
public ExpandablePanel(Context context) { | |
this(context, null); | |
} | |
public ExpandablePanel(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExpandablePanel, 0, 0); | |
mAnimationDuration = a.getInteger(R.styleable.ExpandablePanel_animationDuration, DEFAULT_ANIM_DURATION); | |
int handleId = a.getResourceId(R.styleable.ExpandablePanel_handle, 0); | |
if (handleId == 0) { | |
throw new IllegalArgumentException( | |
"The handle attribute is required and must refer to a valid child."); | |
} | |
int contentContainerId = a.getResourceId(R.styleable.ExpandablePanel_contentContainer, 0); | |
if (contentContainerId == 0) { | |
throw new IllegalArgumentException("The content attribute is required and must refer to a valid child."); | |
} | |
int contentId = a.getResourceId(R.styleable.ExpandablePanel_content, 0); | |
if (contentId == 0) { | |
throw new IllegalArgumentException("The content attribute is required and must refer to a valid child."); | |
} | |
mHandleId = handleId; | |
mContentContainerId = contentContainerId; | |
mContentId = contentId; | |
a.recycle(); | |
} | |
public void setOnExpandListener(OnExpandListener listener) { | |
mListener = listener; | |
} | |
public void setAnimationDuration(int animationDuration) { | |
mAnimationDuration = animationDuration; | |
} | |
@Override | |
protected void onFinishInflate() { | |
super.onFinishInflate(); | |
mHandle = findViewById(mHandleId); | |
if (mHandle == null) { | |
throw new IllegalArgumentException("The handle attribute is must refer to an existing child."); | |
} | |
mContentContainer = findViewById(mContentContainerId); | |
if (mContentContainer == null) { | |
throw new IllegalArgumentException("The content container attribute must refer to an existing child."); | |
} | |
mContent = findViewById(mContentId); | |
if (mContentContainer == null) { | |
throw new IllegalArgumentException("The content attribute must refer to an existing child."); | |
} | |
mContent.setVisibility(View.INVISIBLE); | |
mHandle.setOnClickListener(new PanelToggler()); | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); | |
mHandle.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec); | |
mCollapsedHeight = mHandle.getMeasuredHeight(); | |
mContentWidth = mContentContainer.getMeasuredWidth(); | |
mContentHeight = mContentContainer.getMeasuredHeight(); | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
if (mFirstOpen) { | |
mContentContainer.getLayoutParams().width = 0; | |
mContentContainer.getLayoutParams().height = mCollapsedHeight; | |
mFirstOpen = false; | |
} | |
int width = mHandle.getMeasuredWidth() | |
+ mContentContainer.getMeasuredWidth() | |
+ mContentContainer.getPaddingRight(); | |
int height = mContentContainer.getMeasuredHeight() + mContentContainer.getPaddingBottom(); | |
setMeasuredDimension(width, height); | |
} | |
private class PanelToggler implements OnClickListener { | |
@Override | |
public void onClick(View v) { | |
Animation animation; | |
if (mExpanded) { | |
mContent.setVisibility(View.INVISIBLE); | |
animation = new ExpandAnimation(mContentWidth, 0, mContentHeight, mCollapsedHeight); | |
if (mListener != null) { | |
mListener.onCollapse(mHandle, mContentContainer); | |
} | |
} else { | |
ExpandablePanel.this.invalidate(); | |
animation = new ExpandAnimation(0, mContentWidth, mCollapsedHeight, mContentHeight); | |
if (mListener != null) { | |
mListener.onExpand(mHandle, mContentContainer); | |
} | |
} | |
animation.setDuration(mAnimationDuration); | |
animation.setAnimationListener(new AnimationListener() { | |
@Override | |
public void onAnimationStart(Animation animation) { | |
} | |
@Override | |
public void onAnimationRepeat(Animation animation) { | |
} | |
@Override | |
public void onAnimationEnd(Animation animation) { | |
mExpanded = !mExpanded; | |
if (mExpanded) { | |
mContent.setVisibility(View.VISIBLE); | |
} | |
} | |
}); | |
mContentContainer.startAnimation(animation); | |
} | |
} | |
private class ExpandAnimation extends Animation { | |
private final int mStartWidth; | |
private final int mDeltaWidth; | |
private final int mStartHeight; | |
private final int mDeltaHeight; | |
public ExpandAnimation(int startWidth, int endWidth, int startHeight, int endHeight) { | |
mStartWidth = startWidth; | |
mDeltaWidth = endWidth - startWidth; | |
mStartHeight = startHeight; | |
mDeltaHeight = endHeight - startHeight; | |
} | |
@Override | |
protected void applyTransformation(float interpolatedTime, Transformation t) { | |
android.view.ViewGroup.LayoutParams lp = mContentContainer.getLayoutParams(); | |
lp.width = (int) (mStartWidth + mDeltaWidth * interpolatedTime); | |
lp.height = (int) (mStartHeight + mDeltaHeight * interpolatedTime); | |
mContentContainer.setLayoutParams(lp); | |
} | |
@Override | |
public boolean willChangeBounds() { | |
return true; | |
} | |
} | |
public interface OnExpandListener { | |
public void onExpand(View handle, View content); | |
public void onCollapse(View handle, View content); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<some.awesome.package.ExpandablePanel | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:panel="http://schemas.android.com/apk/res/com.digitalfootsteps.android" | |
android:id="@+id/expandable_panel" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_alignParentRight="true" | |
android:layout_marginRight="10dp" | |
android:layout_marginTop="10dp" | |
android:background="@drawable/some_awesome_background" | |
panel:content="@+id/value" | |
panel:contentContainer="@+id/content_container" | |
panel:handle="@+id/expand" > | |
<FrameLayout | |
android:id="@id/content_container" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_alignParentTop="true" | |
android:layout_toLeftOf="@id/expand" | |
android:paddingBottom="5dp" | |
android:paddingRight="15dp" > | |
<some.awesome.package.SomeAwesomeContentView | |
android:id="@id/value" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
</FrameLayout> | |
<Button | |
android:id="@id/expand" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_alignParentRight="true" | |
android:layout_alignParentTop="true" /> | |
</some.awesome.package.ExpandablePanel> |
i need expand de view from bottom to top , please help me !
I cannot get this to work. Can you make small a sample app?
how can i use this code in my app? do you have any sample app that use this code?
mContentContainer = findViewById(mContentContainerId);
if (mContentContainer == null) {
throw new IllegalArgumentException("The content container attribute must refer to an existing child.");
}
mContent = findViewById(mContentId);
**if (mContentContainer == null) {**
throw new IllegalArgumentException("The content attribute must refer to an existing child.");
}
Assuming the second mContentContainer should be mContent
It's not useful to see instantly how code is work 👎 where the fuck is SomeAwesomeContentView class?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Awesome, thank you very much!!1