I have a simple Kotlin class WarningFragment in which I set an adapter for ExpandableListView and pass list headers and details of every list header inside. For the record, here's the code of the class:
class WarningFragment : Fragment() {
private var _binding: FragmentWarningBinding? = null
private val binding get() = _binding!!
private val header: List<String> = WarningData.warningData.keys.toList()
private val body: List<List<String>> = WarningData.warningData.values.toList()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentWarningBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val warningHeader : TextView = binding.warningTextView
warningHeader.text = WarningData.warningHeader
val expandableListViewWarning : ExpandableListView = binding.expandableListViewWarning
expandableListViewWarning.setAdapter(WarningExpandableListAdapter(requireActivity().applicationContext, expandableListViewWarning, header, body))
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
The code of list adapter class:
class WarningExpandableListAdapter(var context: Context,
var expandableListView: ExpandableListView,
var header: List<String>,
var body: List<List<String>>) : BaseExpandableListAdapter() {
override fun getGroupCount(): Int {
return header.size
}
override fun getChildrenCount(groupPosition: Int): Int {
return body[groupPosition].size
}
override fun getGroup(groupPosition: Int): String {
return header[groupPosition]
}
override fun getChild(groupPosition: Int, childPosition: Int): String {
return body[groupPosition][childPosition]
}
override fun getGroupId(groupPosition: Int): Long {
return groupPosition.toLong()
}
override fun getChildId(groupPosition: Int, childPosition: Int): Long {
return childPosition.toLong()
}
override fun hasStableIds(): Boolean {
return false
}
override fun getGroupView(
groupPosition: Int,
isExpanded: Boolean,
convertView: View?,
parent: ViewGroup?
): View? {
var convertView = convertView
if (convertView == null) {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
convertView = inflater.inflate(R.layout.warning_list_row_group, null)
}
val title = convertView?.findViewById<TextView>(R.id.text_view_warning_list_row_group)
title?.text = getGroup(groupPosition)
//title?.textColors = R.attr.colorOnSurface
//title?.text = getGroup(groupPosition)
title?.setOnClickListener {
if (expandableListView.isGroupExpanded(groupPosition))
expandableListView.collapseGroup(groupPosition)
else
expandableListView.expandGroup(groupPosition)
//Toast.makeText(context, getGroup(groupPosition), Toast.LENGTH_SHORT).show()
}
return convertView
}
override fun getChildView(
groupPosition: Int,
childPosition: Int,
isLastChild: Boolean,
convertView: View?,
parent: ViewGroup?
): View? {
var convertView = convertView
if (convertView == null) {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
convertView = inflater.inflate(R.layout.warning_list_row_child, null)
}
val title = convertView?.findViewById<TextView>(R.id.text_view_warning_list_row_child)
title?.text = getChild(groupPosition, childPosition)
//title?.setTextColor(R.attr.colorOnSurface)
title?.setOnClickListener {
//Toast.makeText(context, getChild(groupPosition, childPosition), Toast.LENGTH_SHORT).show()
}
return convertView
}
override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean {
return true
}
}
Everything worked fine until I've tried to change the color of the TextView in the XML file representing the list header item (group) or details item (child) with this line:
android:textColor="?attr/colorOnSurface"
Here's the XML code example of the list header item:
<LinearLayout
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="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<TextView
android:id="@+id/text_view_warning_list_row_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:fontFamily="sans-serif-condensed-medium"
android:textColor="?attr/colorOnSurface"
tools:text="ZMIANY W SAMOPOCZUCIU FIZYCZNYM" />
</LinearLayout>
Now, when I launch my app and go to my Warning Fragment the app crashes and throws the android.view.InflateException with "Error inflating class android.widget.TextView" info. The exception stack shows this line (in WarningExpandableListAdapter class) causes the exception:
convertView = inflater.inflate(R.layout.warning_list_row_group, null)
Respectively, if I set the same textColor attribute in XML file representing child, then the bugged line:
convertView = inflater.inflate(R.layout.warning_list_row_child, null)
I've tried to hardcode the textColor attribute to @color/black. In this case the app works well but this text color remains black after swithing to dark mode (I want the color to change in case of changing app theme, that's why i use ?attr/...) I've also tried to set the text color programmatically but I don't know why the TextView color sets to purple, not black or white.
Is there any way to get rid of that problem or changing the text color depending on dark or light mode?
Thank you in advance for any help.