misp-bump/expandablecardview/src/main/java/lu/circl/expandablecardview/ExpandableCardView.java

178 lines
6.7 KiB
Java

package lu.circl.expandablecardview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ExpandableCardView extends LinearLayout {
private Context context;
private FrameLayout contentLayout;
private int cardContentPadding;
private boolean isExpanded = true;
private int animationSpeed = 200;
public ExpandableCardView(Context context) {
this(context, null);
}
public ExpandableCardView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ExpandableCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
setOrientation(VERTICAL);
setClipToOutline(true);
TypedArray customAttributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ExpandableCardView, defStyleAttr, 0);
// general
int cornerRadius = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_corner_radius, 12);
// header
String cardTitle = customAttributes.getString(R.styleable.ExpandableCardView_card_title);
int iconRes = customAttributes.getResourceId(R.styleable.ExpandableCardView_card_icon, 0x0);
int headerForegroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_foreground_color, 0xFF000000);
int headerBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_background_color, 0xFFFFFFFF);
// content
cardContentPadding = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_content_padding, 0);
int cardContentBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_content_background_color, 0xFFFFFFFF);
customAttributes.recycle();
GradientDrawable cardBackground = new GradientDrawable();
cardBackground.setCornerRadius(cornerRadius);
cardBackground.setColor(cardContentBackgroundColor);
setBackground(cardBackground);
setElevation(10);
initHeader(cardTitle, iconRes, headerBackgroundColor, headerForegroundColor);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (getChildCount() == 0) {
super.addView(child, index, params); // add header
} else {
if (contentLayout == null) {
contentLayout = new FrameLayout(context);
contentLayout.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
contentLayout.setPadding(cardContentPadding, cardContentPadding, cardContentPadding, cardContentPadding);
super.addView(contentLayout, index, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
contentLayout.addView(child);
}
}
private void initHeader(String title, int iconRes, int backgroundColor, int foregroundColor) {
View header = LayoutInflater.from(context).inflate(R.layout.expandable_card_view_header, this, true);
LinearLayout ll = header.findViewById(R.id.llRoot);
ll.setBackgroundColor(backgroundColor);
TextView titleTextView = header.findViewById(R.id.expandable_card_view_header_title);
titleTextView.setText(title);
titleTextView.setTextColor(foregroundColor);
ImageView iconView = header.findViewById(R.id.expandable_card_view_header_icon);
if (iconRes == 0x0) {
iconView.setVisibility(GONE);
} else {
iconView.setImageResource(iconRes);
iconView.setColorFilter(foregroundColor);
}
final ImageButton expandToggle = header.findViewById(R.id.expandable_card_view_header_toggle);
expandToggle.setColorFilter(foregroundColor);
expandToggle.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (isExpanded) {
collapse(contentLayout);
expandToggle.animate().rotation(0).setDuration(animationSpeed);
} else {
expand(contentLayout);
expandToggle.animate().rotation(180).setDuration(animationSpeed);
}
isExpanded = !isExpanded;
}
});
}
private void expand(final View v) {
int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
final int targetHeight = v.getMeasuredHeight();
v.getLayoutParams().height = 1;
v.setVisibility(View.VISIBLE);
Animation a = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int) (targetHeight * interpolatedTime);
v.requestLayout();
}
@Override
public boolean willChangeBounds() {
return true;
}
};
a.setDuration(animationSpeed);
v.startAnimation(a);
}
private void collapse(final View v) {
final int initialHeight = v.getMeasuredHeight();
Animation a = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if (interpolatedTime == 1) {
v.setVisibility(View.GONE);
} else {
v.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime);
v.requestLayout();
}
}
@Override
public boolean willChangeBounds() {
return true;
}
};
a.setDuration(animationSpeed);
v.startAnimation(a);
}
}