• Post author:
  • Post category:Android
  • Reading time:10 mins read

Welcome to the final part of this Tic Tac Toe Android Kotlin beginner tutorial series. To go to part 1 of this series, click here.

In this tutorial, we’ll change the boring UI that we have so far into this beautiful UI. Let’s get started.

tic tac toe
Final UI

Background Image and Icons

We’ll be using the below image as the background image.

abstract painting with red and blue colors
Photo by Anni Roenkae on Pexels.com

We’ll use the below two images as our custom “X” and “O” placeholders.

Custom “X” Icon

By Pixel perfect from www.flaticon.com

Custom “O” Icon

By Freepik from www.flaticon.com

Once you’ve downloaded the above images, add them to res/drawables folder.

res>drawables folder

Adding The Background Image

Add the below attribute to the Top-Level Parent LinearLayout. This will set our background image as the background.

android:background="@drawable/background"

We need to update the text color of our TextViews from Black to White to make them visible in this darker background. Add the below attribute to all 3 TextViews.

android:textColor="#FFFFFF"

Add the below attributes to the Reset Game Button widget.

android:background="@android:color/background_light"
android:textStyle="bold"
android:paddingHorizontal="@dimen/layout_margin"

3X3 GameBoard ImageButtons

Since we’re going to be using the above-shown icons for “X”es and “O”s, we need to change the Button widgets to the ImageButton widgets for the 3×3 GameBoard. Once you’ve done that, add the below attributes to the ImageButtons.

android:layout_width="@dimen/square_btn_size"
android:layout_height="@dimen/square_btn_size"
android:layout_margin="@dimen/btn_margin"

custom_button.xml

To turn the default ImageButton into the one like we have in the image above, we need to customize it a bit. Create a new Drawable Resource File in the Drawable folder and name it custom_button.

Add the below code to this file. The stroke is the border around the shape (rectangle here). The solid element gives attributes to fill the shape. The 99 in the android:color="#992A5BD6" sets the transparency.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <stroke android:color="#2A5BD6" android:width="5dp"/>
    <solid android:color="#992A5BD6"/>
</shape>

Now add this attribute to the ImageButtons.

android:background="@drawable/custom_button"

Finally, this is what the ImageButton widget should look like.

<ImageButton
            android:id="@+id/btnxx"
            android:layout_width="@dimen/square_btn_size"
            android:layout_height="@dimen/square_btn_size"
            android:layout_margin="@dimen/btn_margin"
            android:background="@drawable/custom_button"/>

Update Kotlin Code to use “X”-“O” Icons

                                 // Change here
lateinit var buttons: Array<Array<ImageButton>>
                                       // Change here
private fun initButtons(r: Int, c: Int): ImageButton {
            // Change here
    val btn: ImageButton = findViewById(...)
    .
    .
    .
}
private fun onBtnClick(btn: ImageButton) {
        // Change here
        if(btn.drawable != null) return
        if(player1Turn){
            // Change here
            btn.setImageResource(R.drawable.cross)
        }else{
            // Change here
            btn.setImageResource(R.drawable.heart)
        }
        .
        .
        .
    }
private fun clearBoard() {
        for (i in 0..2){
            for(j in 0..2){
                // Change here
                buttons[i][j].setImageResource(0)
            }
        }
        roundCount = 0
        player1Turn = true
    }

Since we’re using Images for “X” and “O”, we’re going to implement a new getField() function that will return us the text “x” or “o” that is needed in the fields array.

private fun checkForWin(): Boolean {
        val fields = Array(3){r->
            Array(3){c->
                // Change here
                getField(buttons[r][c])
            }
        }

        for(i in 0..2){
            if((fields[i][0] == fields[i][1])&&
                (fields[i][0] == fields[i][2])&&
                (fields[i][0] != null)// Change here
            )return true
        }

        for(i in 0..2){
            if(
                (fields[0][i] == fields[1][i])&&
                (fields[0][i] == fields[2][i])&&
                (fields[0][i] != null)// Change here
            )return true
        }

        if(
            (fields[0][0] == fields[1][1])&&
            (fields[0][0] == fields[2][2])&&
            (fields[0][0] != null)// Change here
        ) return true

        if(
            (fields[0][2] == fields[1][1])&&
            (fields[0][2] == fields[2][0])&&
            (fields[0][2] != null)// Change here
        ) return true

        return false

    }

Here is the getField() function.

private fun getField(btn: ImageButton): Char? {
        val drw: Drawable? = btn.drawable
        val drwCross: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.cross, null)
        val drwHeart: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.heart, null)

        return when(drw?.constantState){
            drwCross?.constantState -> 'x'
            drwHeart?.constantState -> 'o'
            else -> null
        }
    }

Alright, these are all the changes. You can check and run to see if everything is fine.

I hope all of this has been a fun learning experience for you. In case I’ve missed anything, let me know in the comments. This concludes our Android Kotlin Tic Tac Toe Series. See you in the next one.