How to drag and drop ListView rows in Android Studio using Kotlin

535 views Asked by At

I’m using Android Studio with Kotlin. I’d like to be able to drag and drop items in a ListView to reorder them. I also want to swipe left to delete. This was pretty straightforward in XCode/Swift for iOS, but I’m having trouble finding examples for Android/Kotlin. I’ve seen some fairly old discussions with Java and with RecyclerView, but it would be great to be able to do it in Kotlin with ListView. I should add that the ListView does everything I need so far – I realise there is much discussion about ListView vs RecyclerView.

I’m not asking for people to solve this for me, but it would be great if you could point me to anything that might get me going.

By way of background, here is my code. It is just a ListView with numbers ‘zero’ to ‘ten’ and the selected row highlighted. I should add that I wrote this code with the help of many discussions here and on YouTube, for which I’m very grateful.

I also have a ListView with sections that needs these options, but I’ve not put the code here for that (happy to do so if required).

activity_main.xml

<?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="match_parent"
    tools:context=".MainActivity">
<ListView
    android:id="@+id/list_view"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    android:layout_margin="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

listview_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/rowText"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:textColor="@color/black"
        android:paddingLeft="0dp"
        android:paddingTop="8dp"
        android:paddingRight="0dp"
        android:paddingBottom="8dp"
        android:autoSizeTextType="uniform"
        android:autoSizeMaxTextSize="40sp"
        android:autoSizeMinTextSize="8sp"
        android:autoSizeStepGranularity="2sp"
        android:lines="1" />
</LinearLayout>

listview_selected_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/selectedRowText"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:paddingLeft="0dp"
        android:paddingRight="0dp"
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        android:background="@color/teal_200"
        android:textColor="@color/black"
        android:autoSizeTextType="uniform"
        android:autoSizeMaxTextSize="40sp"
        android:autoSizeMinTextSize="8sp"
        android:autoSizeStepGranularity="2sp"
        android:lines="1" />
</LinearLayout>

ListViewAdapter.kt

package com.ijmusic.listviewrearrange

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

val TYPE_LISTVIEW_ITEM = 0
val TYPE_LISTVIEW_SELECTED_ITEM = 1

class ListViewAdapter(private val context: Context): BaseAdapter() {

    private val mData: ArrayList<String> = ArrayList()
    private var mIndex: ArrayList<Int> = ArrayList()
    private var mSelectedItem = -1

    private lateinit var textView: TextView

    fun addItem(item: String, index: Int) {
        mData.add(item)
        mIndex.add(index)
        notifyDataSetChanged()
    }

    fun addSelectedItem(item: String, index: Int) {
        mData.add(item)
        mIndex.add(index)
        mSelectedItem = mData.size - 1
        notifyDataSetChanged()
    }

    fun highlightSelection(int: Int) {
        mSelectedItem = int
        notifyDataSetChanged()
    }

    override fun getItemViewType(position: Int): Int {
        return if (position == mSelectedItem) TYPE_LISTVIEW_SELECTED_ITEM
        else TYPE_LISTVIEW_ITEM
    }

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

    override fun getItem(position: Int): Any {
        return mData[position]
    }

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

    override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
        var view = view
        var type = getItemViewType(position)
        if (position == mSelectedItem) type = TYPE_LISTVIEW_SELECTED_ITEM
        when (type) {
            TYPE_LISTVIEW_ITEM -> {
                view = LayoutInflater.from(context).inflate(R.layout.listview_row, parent, false)
                textView = view.findViewById(R.id.rowText)
            }
            TYPE_LISTVIEW_SELECTED_ITEM -> {
                view = LayoutInflater.from(context).inflate(R.layout.listview_selected_row, parent, false)
                textView = view.findViewById(R.id.selectedRowText)
            }
        }
        textView.text = mData[position]
        return view
    }
}

MainActivity.kt

package com.ijmusic.listviewrearrange

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import com.ijmusic.listviewrearrange.databinding.ActivityMainBinding

val list = listOf("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var mAdapter: ListViewAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        mAdapter = ListViewAdapter(this)
        setListView()
        binding.listView.onItemClickListener = object: AdapterView.OnItemClickListener {
            override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                binding.listView.setSelection(position)
                mAdapter.highlightSelection(position)
            }
        }
    }

    fun setListView() {
        for ( i in 0 until list.count() ) {
            if ( i == 0 )
                mAdapter.addSelectedItem(list[i], i)
            else
                mAdapter!!.addItem(list[i], i)
        }
        binding.listView.adapter = mAdapter
    }
}
1

There are 1 answers

4
Nandala Abhinav On

You can look into a concept called gestures in android Kotlin. It will help.