package io.virtualapp.widgets;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import io.virtualapp.R;
/**
* Displays a list of cards as a stack on the screen.
* <p>
* <b>XML attributes</b>
* <p>
* See {@link R.styleable#CardStackLayout CardStackLayout Attributes}
* <p>
* {@link R.styleable#CardStackLayout_showInitAnimation}
* {@link R.styleable#CardStackLayout_card_gap}
* {@link R.styleable#CardStackLayout_card_gap_bottom}
* {@link R.styleable#CardStackLayout_parallax_enabled}
* {@link R.styleable#CardStackLayout_parallax_scale}
*/
public class CardStackLayout extends FrameLayout {
public static final boolean PARALLAX_ENABLED_DEFAULT = false;
public static final boolean SHOW_INIT_ANIMATION_DEFAULT = true;
private float mCardGapBottom;
private float mCardGap;
private boolean mShowInitAnimation;
private boolean mParallaxEnabled;
private int mParallaxScale;
private OnCardSelected mOnCardSelectedListener = null;
private CardStackAdapter mAdapter = null;
public CardStackLayout(Context context) {
super(context);
resetDefaults();
}
public CardStackLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CardStackLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
handleArgs(context, attrs, defStyleAttr, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CardStackLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
handleArgs(context, attrs, defStyleAttr, defStyleRes);
}
/**
* package restricted
*/
OnCardSelected getOnCardSelectedListener() {
return mOnCardSelectedListener;
}
/**
* Listen on card selection events for {@link CardStackLayout}. Sends
* clicked view and it's corresponding position in the callback.
*
* @param onCardSelectedListener
* listener
*/
public void setOnCardSelectedListener(OnCardSelected onCardSelectedListener) {
this.mOnCardSelectedListener = onCardSelectedListener;
}
private void resetDefaults() {
mOnCardSelectedListener = null;
}
private void handleArgs(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
resetDefaults();
final TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CardStackLayout, defStyleAttr,
defStyleRes);
mParallaxEnabled = a.getBoolean(R.styleable.CardStackLayout_parallax_enabled, PARALLAX_ENABLED_DEFAULT);
mShowInitAnimation = a.getBoolean(R.styleable.CardStackLayout_showInitAnimation, SHOW_INIT_ANIMATION_DEFAULT);
mParallaxScale = a.getInteger(R.styleable.CardStackLayout_parallax_scale,
getResources().getInteger(R.integer.parallax_scale_default));
mCardGap = a.getDimension(R.styleable.CardStackLayout_card_gap, getResources().getDimension(R.dimen.card_gap));
mCardGapBottom = a.getDimension(R.styleable.CardStackLayout_card_gap_bottom,
getResources().getDimension(R.dimen.card_gap_bottom));
a.recycle();
}
/**
* @return adapter of type {@link CardStackAdapter} that is set for this
* view.
*/
public CardStackAdapter getAdapter() {
return mAdapter;
}
/**
* Set the adapter for this {@link CardStackLayout}
*
* @param adapter
* Should extend {@link CardStackAdapter}
*/
public void setAdapter(CardStackAdapter adapter) {
this.mAdapter = adapter;
mAdapter.setAdapterParams(this);
for (int i = 0; i < mAdapter.getCount(); i++) {
mAdapter.addView(i);
}
if (mShowInitAnimation) {
postDelayed(this::restoreCards, 500);
}
}
/**
* @return currently set parallax scale value.
*/
public int getParallaxScale() {
return mParallaxScale;
}
/**
* Sets the value of parallax scale. Parallax scale is the factor which
* decides how much distance a card will scroll when the user drags it down.
*/
public void setParallaxScale(int mParallaxScale) {
this.mParallaxScale = mParallaxScale;
}
public boolean isParallaxEnabled() {
return mParallaxEnabled;
}
public void setParallaxEnabled(boolean mParallaxEnabled) {
this.mParallaxEnabled = mParallaxEnabled;
}
public boolean isShowInitAnimation() {
return mShowInitAnimation;
}
public void setShowInitAnimation(boolean mShowInitAnimation) {
this.mShowInitAnimation = mShowInitAnimation;
}
/**
* @return the gap (in pixels) between two consecutive cards
*/
public float getCardGap() {
return mCardGap;
}
/**
* Set the gap (in pixels) between two consecutive cards
*/
public void setCardGap(float mCardGap) {
this.mCardGap = mCardGap;
}
/**
* @return gap between the two consecutive cards when collapsed to the
* bottom of the screen
*/
public float getCardGapBottom() {
return mCardGapBottom;
}
public void setCardGapBottom(float mCardGapBottom) {
this.mCardGapBottom = mCardGapBottom;
}
/**
* @return true if a card is selected, false otherwise
*/
public boolean isCardSelected() {
return mAdapter.isCardSelected();
}
/**
* Removes the adapter that was previously set using
* {@link #setAdapter(CardStackAdapter)}
*/
public void removeAdapter() {
if (getChildCount() > 0)
removeAllViews();
mAdapter = null;
mOnCardSelectedListener = null;
}
/**
* Animates the cards to their initial position in the layout.
*/
public void restoreCards() {
mAdapter.resetCards();
}
/**
* Intimates the implementing class about the selection of a card
*/
public interface OnCardSelected {
void onCardSelected(View v, int position);
}
}