Ali Ghassan
Ali Ghassan

Reputation: 1180

how add search filter bar in listview kotlin

l have created a list view and the code working fine . also created a search box . I want to implement search functionality on the basis of particular fields of the list. l used list adapter in Separated class is not in main activity class . l want use search bar filter in class list adapter .

main activity class

package com.iraqairoirt.iraqairports

import android.app.AlertDialog
import android.os.AsyncTask
import android.support.design.widget.TabLayout
import android.support.v7.app.AppCompatActivity

import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter
import android.os.Bundle

import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_arrivel.*
import kotlinx.android.synthetic.main.fragment_dep.*
import org.json.JSONArray
import org.json.JSONObject
import java.net.HttpURLConnection
import java.net.URL

import android.widget.TextView
import com.iraqairoirt.iraqairports.flightsDep.ListAdapteDep
import com.iraqairoirt.iraqairports.flightsArr.ListAdapteArr


    class MainActivity : AppCompatActivity() {


        private var mSectionsPagerAdapter: SectionsPagerAdapter? = null

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




            val url = "xxxxxxxxxxxxxxxxxxxxxxx"
            Arr().execute(url)
            Dep().execute(url)


            setSupportActionBar(toolbar)
            // Create the adapter that will return a fragment for each of the three
            // primary sections of the activity.
            mSectionsPagerAdapter = SectionsPagerAdapter(supportFragmentManager)

            // Set up the ViewPager with the sections adapter.
            container.adapter = mSectionsPagerAdapter

            container.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
            tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container))


        }
        //    full class for json api
        inner class Arr : AsyncTask<String, String, String>(){

            val progressDialog = AlertDialog.Builder(this@MainActivity)
            val dialogView = layoutInflater.inflate(R.layout.progress_dialog,null)
            val message = dialogView.findViewById<TextView>(R.id.message_id)
            val dialog = progressDialog.create()

            override fun onPreExecute() {
                super.onPreExecute()

                dialog.setMessage("loading")
                dialog.setCancelable(false)
                dialog.show()


            }

            //        for build connection
            override fun doInBackground(vararg url: String?): String{

                var text : String
                val connection = URL(url[0]).openConnection() as HttpURLConnection

                try {
                    connection.connect()
                    text = connection.inputStream.use { it.reader().use{reader -> reader.readText()} }


                } finally{

                    connection.disconnect()

                }
                return text
            }

            override fun onPostExecute(result: String?) {

                super.onPostExecute(result)
                handleJson(result)

                dialog.dismiss();

            }

            override fun onProgressUpdate(vararg text: String?) {


            }
            private fun handleJson (jsonString: String?){

                val schedule = pluginData.getJSONObject("schedule")
                val arrivals = schedule.getJSONObject("arrivals")
    //        val data = arrivals.getJSONObject("data")
                val jsonArray = JSONArray(arrivals.get("data").toString())

                val list =  ArrayList<FlightShdu>()
                var x = 0
                while (x < jsonArray.length()){

                    val jsonObject = jsonArray.getJSONObject(x)



                    list.add(FlightShdu(
                        jsonObject.getJSONObject("flight").getJSONObject("identification").getJSONObject("number").getString("default"),
                        jsonObject.getJSONObject("flight").getJSONObject("airline").getString("short"),
                        jsonObject.getJSONObject("flight").getJSONObject("status").getJSONObject("generic").getJSONObject("status").getString("text"),
                        jsonObject.getJSONObject("flight").getJSONObject("airline").getJSONObject("code").getString("icao"),
                        jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("scheduled").getString("arrival"),
                        jsonObject.getJSONObject("flight").getJSONObject("airport").getJSONObject("origin").getJSONObject("code").getString("iata"),
                        jsonObject.getJSONObject("flight").getJSONObject("aircraft").getJSONObject("model").getString("text"),
    //                    for more information
                        jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("real").getString("departure"),
                        jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("estimated").getString("arrival"),
    //                    jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("estimated").getString("arrival"),
                        jsonObject.getJSONObject("flight").getJSONObject("aircraft").getString("registration"),
                        jsonObject.getJSONObject("flight").getJSONObject("status").getJSONObject("generic").getJSONObject("status").getString("diverted"),
                        arrivals.getString("timestamp"),
                        jsonObject.getJSONObject("flight").getJSONObject("status").getString("icon")





                        ))


                    x++
                }
                list.forEach(::println)

                val adapter = ListAdapteArr(this@MainActivity, list)
                flight_arrivel_list.adapter = adapter




            }




        }




        /**
         * A [FragmentPagerAdapter] that returns a fragment corresponding to
         * one of the sections/tabs/pages.
         */
        inner class SectionsPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {

            override fun getItem(position: Int): Fragment? {

                return when (position) {
                    0 -> {
                        fragment_Arr()
                    }
                    1 ->{

                        fragment_Dep()
                    }
                    2->{
                        fragment_Weather()
                    }
                    else-> {
                        return null
                    }
                }

            }

            override fun getCount(): Int {
                // Show 3 total pages.
                return 2
            }

        }


    }

List Adapter

   class ListAdapteArr (val context: MainActivity, val list: ArrayList<FlightShdu>): BaseAdapter() {
        @SuppressLint("ViewHolder", "NewApi")
        override fun getView(p0: Int, convertView: View?, parent: ViewGroup?): View {

            val view : View = LayoutInflater.from(context).inflate(R.layout.arr_list,parent,false)


            val searchBar = view.findViewById(R.id.searchFlightId) as MaterialSearchBar

            Airport.text= list.Airport




            return view

        }




        override fun getItem(p0: Int): Any {
            return list [p0]
        }

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

        override fun getCount(): Int {
            return list.size
        }



    }

xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/flight_arrivel_list"
            style="@style/Widget.AppCompat.ListView"
            android:paddingStart="10sp"
            android:paddingEnd="10sp"
            android:paddingTop="0dp" android:layout_alignParentStart="true" android:layout_alignParentTop="true"
            android:layout_marginTop="58dp" android:layout_marginStart="0dp"/>
    <com.mancj.materialsearchbar.MaterialSearchBar
            style="@style/MaterialSearchBarLight"
            app:mt_speechMode="true"
            app:mt_hint="Custom hint"
            app:mt_maxSuggestionsCount="10"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/searchBar" />


</RelativeLayout>

enter image description here

l added search bar filter to search on any item inside listview but the there still not funcation to do this

Upvotes: 0

Views: 3228

Answers (1)

Blue Jones
Blue Jones

Reputation: 385

In your activity perform your search on your list and reassign the value(keep a val baseList and var filteredList so you can default back to the original if need be. First of all we want to move the nested adapter to the top of the activity so we can access it after its instantiated. We also want to use two lists for this so aff the baseList and filteredList as i have below the private lateinit var adapter: ListAdapteArr? = null at the top of the activity.

private lateinit var adapter: ListAdapteArr? = null

private var baseList: List<FlightShdu> = listOf()
private var filteredList: MutableList<FlightShdu> = mutableListOf()

In your handleJson() method, once the list has been populated with all the FlightShdu objects, assign it to the baseList

baseList = list

Then assign your private lateinit var adapter:

 adapter = ListAdapteArr(this@MainActivity, baseList)
                flight_arrivel_list.adapter = adapter

Have a method that takes the edit text search term and compares it with your list

   fun searchList() {
       filteredList.clear()
       baseList.forEach { 
       if (it.contains(search.text.toString())) {
          filteredList.add(it)
       }
    }
    adapter.updateList(filteredList)

Then within your adapter change:

val list: ArrayList<FlightShdu> to var list: ArrayList<FlightShdu>

and have a method like:

 fun updateList(filteredList: List<FlightShdu>) {
    list.clear()
    list.addAll(filteredList)
    notifyDataSetChanged()
 }

With the updated list in activity, call the method with adapter.updateList(filteredList)

I would also recommend using a recyclerview instead of a listview RecyclerView vs. ListView

You could also look into using DiffUtils as it offers nice smooth animations when transitioning between lists in the adapter. This answer was just to get the ball rolling for you.

val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {

                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean = newList[newItemPosition] == oldList[oldItemPosition]

                override fun getOldListSize(): Int = oldList.size

                override fun getNewListSize(): Int = newList.size

                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean = newList[newItemPosition] == oldList[oldItemPosition]
            }

diffResult.dispatchUpdatesTo(adapter)

Upvotes: 1

Related Questions