Dexter
Dexter

Reputation: 1551

Recyclerview horizontal deck of cards effect

I am trying to make simple card game where I need to show deck of cards laying on the desk horizontally and user can select any number of cards by clicking them. Ideally when use click on any card, card should elevate a bit from other cards. Plus cards are not completely visible, they are partially visible like this. I have created custom Recyclerview and used item decorator to change offset of cards. However whenever I change offset, first or last card of deck is completely overlapped by others. Like following image,

enter image description here

How to show above effect properly, without loosing first (or last) card? Also how to implement elevation of any of these cards when we click on them ? I tried to use "setElevation()" but it has no effect. It will be nice if I can achieve this without any third party library (however I am open to suggestions.). I used following code,

Game.java

public class Game extends AppCompatActivity {

    private List<Card> cards = new ArrayList<>();
    private RecyclerView.ItemDecoration decoration = new OverlapDecoration();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.game);
        RecyclerView marketDeck = (RecyclerView) findViewById(R.id.market_deck);


        Card item1 = new Card();
        item1.setImage(R.color.colorPrimary);
        Card item2 = new Card();
        item2.setImage(R.color.colorAccent);

        cards.add(item1);
        cards.add(item2);
        cards.add(item1);
        cards.add(item2);
        cards.add(item1);

        CardHolder cardHolder = new CardHolder(cards);
        marketDeck.setAdapter(cardHolder);
        marketDeck.setLayoutManager(new LinearLayoutManager(getBaseContext(), LinearLayoutManager.HORIZONTAL, false));
        marketDeck.addItemDecoration(decoration);

        cardHolder.setOnCardClick(new CardHolder.onCardClick() {
            @Override
            public void onClick(View v) {
                v.setElevation(10);
            }
        });


    }

    private class OverlapDecoration extends RecyclerView.ItemDecoration {

        //Following code from : http://stackoverflow.com/questions/27633454/how-to-overlap-items-in-linearlayoutmanager-recyclerview-like-stacking-cards
        private final static int overlap = -100;

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);

            final int itemPosition = parent.getChildAdapterPosition(view);
            if (itemPosition == RecyclerView.NO_POSITION) {
                return;
            }
            outRect.set(overlap, 0, 0, 0);
        }
    }

}

CardHolder.java

public class CardHolder extends RecyclerView.Adapter<CardHolder.CardView> {

    private List<Card> cards;

    private onCardClick cardClick;

    public CardHolder(List<Card> cards) {
        this.cards = cards;
    }

    @Override
    public CardView onCreateViewHolder(ViewGroup parent, int viewType) {
        return new CardView(LayoutInflater.from(parent.getContext()).inflate(R.layout.card, parent, false));
    }

    @Override
    public void onBindViewHolder(CardView holder, int position) {
        Card card = cards.get(position);
        holder.icon.setImageResource(card.getImage());

    }

    @Override
    public int getItemCount() {
        return cards.size();
    }

    class CardView extends RecyclerView.ViewHolder {
        ImageView icon;

        CardView(final View itemView) {
            super(itemView);
            icon = (ImageView) itemView.findViewById(R.id.card_icon);
            icon.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    cardClick.onClick(v);
                }
            });
        }
    }

    void setOnCardClick(onCardClick click) {
        cardClick = click;
    }

    public interface onCardClick {
        void onClick(View v);
    }


}

Card.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="5sp">

    <ImageView
        android:id="@+id/card_icon"
        style="@style/CardTheme"
        android:contentDescription="@null"
        app:srcCompat="@color/colorPrimary" />
</LinearLayout>

game.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.company.someapp.Game">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/market_deck"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

Note: I have kept recyclerview width are "wrap_content" because number of cards will be variable.

Upvotes: 3

Views: 2848

Answers (1)

Dexter
Dexter

Reputation: 1551

Got it working by adjusting margin of first element like following,

private class OverlapDecoration extends RecyclerView.ItemDecoration {

        //Following code from : http://stackoverflow.com/questions/27633454/how-to-overlap-items-in-linearlayoutmanager-recyclerview-like-stacking-cards
        private final static int overlap = -100;

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);

             final int itemPosition = parent.getChildAdapterPosition(view);
        if (itemPosition == 0) {
            outRect.set(0, 0, 0, 0);
        } else {
            outRect.set(overlap, 0, 0, 0);
        }
        }
    }

Upvotes: 5

Related Questions