2

I want an Activity that shows exactly four cards (never more or less) with the same layout as you can see in the image below. Can I implement this without using the, imo rather complex, RecyclerView and without the just copy & pasting xml four times? It is also important that I can access and change each of the views by id.

I currently have four CardViews stacked on top of each other and it feels very wrong. How should I be doing this?

How it should look like

Here is the bad XML code I used for the mockup above. I put it into an snippet since it is rather long and probably not very important to the question:

<?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=".LobbyActivity">

    <android.support.v7.widget.CardView
        android:id="@+id/player1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="16dp"
        app:layout_constraintBottom_toTopOf="@id/player2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintWidth_percent="0.95">

        <android.support.constraint.ConstraintLayout
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/player1Info"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="16dp"
                android:text="Playername - 100(+3)"
                android:textAppearance="@style/TextAppearance.AppCompat.Headline"
                android:textColor="@color/colorPrimary"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player1Thumb"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/player1Ready"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="16dp"
                android:text="Ready: true"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                android:textColor="#8A000000"
                android:textSize="18sp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player1Thumb"
                app:layout_constraintTop_toBottomOf="@+id/player1Info" />

            <ImageView
                android:id="@+id/player1Thumb"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginBottom="16dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@android:drawable/ic_lock_lock" />

        </android.support.constraint.ConstraintLayout>
    </android.support.v7.widget.CardView>

    <android.support.v7.widget.CardView
        android:id="@+id/player2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="16dp"
        app:layout_constraintBottom_toTopOf="@id/player3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/player1"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintWidth_percent="0.95">

        <android.support.constraint.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/player2Info"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="16dp"
                android:text="Playername - 100(+3)"
                android:textAppearance="@style/TextAppearance.AppCompat.Headline"
                android:textColor="@color/colorPrimary"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player2Thumb"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/player2Ready"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="16dp"
                android:text="Ready: true"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                android:textColor="#8A000000"
                android:textSize="18sp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player2Thumb"
                app:layout_constraintTop_toBottomOf="@+id/player2Info" />

            <ImageView
                android:id="@+id/player2Thumb"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginBottom="16dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@android:drawable/ic_lock_lock" />

        </android.support.constraint.ConstraintLayout>
    </android.support.v7.widget.CardView>

    <android.support.v7.widget.CardView
        android:id="@+id/player3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="16dp"
        app:layout_constraintBottom_toTopOf="@id/player4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/player2"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintWidth_percent="0.95">

        <android.support.constraint.ConstraintLayout
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/player3Info"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="16dp"
                android:text="Playername - 100(+3)"
                android:textAppearance="@style/TextAppearance.AppCompat.Headline"
                android:textColor="@color/colorPrimary"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player3Thumb"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/player3Ready"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="16dp"
                android:text="Ready: true"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                android:textColor="#8A000000"
                android:textSize="18sp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player3Thumb"
                app:layout_constraintTop_toBottomOf="@+id/player3Info" />

            <ImageView
                android:id="@+id/player3Thumb"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginBottom="16dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@android:drawable/ic_lock_lock" />

        </android.support.constraint.ConstraintLayout>
    </android.support.v7.widget.CardView>

    <android.support.v7.widget.CardView
        android:id="@+id/player4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/player3"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintWidth_percent="0.95">

        <android.support.constraint.ConstraintLayout
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/player4Info"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="16dp"
                android:text="Playername - 100(+3)"
                android:textAppearance="@style/TextAppearance.AppCompat.Headline"
                android:textColor="@color/colorPrimary"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player4Thumb"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/player4Ready"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="16dp"
                android:text="Ready: true"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                android:textColor="#8A000000"
                android:textSize="18sp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/player4Thumb"
                app:layout_constraintTop_toBottomOf="@+id/player4Info" />

            <ImageView
                android:id="@+id/player4Thumb"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginBottom="16dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@android:drawable/ic_lock_lock" />

        </android.support.constraint.ConstraintLayout>
    </android.support.v7.widget.CardView>

</android.support.constraint.ConstraintLayout>
leonheess
  • 16,068
  • 14
  • 77
  • 112

5 Answers5

2

If the card view looks the same, you can create a separate reusable layout with only one CardView in it. Then, you can use the <include> tag to add it 4 times. This way, if you ever need to change the look of it, you only do it once.

More info on how to achieve this here.

Example

<include 
   android:id="@+id/news_title" 
   android:layout_width="match_parent" 
   android:layout_height="match_parent" 
   layout="@layout/title"/>

NB: you can differentiate each included element by setting a an id, just like in the example above.

To get a child view, you will need its id. First, use the id to retrieve a the View (or CardView or...). For example:

CardView card1 = view.findViewById(cardView1);
card1.findViewById(player1Info);

Same with the next included card:

CardView card2 = view.findViewById(cardView2);
card2.findViewById(player1Info); //Notice how it is the same id here <------  
Ariles
  • 333
  • 1
  • 14
  • So I would just include the same layout four times? How would I be able to get the fields? Won't they all have the same view ids? – leonheess Oct 29 '18 at 09:40
  • i think so `` would be better option in your case. – Ali Ahmed Oct 29 '18 at 09:42
  • @AliAhmed Could you elaborate in an answer? – leonheess Oct 29 '18 at 09:43
  • 1
    You can give each element a different id. Here is an example from the link in the answer above: `` – Ariles Oct 29 '18 at 09:44
  • @Ariles So if I include the same layout four times and give each include an id. How can I separately access the first TextView of include 1 and include 2? – leonheess Oct 29 '18 at 09:55
  • 1
    @MiXT4PE you will need the child id. First, use the id to retrieve a the `View` (or CardView or...), for example: CardView **card1** = view.findViewById(cardView1); Then: card1.findViewById(**player1Info**); Same with the next included card: CardView **card2** = view.findViewById(cardView1); Then: card2.findViewById(**player1Info**); – Ariles Oct 29 '18 at 09:57
  • @Ariles Thank you very much! You should edit this in – leonheess Oct 29 '18 at 09:58
  • @MiXT4PE done ! I made a mistake in my last comment: the id for the cardView is different each time (cardView1 vs cardView2). – Ariles Oct 29 '18 at 10:05
0

Of course you can. Recycler view do not give you any advantages in your case.

But do not forget create style or use <include>.

It will help you if design will be changed in the future

In your case I recomend to use include. You can read about it here. The main idea is to create aditional cardview_layout.xml and use

<include layout="@layout/cardview_layout"/>

in your main xml file.

0

As described here <merge/> is used when you don't need extra View groups for good UI performance.

The tag helps eliminate redundant view groups in your view hierarchy when including one layout within another. For example, if your main layout is a vertical LinearLayout in which two consecutive views can be re-used in multiple layouts, then the re-usable layout in which you place the two views requires its own root view. However, using another LinearLayout as the root for the re-usable layout would result in a vertical LinearLayout inside a vertical LinearLayout. The nested LinearLayout serves no real purpose other than to slow down your UI performance.

<merge xmlns:android="http://schemas.android.com/apk/res/android">

<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/add"/>

<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/delete"/>

</merge>

Now, when you include this layout in another layout (using the <include/> tag), the system ignores the <merge> element and places the two buttons directly in the layout, in place of the <include/> tag.

Hope this helps you.

Ali Ahmed
  • 2,130
  • 1
  • 13
  • 19
0

If you are using RecyclerView use GridLayoutManager to achieve this

List<String> dataSource = new ArrayList<String>();


RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    recyclerView.setLayoutParams(lp);


    GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false);
    setContentView(recyclerView);
    recyclerView.setAdapter(new TextRecyclerAdapter(dataSource));
    recyclerView.setLayoutManager(gridLayoutManager);

here is git example for this

Adil
  • 812
  • 1
  • 9
  • 29
0

use a LinearLayout ... optionally, convert to 4 times include, with unique id attribute.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:orientation="vertical">

    <android.support.design.card.MaterialCardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp">
        <Space
            android:layout_width="match_parent"
            android:layout_height="80dp"/>
    </android.support.design.card.MaterialCardView>

    <android.support.design.card.MaterialCardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp">
        <Space
            android:layout_width="match_parent"
            android:layout_height="80dp"/>
    </android.support.design.card.MaterialCardView>

    <android.support.design.card.MaterialCardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp">
        <Space
            android:layout_width="match_parent"
            android:layout_height="80dp"/>
    </android.support.design.card.MaterialCardView>

    <android.support.design.card.MaterialCardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp">
        <Space
            android:layout_width="match_parent"
            android:layout_height="80dp"/>
    </android.support.design.card.MaterialCardView>

</android.support.v7.widget.LinearLayoutCompat>

this looks quite alike what you have there:

XML preview screenshot

Martin Zeitler
  • 1
  • 19
  • 155
  • 216