Logo
Published on
ยท10 min read

Creating Square Brackets ([ ]) Shaped Like Lottery Ticket Numbers (Android)

I apologize in advance for any awkward expressions in English.

English is not my native language, and I have relied on ChatGPT's assistance to proceed with the translation.

Quick Access to the Service

Lotto Number Generator


I created a lottery number generator service with a UI similar to a lottery ticket for both web and Android services. For the CSS styling of the lottery ticket numbers on the web service, please refer to the following post:

Creating Square Brackets ([ ]) Shaped Like Lottery Ticket Numbers(css)

Content to Explain

In this post, I'll explain how to implement the square bracket ([ ]) shape for lottery ticket numbers in an Android app.

You can see how the sections from 1 to 45, marked with square brackets, were implemented in the UI in the image below.

UI Implemented in Android
Capture

Implementation

1. Create Drawables

  • Unselected number drawable: app/src/main/res/drawable/border_lotto_number.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- A rectangle with a 2dp border in the @color/lotto color -->
    <item>
        <shape android:shape="rectangle">
            <stroke android:width="2dp" android:color="@color/lotto"/>
            <solid android:color="@color/lotto_background"/>
        </shape>
    </item>
    <!-- It covers a rectangle with @color/lotto_background background color located 10dp above and below -->
    <item android:top="10dp" android:bottom="10dp">
        <shape android:shape="rectangle">
            <!-- I noticed that the stroke part can be removed while writing this post, and it still works the same. -->
            <stroke android:width="2dp" android:color="@color/lotto_background"/>
            <solid android:color="@color/lotto_background"/>
        </shape>
    </item>
</layer-list>
  • Selected number drawable: app/src/main/res/drawable/border_lotto_number_selected.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
	<!-- A rectangle with a 2dp border in the @color/lotto color -->
    <item>
        <shape android:shape="rectangle">
            <stroke android:width="2dp" android:color="@color/lotto"/>
            <solid android:color="@color/lotto_background"/>
        </shape>
    </item>
    <!-- It covers a rectangle with @color/lotto_background background color located 10dp above and below -->
    <item android:top="10dp" android:bottom="10dp">
        <shape android:shape="rectangle">
            <stroke android:width="2dp" android:color="@color/lotto_background"/>
            <solid android:color="@color/lotto_background"/>
        </shape>
    </item>
    <!-- It covers rectangles with @color/black color located 2dp inside on the top, bottom, left, and right sides. -->
    <item android:top="2dp" android:bottom="2dp" android:left="2dp" android:right="2dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/black"/>
        </shape>
    </item>
</layer-list>

When you preview the above code in Android Studio using the Design or Split view, it should look as follows.

Left) Unselected number drawable, Right) Selected number drawable

2. Use Drawable Resources as the Background of TextView

Use the created drawable resources as the background for the TextView.

app/src/main/res/layout/number_item.xml > android:background="@drawable/border_lotto_number"

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/txt_lotto_number"
    android:layout_width="29dp"
    android:layout_height="45dp"
    android:gravity="center"
    tools:text="1"
    android:background="@drawable/border_lotto_number"
    android:textColor="@color/lotto"
    android:textStyle="bold"
    android:layout_marginBottom="10dp"
    />

When you preview the above code in Android Studio using the Design or Split view, it should look like this:

TextView Preview

3. Use number_item in RecyclerView

Use number_item.xml within a RecyclerView with a GridLayoutManager.

The connection with number_item isn't visible in the layout code below, but it's linked through the source code in the Adapter.

app/src/main/res/layout/game_item.xml > <androidx.recyclerview.widget.RecyclerView .../>

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="457dp"
    android:background="@drawable/border_lotto"
    android:layout_marginLeft="16dp"
    android:layout_marginTop="16dp"
    android:layout_marginRight="16dp"
    android:layout_marginBottom="16dp"
    >

    <!-- Abbreviation of the game round and selected number display section-->
    <LinearLayout
        android:id="@+id/game_summary"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <!-- Abbreviation of the game round display section -->
        <TextView
            android:id="@+id/txt_game_number"
            tools:text="1"/>
    </LinearLayout>

    <!-- This is where the lottery numbers are displayed. Refer to the LottoNumberAdapter code. -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/view_number_recycler"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/game_summary"
        app:layout_constraintBottom_toBottomOf="parent"
        app:spanCount="7"
        android:padding="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

When you preview the code in Android Studio using the Design or Split view, it should look like this (the part that says "item0 item1 item2..." should display the number_item created earlier):

RecyclerView Preview

The part in the source code that connects the RecyclerView and number_item is in:

app/src/main/java/kr/sosone/lotto/adapter/LottoNumberAdapter.kt

package kr.sosone.lotto.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import kr.sosone.lotto.R
import kr.sosone.lotto.model.LottoNumber

class LottoNumberAdapter (private val context: Context, private val dataset: List<LottoNumber>)
    : RecyclerView.Adapter<LottoNumberAdapter.ItemViewHolder>()
{
    class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view){
        // TextView defined in number_item.xml
        val txtLottoNumber: TextView = view.findViewById(R.id.txt_lotto_number)
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
        val adapterLayout = LayoutInflater.from(parent.context)
            .inflate(R.layout.number_item, parent, false)
        return ItemViewHolder(adapterLayout);
    }

    override fun onBindViewHolder(holder: LottoNumberAdapter.ItemViewHolder, position: Int) {
        val item = dataset[position]
        if(item.isPick){
            // If it's a selected item, change the background to border_lotto_number_selected and the text color
            holder.txtLottoNumber.setBackgroundResource(R.drawable.border_lotto_number_selected)
            holder.txtLottoNumber.setTextColor(ContextCompat.getColor(context, R.color.white))
        }

        holder.txtLottoNumber.text = item.number.toString()
    }

    override fun getItemCount() = dataset.size
}

app/src/main/java/kr/sosone/lotto/model/LottoNumber.kt

package kr.sosone.lotto.model

data class LottoNumber(val number: Int, val isPick: Boolean)

The LottoNumberAdapter is assigned in the parent RecyclerView Adapter.

(Note: The code related to this is beyond the scope of what we are explaining here, so it is abbreviated.)

app/src/main/java/kr/sosone/lotto/model/LottoGame.kt

class LottoGameAdapter(private val context: Context, private val dataset: List<LottoGame>)
    : RecyclerView.Adapter<LottoGameAdapter.ItemViewHolder>()
{
    class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view){
        // Handling nested RecyclerView
        val viewNumberRecycler: RecyclerView = view.findViewById(R.id.view_number_recycler)
    }

    override fun onBindViewHolder(holder: LottoGameAdapter.ItemViewHolder, position: Int) {
        // Handling nested RecyclerView
        holder.viewNumberRecycler.adapter = LottoNumberAdapter(context, item.fullNumbers)
        holder.viewNumberRecycler.setHasFixedSize(true)
    }
}