I made an extension of ArrayAdapter
which preservers as much of its functionality as possible, just sets the long description to the selected item.
First, we need a new model for feeding the adapter. Note that toString()
returns the shortDescription
so that the ArrayAdapter
will show short description in the dropdown:
data class DescriptiveArrayItem(val shortDescription: String, val longDescription: String) {
override fun toString(): String {
return shortDescription
}
}
Second, we create our custom adapter which overrides getView()
and shows the long description when the item is selected (unfortunately, a lot of fields and methods in ArrayAdapter
are private so I had to copy them):
class DescriptiveArrayAdapter : ArrayAdapter<DescriptiveArrayItem> {
private var mResource: Int
private val mFieldId: Int
private val mContext: Context
private val mInflater: LayoutInflater
constructor(context: Context, resource: Int) : super(context, resource) {
mContext = context
mFieldId = 0
mInflater = LayoutInflater.from(context)
mResource = resource
}
constructor(context: Context, resource: Int, textViewResourceId: Int) : super(context, resource, textViewResourceId) {
mContext = context
mFieldId = textViewResourceId
mInflater = LayoutInflater.from(context)
mResource = resource
}
constructor(context: Context, resource: Int, objects: Array<out DescriptiveArrayItem>) : super(context, resource, objects) {
mContext = context
mFieldId = 0
mInflater = LayoutInflater.from(context)
mResource = resource
}
constructor(context: Context, resource: Int, textViewResourceId: Int, objects: Array<out DescriptiveArrayItem>) : super(context, resource, textViewResourceId, objects) {
mContext = context
mFieldId = textViewResourceId
mInflater = LayoutInflater.from(context)
mResource = resource
}
constructor(context: Context, resource: Int, objects: List<DescriptiveArrayItem>) : super(context, resource, objects) {
mContext = context
mFieldId = 0
mInflater = LayoutInflater.from(context)
mResource = resource
}
constructor(context: Context, resource: Int, textViewResourceId: Int, objects: List<DescriptiveArrayItem>) : super(context, resource, textViewResourceId, objects) {
mContext = context
mFieldId = textViewResourceId
mInflater = LayoutInflater.from(context)
mResource = resource
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
return createViewFromResource(mInflater, position, convertView, parent, mResource)
}
private fun createViewFromResource(inflater: LayoutInflater, position: Int,
convertView: View?, parent: ViewGroup, resource: Int): View {
val text: TextView?
val view: View = convertView ?: inflater.inflate(resource, parent, false)
try {
if (mFieldId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = view as TextView
} else {
// Otherwise, find the TextView field within the layout
text = view.findViewById(mFieldId)
if (text == null) {
throw RuntimeException("Failed to find view with ID "
+ mContext.resources.getResourceName(mFieldId)
+ " in item layout")
}
}
} catch (e: ClassCastException) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView")
throw IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e)
}
val item: DescriptiveArrayItem? = getItem(position)
text.text = item?.longDescription
return view
}
}