Skip to content

Instantly share code, notes, and snippets.

@amank22
Created December 1, 2017 11:36
Show Gist options
  • Save amank22/5f37e6a283e887e31ec45f93a2c93642 to your computer and use it in GitHub Desktop.
Save amank22/5f37e6a283e887e31ec45f93a2c93642 to your computer and use it in GitHub Desktop.
A ViewGroup that can have children stacked as card on one above. You can move only to next card with each card removing from stack. Can be used where some steps are needed in particular order.
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by amankapoor on 23/11/17.
* [email protected]
*/
public class CardStackLayout extends ViewGroup {
private static final String TAG = CardStackLayout.class.getCanonicalName();
private int marginBetweens = 25;
private int marginBetweensHeight = 25;
public CardStackLayout(Context context) {
super(context);
init();
}
public CardStackLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CardStackLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CardStackLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
}
@Override
public boolean isInEditMode() {
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
final int widthParent = MeasureSpec.getSize(widthMeasureSpec);
final int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom() - getPaddingTop();
final int heightParent = MeasureSpec.getSize(heightMeasureSpec);
final int childCount = getChildCount();
int childWidth = width;
int childHeight = height;
for (int i = childCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
int childLocalHeight = (int) (childHeight - (childCount - 1 - i) * marginBetweensHeight - heightParent * 0.25);
int childLocalWidth = childWidth - (childCount - 1 - i) * marginBetweens;
LayoutParams lp = child.getLayoutParams();
if (lp instanceof MarginLayoutParams) {
childLocalHeight -= ((MarginLayoutParams) lp).bottomMargin - ((MarginLayoutParams) lp).topMargin;
}
int childWidthSpec = MeasureSpec.makeMeasureSpec(childLocalWidth, MeasureSpec.EXACTLY);
int childHeightSpec = MeasureSpec.makeMeasureSpec(childLocalHeight, MeasureSpec.AT_MOST);
Log.d(TAG, "onMeasure: " + childLocalHeight);
measureChildWithMargins(child, childWidthSpec, 50, childHeightSpec, 50);
childWidth -= marginBetweens;
childHeight -= marginBetweensHeight;
}
// 10. Set the dimension for this ViewGroup.
setMeasuredDimension(
resolveSize(widthParent, widthMeasureSpec),
resolveSize(heightParent, heightMeasureSpec));
}
@Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
int width = MeasureSpec.getSize(parentWidthMeasureSpec);
int height = MeasureSpec.getSize(parentHeightMeasureSpec);
int childWidthMeasureSpec = getChildMeasureSpec(
parentWidthMeasureSpec,
widthUsed,
width);
int childHeightMeasureSpec = getChildMeasureSpec(
parentHeightMeasureSpec,
heightUsed,
height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int nextChildLeft = getPaddingLeft();
final int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
child.layout(nextChildLeft, getPaddingTop() + (i + 1) * marginBetweensHeight, right, bottom);
nextChildLeft += marginBetweens;
final float alpha = (float) (1 - ((childCount - 1 - i) * 0.22));
ViewCompat.setAlpha(child, alpha);
}
}
public void moveToNext() {
final int childCount = getChildCount();
if (childCount <= 0) {
return;
}
final View view = getChildAt(childCount - 1);
ViewCompat.animate(view).setDuration(700).translationYBy(view.getHeight() + 800).rotationBy(25).alpha(0).scaleX(0).scaleY(0).setInterpolator(new FastOutSlowInInterpolator())
.setListener(new ViewPropertyAnimatorListenerAdapter() {
@Override
public void onAnimationEnd(View viewL) {
super.onAnimationEnd(viewL);
removeView(view);
requestLayout();
invalidate();
}
}).start();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment