Existe-t-il un moyen simple de créer des blocs extensibles/collapables comme dans l'application officielle du marché ?
Capture d'écran de l'application Market, lorsque vous cliquez sur le bouton "Plus", la section de description s'étend avec animation :
Je connais Tiroir coulissant mais il ne semble pas être adapté à ce genre de choses - il est censé être placé en superposition, et ne supporte pas les états semi-ouverts.
Mise à jour :
Voici ma solution à moitié fonctionnelle. C'est un widget personnalisé qui étend LinearLayout
. Cela fonctionne en quelque sorte, mais ne gère pas bien les cas limites, comme une hauteur de contenu plus petite que la taille de l'image. collapsedHeight
paramètre. Je suis sûr qu'avec suffisamment d'attention, en creusant dans le code et en expérimentant, les bizarreries pourraient être corrigées. J'espérais éviter de faire cela, et gagner du temps en utilisant une solution officielle ou tierce prête à l'emploi. Bref, voici le code :
package com.example.androidapp.widgets;
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.Transformation;
import android.widget.LinearLayout;
import com.example.androidapp.R;
public class ExpandablePanel extends LinearLayout {
private final int mHandleId;
private final int mContentId;
private View mHandle;
private View mContent;
private boolean mExpanded = true;
private int mCollapsedHeight = 0;
private int mContentHeight = 0;
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);
// How high the content should be in "collapsed" state
mCollapsedHeight = (int) a.getDimension(
R.styleable.ExpandablePanel_collapsedHeight, 0.0f);
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 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;
mContentId = contentId;
a.recycle();
}
@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.");
}
mContent = findViewById(mContentId);
if (mContent == null) {
throw new IllegalArgumentException(
"The content attribute is must refer to an"
+ " existing child.");
}
mHandle.setOnClickListener(new PanelToggler());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mContentHeight == 0) {
// First, measure how high content wants to be
mContent.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
mContentHeight = mContent.getMeasuredHeight();
}
// Then let the usual thing happen
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private class PanelToggler implements OnClickListener {
public void onClick(View v) {
Animation a;
if (mExpanded) {
a = new ExpandAnimation(mContentHeight, mCollapsedHeight);
} else {
a = new ExpandAnimation(mCollapsedHeight, mContentHeight);
}
a.setDuration(500);
mContent.startAnimation(a);
mExpanded = !mExpanded;
}
}
private class ExpandAnimation extends Animation {
private final int mStartHeight;
private final int mDeltaHeight;
public ExpandAnimation(int startHeight, int endHeight) {
mStartHeight = startHeight;
mDeltaHeight = endHeight - startHeight;
}
@Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
android.view.ViewGroup.LayoutParams lp = mContent.getLayoutParams();
lp.height = (int) (mStartHeight + mDeltaHeight * interpolatedTime);
mContent.setLayoutParams(lp);
}
@Override
public boolean willChangeBounds() {
// TODO Auto-generated method stub
return true;
}
}
}
Voici res/values/attrs.xml
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ExpandablePanel">
<attr name="handle" format="reference" />
<attr name="content" format="reference" />
<attr name="collapsedHeight" format="dimension" />
</declare-styleable>
</resources>
Et voici comment je l'utilise dans la mise en page :
<com.example.androidapp.widgets.ExpandablePanel
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
example:handle="@+id/expand"
example:content="@+id/value"
example:collapsedHeight="50dip">
<TextView
android:id="@id/value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:maxHeight="50dip"
/>
<Button
android:id="@id/expand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="More" />
</com.example.androidapp.widgets.ExpandablePanel>