ListView in Android

ListView-in-Android.png

17th March, 2023

Hello Android Learner, you want to display a list in an application. What will you do? Android has a widget that can be used. In this part we will learn about Android ListView. Let’s start.

1. What is ListView?

ListView is a Android User Interface (UI) widely used in Android application development. ListView is used to display scrollable list of items. A common example of a ListView is our contact book in which contacts are displayed as a list.

Android-ListView-Sample.png
Android ListView

Before going to create Android ListView, we need understand List Item (List Row) and List Adapter as they are used to create Android ListView.

2. ListItem

Android ListItems are the individual rows of the ListView in which the data will be displayed. ListItem can be created by a number of views.

List-Item-Single-row-of-Android-ListView.png

3. Android Adapters

Android adapter is used to fill the data in the ListView. Android adapter acts as a bridge between the views (e.g. ListView, GridView) and data. We can use the adapter through the setAdapter() method. See the image below which shows the function of the Android Adapter.

Android-Adapter-for-ListView.png

3.1 Android Adapters used for ListView

Value Description
ArrayAdapter It is used to display ListView, GridView with simple Item element. Item can be created from TextView, CheckBox etc.
CursorAdapter CursorAdapter is used to display data by cursor instance when we have to display data from database.
SimpleAdapter SimpleAdapter is used to display static data defined in XML.
BaseAdapter BaseAdapter is common adapter used in ListView, GridView, Spinner, etc. It is a generic implementation of all the above adapters.

4. Create Android ListView using Android Studio

We can create Android ListView in two ways:

4.1 Create/Add ListView in XML layout file

Open the XML layout file in Android Studio, select ListView from the palette and add it to the layout.

Add-ListView-Android-Studio.gif

The source code is given below.

XML
content_copy light_mode remove
<?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:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <ListView
        android:id="@+id/myListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

4.2 Create ListView Programmatically in Android

Alternatively we can create Android ListView from a Kotlin/Java file. Create an instance of the ListView class by passing an activity context as a constructor parameter. Add the listView to the layout via the addView() method.

KotlinJava
content_copy light_mode remove
package com.androidchunk.hellolistview

import android.os.Bundle
import android.widget.*
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

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

        //a layout
        val aLayout = findViewById<LinearLayout>(R.id.linearLayout)

        //create listview
        val aListView = ListView(this)

        //add the listview to the layout
        aLayout.addView(aListView)
    }
}
package com.androidchunk.hellolistview;

import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.ListView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //a layout
        LinearLayout aLayout= findViewById(R.id.linearLayout;

        //create listview
        ListView aListView = new ListView(this);

        //add the listview to the layout
        aLayout.addView(aListView);
    }
}

Now we have created/Added a blank ListView. What about listView items? Where is the Implementation? We will cover it in the following examples.

5. Android ListView Attributes

Attribute Description
android:divider It is the drawable resource or color that is drawn between list items.
android:dividerHeight Height of the list divider
android:entries An array resource that will populate the ListView
android:headerDividersEnabled If we set the value to false, the ListView will not draw the divider after each header view. The default value is true.
android:footerDividersEnabled If we set the value to false, the ListView will not draw the divider before each footer view. The default value is true.
android:listSelector It is used to beautify the listView. It indicates currently selected item in the listView.

6. Android ListView Examples

6.1 Simple Android ListView with ArrayAdapter Example

In this example we will create a simple Android ListView using ArrayAdapter.

Step 6.1.1: Create New Project

Create a new project in Android Studio from File ⇒ New Project and select Empty Activity from the templates.

Step 6.1.2: Add ListView to the XML Layout (UI)

Open the xml layout file and add a ListView from the palette. See the code below.

XML
content_copy light_mode remove
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:alpha="0.3"
        android:text="Hello Androidchunk!" />

    <ListView
        android:id="@+id/myListView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

Step 6.1.3: Update Activity File

Open the activity file and create an instance of ListView. Create an instance of arrayAdapter and set it to the listView.

KotlinJava
content_copy light_mode remove
package com.androidchunk.hellolistview;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    //data
    private String[] countries = new String[]
            {"Switzerland", "Canada", "India", "United States", "Germany",
                    "Sweden", "Japan", "Australia", "United Kingdom", "New Zealand", "Sweden",
                    "China", "France", "Brazil", "Russia", "Spain", "United Arab Emirates"};

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Array adapter
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, countries);

        //instance of listview
        ListView aListView = findViewById(R.id.myListView);

        //set the arrayAdapter to the listView
        aListView.setAdapter(arrayAdapter);

        //ListView click listener
        aListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                Toast.makeText(MainActivity.this, countries[position], Toast.LENGTH_SHORT).show();
            }
        });
    }
}

package com.androidchunk.hellolistview

import android.os.Bundle
import android.widget.AdapterView.OnItemClickListener
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    //data
    private val countries = arrayOf(
        "Switzerland", "Canada", "India", "United States", "Germany",
        "Sweden", "Japan", "Australia", "United Kingdom", "New Zealand", "Sweden",
        "China", "France", "Brazil", "Russia", "Spain", "United Arab Emirates"
    )

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

        //Array adapter
        val arrayAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, countries)

        //instance of listview
        val aListView = findViewById<ListView>(R.id.myListView)

        //set the arrayAdapter to the listView
        aListView.adapter = arrayAdapter

        //ListView click listener
        aListView.onItemClickListener =
            OnItemClickListener { adapterView, view, position, id ->
                Toast.makeText(this@MainActivity, countries[position], Toast.LENGTH_SHORT).show()
            }
    }
}

The parameters of the ArrayAdapter constructor that we used to create an instance of ArrayAdapter are explained below.

Android-ListView-ArrayAdapter-constructor-parameter.png

Run the application and check the output.

Step 6.1.4: Output

6.2 Simple Android ListView Example using BaseAdapter

In this example we will create a simple Android ListView using BaseAdapter. We will display the list of countries with their name, flag, currency etc. Let’s start.

Step 6.2.1: Create New Project

Create a new project in Android Studio from File ⇒ New Project and select Empty Activity from the templates.

Step 6.2.2: Add List Item Layout

A List Item is a unit of the ListView, So first we will create a XML layout file for the list item. See how we designed it. You can create your own too!

Android-ListView-ListItem-layout.png

We have taken three TextViews Country name, currency, calling code respectively . We also want an ImageView to display the flag. Check the code below.

XML
content_copy light_mode remove
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="8dp">

    <ImageView
        android:id="@+id/flagImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:src="@mipmap/ic_launcher" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="vertical"
        android:paddingStart="10dp">

        <TextView
            android:id="@+id/nameTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="name"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/currencyTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="currency" />

        <TextView
            android:id="@+id/callingCodeTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="calling code" />
    </LinearLayout>
</LinearLayout>

Step 6.2.3: Copy Image Resources (optional)

Now download the following images and add them to the drawable folder of the project.

Add-flags-to-drawable-folder.png

Step 6.2.4: Add ListView to the XML Layout (UI)

Open the Activity’s xml layout file and add a ListView from the palette.

XML
content_copy light_mode remove
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:alpha="0.3"
        android:text="Hello Androidchunk!" />

    <ListView
        android:id="@+id/myListView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:listitem="@layout/list_item_layout" />

</RelativeLayout>

Step 6.2.5: Create a Model Class

To display data in the ListView we have created a simple model class that helps in setting and getting country data. Model class make it easy to manage data. Let’s create one.

Open the project tool window by clicking on the project option from the Tool window bar. After that select the Android option from the drop-down and open the app → java hierarchy.

Right click on the package name and select New → Kotlin or Java class.

KotlinJava
content_copy light_mode remove
package com.androidchunk.hellolistview

data class Country(val name: String, val flag: Int, val currency: String, val callingCode: String)
package com.androidchunk.hellolistview;

class Country {
   private String name;
   private int flag;
   private String currency;
   private String callingCode;

   public Country(String name, int flag, String currency, String callingCode) {
      this.name = name;
      this.flag = flag;
      this.currency = currency;
      this.callingCode = callingCode;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public int getFlag() {
      return flag;
   }
   public void setFlag(int flag) {
      this.flag = flag;
   }
   public String getCurrency() {
      return currency;
   }
   public void setCurrency(String currency) {
      this.currency = currency;
   }
   public String getCallingCode() {
      return callingCode;
   }
   public void setCallingCode(String callingCode) {
      this.callingCode = callingCode;
   }
}

Step 6.2.6: Create a Custom Adapter Class

We learned above that the Android Adapter is the bridge between the views (e.g. ListView, GridView) and data. Let’s create one.

Right click on the package name and select New → Kotlin or Java class.
Add the following code.

KotlinJava
content_copy light_mode remove
package com.androidchunk.hellolistview

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView

class MyBaseAdapter(val context: Context, val data: ArrayList<Country>?) : BaseAdapter() {

    override fun getCount(): Int {
        return data?.size ?: 0
    }

    override fun getItem(position: Int): Any? {
        if (data != null)
            return data[position]
        else
            return null
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View? {
        var view = convertView
        val holder: MyViewHolder
        if (view == null) {
            view = LayoutInflater.from(context).inflate(R.layout.list_item_layout, null, false)

            holder = MyViewHolder()

            holder.flagIV = view.findViewById(R.id.flagImageView)
            holder.nameTV = view.findViewById(R.id.nameTextView)
            holder.currencyTV = view.findViewById(R.id.currencyTextView)
            holder.callingCodeTV = view.findViewById(R.id.callingCodeTextView)

            view.tag = holder
        } else {
            holder = view.tag as MyViewHolder
        }
        holder.flagIV!!.setImageResource(data!![position].flag)

        holder.nameTV!!.text = data[position].name

        val currencyStr = "Currency: " + data[position].currency
        holder.currencyTV!!.text = currencyStr

        val callingCodeStr = "Calling code: " + data[position].callingCode
        holder.callingCodeTV!!.text = callingCodeStr

        return view
    }

    private class MyViewHolder {
        var flagIV: ImageView? = null
        var nameTV: TextView? = null
        var currencyTV: TextView? = null
        var callingCodeTV: TextView? = null
    }
}
package com.androidchunk.hellolistview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

class MyBaseAdapter extends BaseAdapter {
    private final Context context;
    private final ArrayList<Country> data;

    public MyBaseAdapter(Context context, ArrayList<Country> countryData) {
        this.context = context;
        this.data = countryData;
    }

    @Override
    public int getCount() {
        if (data != null) {
            return data.size();
        }
        return 0;
    }

    @Override
    public Object getItem(int position) {
        if (data != null) {
            return data.get(position);
        }
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        MyViewHolder holder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.list_item_layout, null, false);

            holder = new MyViewHolder();

            holder.flagIV = convertView.findViewById(R.id.flagImageView);
            holder.nameTV = convertView.findViewById(R.id.nameTextView);
            holder.currencyTV = convertView.findViewById(R.id.currencyTextView);
            holder.callingCodeTV = convertView.findViewById(R.id.callingCodeTextView);

            convertView.setTag(holder);
        } else {
            holder = (MyViewHolder) convertView.getTag();
        }

        holder.flagIV.setImageResource(data.get(position).getFlag());

        holder.nameTV.setText(data.get(position).getName());

        String currencyStr = "Currency: " + data.get(position).getCurrency();
        holder.currencyTV.setText(currencyStr);

        String callingCodeStr = "Calling code: " + data.get(position).getCallingCode();
        holder.callingCodeTV.setText(callingCodeStr);

        return convertView;
    }

    private static class MyViewHolder {
        ImageView flagIV;
        TextView nameTV;
        TextView currencyTV;
        TextView callingCodeTV;
    }
}

Step 6.2.7: Update Activity File

Open the Activity Kotlin/Java file and modify it as follows.

KotlinJava
content_copy light_mode remove
package com.androidchunk.hellolistview

import android.os.Bundle
import android.widget.AdapterView.OnItemClickListener
import android.widget.ListView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

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

        //create a list
        val countryData = ArrayList<Country>()
        //add data to the list
        countryData.add(Country("Australia", R.drawable.au, "Australian Dollar", "+61"))
        countryData.add(Country("Germany", R.drawable.de, "Euro", "+49"))
        countryData.add(Country("India", R.drawable.`in`, "Indian Rupee", "+91"))
        countryData.add(Country("United States", R.drawable.us, "United States Dollar", "+1"))
        countryData.add(Country("New Zealand", R.drawable.nz, "New Zealand Dollar", "+64"))
        countryData.add(Country("Russia", R.drawable.ru, "Russian Ruble", "+7"))

        //instance of custom adapter
        val arrayAdapter = MyBaseAdapter(this, countryData)

        //instance of listview
        val aListView = findViewById<ListView>(R.id.myListView)

        //set the adapter to the listView
        aListView.adapter = arrayAdapter

        //ListView click listener
        aListView.onItemClickListener =
            OnItemClickListener { adapterView, view, position, id ->
                val obj = aListView.getItemAtPosition(position)
                if (obj != null) {
                    val (name) = obj as Country
                    Toast.makeText(this@MainActivity, name, Toast.LENGTH_SHORT).show()
                }
            }
    }
}
package com.androidchunk.hellolistview;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //create a list
        ArrayList<Country> countryData = new ArrayList<>();
        //add data to the list
        countryData.add(new Country("Australia", R.drawable.au, "Australian Dollar", "+61"));
        countryData.add(new Country("Germany", R.drawable.de, "Euro", "+49"));
        countryData.add(new Country("India", R.drawable.in, "Indian Rupee", "+91"));
        countryData.add(new Country("United States", R.drawable.us, "United States Dollar", "+1"));
        countryData.add(new Country("New Zealand", R.drawable.nz, "New Zealand Dollar", "+64"));
        countryData.add(new Country("Russia", R.drawable.ru, "Russian Ruble", "+7"));

        //instance of custom adapter
        MyBaseAdapter arrayAdapter = new MyBaseAdapter(this, countryData);

        //instance of listview
        ListView aListView = findViewById(R.id.myListView);

        //set the adapter to the listView
        aListView.setAdapter(arrayAdapter);

        //ListView click listener
        aListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                Object obj = aListView.getItemAtPosition(position);
                if (obj != null) {
                    Country country = (Country) obj;
                    Toast.makeText(MainActivity.this, country.getName(), Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

Run the application and check the output.

Step 6.2.8: Output

7. Exercises Box

7.1 Exercise-1

In the above example (Simple Android ListView Example Using BaseAdapter) update the adapter code with the following code, run the application and check the output.

KotlinJava
content_copy light_mode remove
class MyBaseAdapter(val context: Context, val data: ArrayList<Country>?) : BaseAdapter() {

    ...
    ...
    ...

    override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View? {
        var view = convertView
        val holder: MyViewHolder
        if (view == null) {
            view = LayoutInflater.from(context).inflate(R.layout.list_item_layout, null, false)

            holder = MyViewHolder()

            holder.flagIV = view.findViewById(R.id.flagImageView)
            holder.nameTV = view.findViewById(R.id.nameTextView)
            holder.currencyTV = view.findViewById(R.id.currencyTextView)
            holder.callingCodeTV = view.findViewById(R.id.callingCodeTextView)

            view.tag = holder
        } else {
            holder = view.tag as MyViewHolder
        }
        holder.flagIV!!.setImageResource(data!![position].flag)

        holder.nameTV!!.text = data[position].name

        val str = SpannableStringBuilder("Currency: " + data[position].currency)
        str.setSpan(StyleSpan(Typeface.BOLD),0, "Currency: ".length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        //String currencyStr = "Currency: " + data.get(position).getCurrency();
        holder.currencyTV!!.text = str

        val callingCodeStr = SpannableStringBuilder("Calling code: " + data[position].callingCode)
        callingCodeStr.setSpan(StyleSpan(Typeface.BOLD),0, "Calling code: ".length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        //String callingCodeStr = "Calling code: " + data.get(position).getCallingCode();
        holder.callingCodeTV!!.text = callingCodeStr

        return view
    }

    private class MyViewHolder {
        var flagIV: ImageView? = null
        var nameTV: TextView? = null
        var currencyTV: TextView? = null
        var callingCodeTV: TextView? = null
    }
}
class MyBaseAdapter extends BaseAdapter {
    ...
    ...
    ...

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        MyViewHolder holder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.list_item_layout, null, false);

            holder = new MyViewHolder();

            holder.flagIV = convertView.findViewById(R.id.flagImageView);
            holder.nameTV = convertView.findViewById(R.id.nameTextView);
            holder.currencyTV = convertView.findViewById(R.id.currencyTextView);
            holder.callingCodeTV = convertView.findViewById(R.id.callingCodeTextView);

            convertView.setTag(holder);
        } else {
            holder = (MyViewHolder) convertView.getTag();
        }

        holder.flagIV.setImageResource(data.get(position).getFlag());

        holder.nameTV.setText(data.get(position).getName());

        SpannableStringBuilder currencyStr = new SpannableStringBuilder("Currency: " + data.get(position).getCurrency());
        currencyStr.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), 0, "Currency: ".length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        //String currencyStr = "Currency: " + data.get(position).getCurrency();
        holder.currencyTV.setText(currencyStr);

        SpannableStringBuilder callingCodeStr = new SpannableStringBuilder("Calling code: " + data.get(position).getCallingCode());
        callingCodeStr.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), 0, "Calling code: ".length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        //String callingCodeStr = "Calling code: " + data.get(position).getCallingCode();
        holder.callingCodeTV.setText(callingCodeStr);

        return convertView;
    }

    private static class MyViewHolder {
        ImageView flagIV;
        TextView nameTV;
        TextView currencyTV;
        TextView callingCodeTV;
    }
}

Finally we learned something about Android ListView. Hope it will be useful for you when you need to use it in your app.

Happy coding!

Leave a Reply