Created
December 1, 2017 11:36
-
-
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.
This file contains 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
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