Reputation: 33
I'm new to Kotlin and Android development in general. I have created a custom adapter that extends BaseAdapter and it works as I want it to, but as soon as I was to add a click listener to the view that gets returned in the getView, it doesn't seem to work as expected.
I have looked everywhere for an answer. I have seen people talking about clickable, duplicateParentState, focusable,... But nothing seems to work
The click listener does react if I click on the left/right border of my layout RelativeLayout, but I want the entire RelativeLayout to react when I click.
Am I missing something in my XML? Or is there some kind of "hack" that works. I'm a little confused as to why my click listener is not working as expected
My TokenAdapter (extends BaseAdapter)
class TokenAdapter(private val ctx: Context) : BaseAdapter() {
private val tokenPersistence: TokenPersistence = TokenPersistence(ctx)
private val clipboardManager: ClipboardManager =
ctx.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
var seconds: Int
var percentage: Int = 100
var shouldGenerateToken: Boolean = true
init {
seconds = getSecondsUntilRefresh()
}
fun getSecondsUntilRefresh() : Int{
val secondsElapsedInMinute = LocalDateTime.now().second
return if(secondsElapsedInMinute < 30) 30 - secondsElapsedInMinute else 60 - secondsElapsedInMinute
}
override fun getCount(): Int {
return tokenPersistence.length()
}
override fun getItem(position: Int): Token? {
return tokenPersistence.get(position)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val v: View = if (convertView == null) {
val inflater: LayoutInflater =
ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
inflater.inflate(R.layout.list_item, parent, false)
} else {
convertView
}
val t: Token = getItem(position)!!
val title: TextView = v.findViewById(R.id.list_item_title)
val code: TextView = v.findViewById(R.id.list_item_subtitle)
title.text = t.getLabel()
if (shouldGenerateToken) {
var generatedCode : String = t.generateCode()
generatedCode = generatedCode.substring(0, 3) + " " + generatedCode.substring(3, generatedCode.length)
code.text = generatedCode
shouldGenerateToken = false
}
val countdown: ProgressBar = v.findViewById(R.id.progress_circular)
val countdownText: TextView = v.findViewById(R.id.progress_circular_text)
countdownText.text = seconds.toString()
countdown.progress = percentage
v.setOnClickListener {
val copyText = code.text.split(' ').joinToString("")
println("===================")
println("Copied: $copyText")
val clip: ClipData = ClipData.newPlainText("2FA Code", copyText)
clipboardManager.setPrimaryClip(clip)
Toast.makeText(ctx, "Copied: $copyText to clipboard", Toast.LENGTH_LONG).show()
}
return v
}
}
The list_item XML layout
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list_item_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/list_item_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:paddingHorizontal="8dp"
android:paddingTop="16dp"
android:paddingBottom="0dp"
android:clickable="false"
/>
<TextView
android:id="@+id/list_item_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="@id/list_item_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_toStartOf="@id/progress_circular_container"
android:layout_toLeftOf="@id/progress_circular_container"
android:paddingHorizontal="8dp"
android:paddingTop="0dp"
android:text="123456"
android:textColor="@color/primary"
android:textSize="32sp"
android:textStyle="bold"
android:clickable="false"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/progress_circular_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_below="@id/list_item_title"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:clickable="false">
<ProgressBar
android:id="@+id/progress_circular"
android:layout_width="48sp"
android:layout_height="48sp"
android:indeterminateOnly="false"
android:progressDrawable="@drawable/pb_circular_determinative"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:progress="100"/>
<TextView
android:id="@+id/progress_circular_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
app:layout_constraintBottom_toBottomOf="@+id/progress_circular"
app:layout_constraintEnd_toEndOf="@+id/progress_circular"
app:layout_constraintStart_toStartOf="@+id/progress_circular"
app:layout_constraintTop_toTopOf="@+id/progress_circular"
tools:text="30" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
Upvotes: 0
Views: 277
Reputation: 33
So I managed to fix my problem.
I did 2 "major" things after which my problem was resolved:
I rewrote my list_item.xml making use of LinearLayout instead of RelativeLayout (although I doubt this did anything)
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/list_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:paddingHorizontal="8dp"
android:paddingTop="16dp"
android:paddingBottom="0dp"
/>
<TextView
android:id="@+id/list_item_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="8dp"
android:paddingTop="0dp"
android:textColor="@color/primary"
android:textSize="32sp"
android:textStyle="bold"
/>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ProgressBar
android:id="@+id/progress_circular"
android:layout_width="48sp"
android:layout_height="48sp"
android:indeterminateOnly="false"
android:progressDrawable="@drawable/pb_circular_determinative"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:progress="100"/>
<TextView
android:id="@+id/progress_circular_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
app:layout_constraintBottom_toBottomOf="@+id/progress_circular"
app:layout_constraintEnd_toEndOf="@+id/progress_circular"
app:layout_constraintStart_toStartOf="@+id/progress_circular"
app:layout_constraintTop_toTopOf="@+id/progress_circular"
tools:text="30" />
</androidx.constraintlayout.widget.ConstraintLayout>
I moved my ClickListener from my Adapter getView() to my MainActivity with an setOnItemClickListener on my ListView
val listview = findViewById<ListView>(R.id.tokenList)
listview.setOnItemClickListener { parent: AdapterView<*>, view: View, position: Int, id ->
val token = tokenAdapter.getItem(position)
if(token != null) {
val code = token.generateCode()
val clip: ClipData = ClipData.newPlainText("2FA Code", code)
clipboardManager.setPrimaryClip(clip)
Toast.makeText(this, "Copied: $code", Toast.LENGTH_LONG).show()
}
}
Using this method on my Listview I also didn't have to use clickable, or any of those kinds of properties on my XML layouts. If someone knows what exactly made it work, please tell me. Personally I think it is the Listener being an 'OnItemClick' and it being moved to the MainActivity, although don't take my word for it as it could just be something else random that I did.
Upvotes: 1