Android TextView Using Kotlin

Filed Under: Android

Are you a seasoned Android Developer and are looking to switch from Java to Kotlin? Are you a beginning as an Android Developer and want to use Kotlin in your next cool application? Either ways, this tutorial is the ideal place you’ve come upon. We’ll be discussing TextViews in Android using Kotlin. Using Kotlin, we’ll be creating and changing TextViews and see how easy it is to write and understand the code. Let the journey begin!

Android TextView

Android TextView class is a subclass of the View class in Android. The View class can typically occupy our window. TextView is used to display text on the screen. Furthermore, we can do lots of fancy things using TextView.

Let’s start off with a fresh new project in Android Studio. Create a new project and make sure you’ve enabled Kotlin in the setup wizard!

android-textview-project-setup-kotlin

Creating TextView in xml

TextView is created in an xml layout in the following manner:


<TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

The 4 attributes defined above are the core attributes of the TextView widget.
id is used to set a unique identifier. It’s set as @+id/ followed by the name you assign. The same name would be used to retrieve the TextView property in our Kotlin Activity class.
text is used to set the string text to be displayed.
As it is evident from the names itself, layout_width and layout_height are used to set the boundaries of the TextView. wrap_content means, wrapping the width, height to the length of the text. match_parent means the TextView matches the width/height of the enclosed parent view. We can also set hardcoded values in dp(device independent pixels).

Clean code tisp: Instead of hardcoding the string, define it inside the strings.xml and set the text in the layout as : android:text="@string/app_name".

Let’s know and apply some attributes over the TextView in XML.

Xml Attributes over TextView

Let’s give you a quick tour of some of the popular attributes for TextView
android:textSize: Set the size of the TextView. It’s recommended to use sp instead of dp. sp stands for scale independent pixels and scales the font. Example: 16sp.
android:textColor is used to set a color for the text. Typically it is of the format #rgb, #rrggbb, #aarrggbb.
android:background is used to set the background color of the TextView
android:textStyle is used to set the style among bold, italic, normal. To set bold and italic we use android:textStyle = “bold|italic”
android:textAppearance is used to set the a style on a TextView which includes its own color, font,size. We can create custom styles in the styles.xml file.
android:visibility is used to set the visibililty of the text among visible, invisible, gone. gone makes the textview invisible and removes it from the current position in the layout.
android:ellipsize is used to handle situations when the length of the text exceeds the limit.
android-textview-xml-ellipisize-kotlin. end adds dots are the text reaches the limit width of the TextView. start adds the dots at the beginning. marquee is used to make the text continously slide left and right to show the full text.
android:onClick : The value set to this is the method name in the Kotlin Activity class that’ll be invoked on TextView click. We need to ensure android:clickable is set to true for this attribute.
android:typeface is used to set the typeface of the text from among:
android-textview-xml-typeface-kotlin
android:drawableLeft is used to set a drawable/mipmap image or vector asset besides the textView.
android:gravity is used to set the position of the text relative to it’s dimensions.
android:layout_margin is used to set the spacing of the TextView from the other views present in the layout. layout_marginLeft, layout_marginRight, layout_marginTop, layout_marginBottom are used for setting margins on the individiual sides.
android:padding is used to add spacing inside the four sides of the TextView. paddingLeft, paddingRight, paddingTop, paddingBottom are used for the individual sides.

Let’s use the xml attributes on a TextView in our layout.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:id="@+id/linearLayout"
    android:orientation="vertical"
    tools:context="net.androidly.androidtextviewkotlin.MainActivity">


    <TextView
        android:id="@+id/textViewEllipsize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:ellipsize="end"
        android:maxLines="1"
        android:text="@string/long_string"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/textViewClickMe"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:background="@color/colorPrimaryDark"
        android:padding="@android:dimen/app_icon_size"
        android:shadowColor="@android:color/black"
        android:text="TextView Click Me" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Android TextView Color"
        android:textAllCaps="true"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="#234568"
        android:textStyle="bold|italic" />

    <TextView
        android:id="@+id/textViewOpacity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:drawableLeft="@mipmap/ic_launcher"
        android:drawablePadding="16dp"
        android:gravity="center"
        android:text="Android TextView Opacity is 50 percent"
        android:textColor="#50234568"
        android:textSize="14sp"
        android:typeface="serif" />


</LinearLayout>

Note: We’ve replaced the ConstraintLayout with a LinearLayout to make things easier.

android-textview-xml-output

Notice the opacity in the last TextView

For more info on xml attributes for Android TextView, visit the Google docs attached at the end of this page or JournalDev Android TextViews tutorial.

Now let’s get onto Kotlin!!
In the following section we’ll be using creating TextView programmatically using Kotlin and set Kotlin functions, properties, use lambda functions over the TextView.

Using Kotlin with Android TextView

Let’s get the TextView in our MainActivity.kt Kotlin class using findViewById.
findViewById is used to get a view from the XML in the Activity class using the id specified. It works like a dictionary – key/value pair.


package net.androidly.androidtextviewkotlin

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    val TAG = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var textView = findViewById(R.id.textView)
        
        //text property is equivalent to getText() or setText() in Java.
        Log.d(TAG,"TextView text is ${textView.text}") //Logs TextView text is Android TextView Color
        
        //setting the text.
        textView.text = "Text changed"
        
        //Setting the text from the strings.xml file.
        textView.text = resources.getString(R.string.app_name)

    }
}

In the above code:

  • MainActivity Kotlin class extends AppCompatActivity.
  • We’ve created the textView property by using findViewById. Though from Android API > 24 you can ignore specifying the type explicitly.
  • The text property is used as getter/setter on the TextView. It returns a CharSequence.
  • ${textView.text} implcitily converts the CharSequence to a String.
  • The text property in Kotlin is equivalent to getText() and setText(String) in Java.
  • To set the string from the strings.xml file we call resources.getString(R.string.).
    resources property is equivalent to getResources() from Java.

Handling Null Values in TextView

Kotlin has a very safe way to deal with null values. Optional Types act as a wrapper over the current type and need to be safely unwrapped to use non-null values thus enabling null safety in our code.

Let’s look at how the above app behaves when the textView is null.


override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var textView = findViewById(R.id.textView)
        textView.text = null
        Log.d(TAG, "TextView text is ${textView.text}") // Logs TextView text is
        textView = null
        Log.d(TAG, "TextView text is ${textView.text}") //compilation error. Add safe call.
}

So when the text is null, the compiler ignores it.
When the textView is null, in all the future calls we need to add a safe call to unwrap the textView. This way Kotlin automatically gives us null safety.

What if the textView goes null at runtime?


override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //we've set a random id available from the autocomplete just to set textView to null at runtime.
        var textView = findViewById(R.id.ALT) 
        Log.d(TAG, "TextView text is ${textView.text}")
    }

IllegalStateException. TextView cannot be null. CRASH

So let’s set the TextView properties as Optionals in the declaration.


override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val otherTextView: TextView? = findViewById(R.id.textViewOpacity)
        otherTextView?.text = null
        Log.d(TAG, "TextView displays ${otherTextView?.text ?: "NA"}")
    }

We’ve set otherTextView to the type TextView?.
So calling anything over the TextView would require a safe call.

What if the text is null? What do we display instead?
We use the elvis operator ?: from Kotlin for null safety.
In the above code, NA gets displayed if otherTextView?.text is null.
The safe call can be replaced by a let lambda expression too.

Kotlin Android Extensions

Thanks to apply plugin: 'kotlin-android-extensions' in our build.gradle file, we can directly bind views from the layout in our Kotlin activity class.

Add the following import statement in your MainActivity.kt class.


import kotlinx.android.synthetic.main.activity_main.*

Now you can use the TextView properties directly, without using findViewById.

Android TextView onClick Listener


package net.androidly.androidtextviewkotlin

import android.graphics.Color
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    val TAG = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //set textView to clickable
        textView.isClickable = true
        textView.setOnClickListener{ textView.text = resources.getString(R.string.app_name) }

        textViewClickMe.setOnClickListener { textViewClickMe.setTextColor(Color.WHITE) }

        textViewEllipsize.ellipsize = TextUtils.TruncateAt.MARQUEE
        textViewEllipsize.setHorizontallyScrolling(true)
        textViewEllipsize.marqueeRepeatLimit = -1
        textViewEllipsize.isSelected = true

        val mipMapDrawable = ContextCompat.getDrawable(this, R.mipmap.ic_launcher)
        textViewOpacity.setCompoundDrawablesWithIntrinsicBounds(mipMapDrawable,null,mipMapDrawable,null)

    }
}

In the above code, for the setOnClickListener we use lambda expressions from Kotlin. It makes the code shorter and easier to read than Java.
To make the textViewEllipsize slide, set it to MARQUEE. To make it loop continuously, we’ve set marqueeRepeatLimit to -1.
mipMapDrawable is of the type Drawable and setCompoundDrawablesWithIntrinsicBounds() is the equivalent of android:drawablePadding.

The output when the above code is run looks like this:
android-textview-kotlin-onclick-output

Android TextView extension functions

We can create Kotlin extension functions on a TextView to add our custom functions and properties.
The below extension function creates a consistent property for currentTextColor property and setTextColor() function.

Add the following code outside the class.


var TextView.textColor: Int
    get() = currentTextColor
    set(v) = setTextColor(v)

We can then set the color on our TextView using the textColor property above.


textViewOpacity.textColor = ContextCompat.getColor(this, R.color.colorPrimaryDark)

Android TextView and with expression

Instead of using redundant lines wherein we set the attributes on the same TextView property like this:


textViewEllipsize.ellipsize = TextUtils.TruncateAt.MARQUEE
textViewEllipsize.setHorizontallyScrolling(true)
textViewEllipsize.marqueeRepeatLimit = -1
textViewEllipsize.isSelected = true
textViewEllipsize.setOnClickListener { println("So many calls to the same TextView") }

We make it better using the with expression.


with(textViewEllipsize)
        {
            ellipsize = TextUtils.TruncateAt.MARQUEE
            setHorizontallyScrolling(true)
            marqueeRepeatLimit = -1
            isSelected = true
            setOnClickListener { println("WOW. AWESOME.") }
        }

Creating a TextView Programmatically

Below, we’ve created two TextViews programmatically. We’ve set a custom font from the assets folder and set underline on one of the TextViews. Also, we’ve set the string in the form of HTML. assets directory is created under src | main folder and is used to hold the ttf files for the custom fonts.


package net.androidly.androidtextviewkotlin

import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.content.ContextCompat
import android.text.Html
import android.text.TextUtils
import android.view.Gravity
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    val TAG = "MainActivity"
    lateinit var programmaticTextView : TextView
    var optionalTextView : TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        programmaticTextView = TextView(this)
        with(programmaticTextView)
        {
            text = "I'm Created Programmatically. Kotlin makes life simple"
            textSize = 20f
            textColor = Color.parseColor("#1F2135")
            typeface = Typeface.DEFAULT_BOLD
            isClickable = true
            setOnClickListener { println("I contain the string: $text") }
        }

        linearLayout.addView(programmaticTextView)

        optionalTextView = TextView(this)

        optionalTextView.let { with(optionalTextView!!)
        {
            text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                "${Html.fromHtml("

this is underlined text

Body goes here",Html.FROM_HTML_MODE_LEGACY)}" } else { @Suppress("DEPRECATION") "${Html.fromHtml("this is underlined text")}" } typeface = Typeface.createFromAsset(assets, "Pacifico.ttf") textSize = 20f gravity = Gravity.CENTER paintFlags = Paint.UNDERLINE_TEXT_FLAG } } linearLayout.addView(optionalTextView) } } var TextView.textColor: Int get() = currentTextColor set(v) = setTextColor(v)

Kotlin properties are required to be initialized there itself. If it’s not possible, we can set a lateinit modifier to the property.
By default when the textView is created programmatically, it’s width is match_parent and height is wrap_content.
paintFlags is used to add an underline to the string.
The output with the above TextViews added into the layout programmatically is given below.
android-textview-kotlin-output

Using Spannable Strings

Spannable Strings are useful when we need to set different styles on different substrings of the TextView.


val string = "this is normal, this is underlined"
        val firstWord = string.substringBefore(",")
        val secondWord = string.substringAfterLast(",")
        val redColor = ForegroundColorSpan(
                ContextCompat.getColor(this,android.R.color.holo_red_dark))

        val ssb = SpannableStringBuilder(firstWord)

        ssb.setSpan(
                redColor, // the span to add
                0, // the start of the span (inclusive)
                ssb.length, // the end of the span (exclusive)
                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        ssb.append(" ")

        val underlineSpan = UnderlineSpan()

        ssb.append(secondWord)
        ssb.setSpan(
                underlineSpan,
                ssb.length - secondWord.length,
                ssb.length,
                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

        optionalTextView = TextView(this)

        optionalTextView.let { with(optionalTextView!!)
        {
            text = ssb
            typeface = Typeface.createFromAsset(assets, "Pacifico.ttf")
            textSize = 20f
            gravity = Gravity.CENTER


        } }

        linearLayout.addView(optionalTextView)

The output is like this:
android-textview-kotlin-spannable-string

This brings an end to this comprehensive tutorial on Android TextViews using Kotlin.
You can download the project from the link below.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages