RecyclerView not reading property to assign values - android

I'm trying to get my RecyclerView adapter to obtain values from an Array in my fragment but for some reason is doesn't work and I get this error (I think I have gotten lost somewhere):
lateinit property dataTitles has not been initialized
What's the correct way to obtain the data in this scenario?
Fragment class
class MyFragment : androidx.fragment.app.Fragment() {
private lateinit var mRecyclerView: RecyclerView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_rv, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
val v = view
val dataTitles: ArrayList<String> = ArrayList()
val dataSubtitles: ArrayList<String> = ArrayList()
mRecyclerView = v!!.findViewById<RecyclerView>(R.id.my_recyclerview)
// Set the linear layout manager
mRecyclerView.layoutManager = LinearLayoutManager(activity)
// create the adapter
val mAdapter = MyRVAdapter()
// init data
dataTitles.add(getString(R.string.addition))
dataTitles.add(getString(R.string.subtraction))
dataTitles.add(getString(R.string.multiplication))
dataTitles.add(getString(R.string.division))
dataSubtitles.add(getString(R.string.addition_information))
dataSubtitles.add(getString(R.string.subtraction_information))
dataSubtitles.add(getString(R.string.multiplication_information))
dataSubtitles.add(getString(R.string.division_information))
// Set the adapter
mRecyclerView.adapter = mAdapter
super.onActivityCreated(savedInstanceState)
}
}
Adapter class
class MyRVAdapter(private val dataTitles: Array<String>, private val dataSubtitles: Array<String>): RecyclerView.Adapter<MyRVAdapter.MyViewHolder>() {
private val typeItem = 1
private val typeHeader = 2
private val typeGrid = 3
private val primeNumbers = arrayOf("2", "3", "5", "7", "11", "13",
"17", "19", "23")
private lateinit var adapterGV: MyAdapter
override fun onCreateViewHolder(parent: ViewGroup, type: Int): MyRVAdapter.MyViewHolder {
return when (type) {
typeHeader -> MyRVAdapter.MyViewHolder(inflateHelper(R.layout.rv_header, parent))
typeItem -> MyRVAdapter.MyViewHolder(inflateHelper(R.layout.rv_item, parent))
typeGrid -> MyRVAdapter.MyViewHolder(inflateHelper(R.layout.rv_gv, parent))
else -> MyRVAdapter.MyViewHolder(inflateHelper(R.layout.rv_item, parent))
}
}
override fun onBindViewHolder(viewHolder: MyRVAdapter.MyViewHolder, position: Int) {
val llGV = viewHolder.itemView.findViewById<LinearLayout>(R.id.ll_gv)
val llTV = viewHolder.itemView.findViewById<LinearLayout>(R.id.ll_tv)
val mGridView = viewHolder.itemView.findViewById<GridView>(R.id.my_gv)
when (getItemViewType(position)) {
typeHeader -> {
val tValueE = TypedValue()
// test
llTV.context.theme.resolveAttribute(R.attr.imgUnfoldMore, tValueE, true)
val tValueC = TypedValue()
// test
llTV.context.theme.resolveAttribute(R.attr.imgUnfoldLess, tValueC, true)
}
typeGrid -> {
val titleG = viewHolder.itemView.findViewById<TextView>(R.id.tv_gv_A)
titleG.setText(R.string.prime_numbers)
//
val cardViewGV = viewHolder.itemView.findViewById<CardView>(R.id.cv_gv)
val mLinearLayoutGV = viewHolder.itemView.findViewById<LinearLayout>(R.id.cardview_gv_titlerow
mGridViewA.isEnabled = false
mGridViewA.isVerticalScrollBarEnabled = false
// adapterGV = MyAdapter(activity!!.applicationContext, 0)
mGridViewA.adapter = adapterGV
for (ldnBusesRoute in ldnBusesRoutes) {
adapterGV.addAdapterItem(AdapterItem(ldnBusesRoute))
}
typeItem -> {
// get the current item
val itemA = dataTitles[position - 2]
val itemB = dataSubtitles[position - 2]
//
val txtTitle = viewHolder.itemView.findViewById<TextView>(R.id.tv_title)
txtTitle.text = itemA
val txtSubtitle = viewHolder.itemView.findViewById<TextView>(R.id.tv_subtitle)
txtSubtitle.text = itemB
}
}
}
private fun inflateHelper(resId: Int, parent: ViewGroup): View {
return LayoutInflater.from(parent.context).inflate(resId, parent, false)
}
// inner class for view holder to use,
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
// Adapter for GridView
private inner class MyAdapter internal constructor(context: Context, textviewid: Int) : ArrayAdapter<AdapterItem>(context, textviewid) {
private val items = ArrayList<AdapterItem>()
internal fun addAdapterItem(item: AdapterItem) {
items.add(item)
}
override fun getCount(): Int {
return items.size
}
override fun getItem(position: Int): AdapterItem? {
return items[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val rowView: View = when (convertView) {
null -> LayoutInflater.from(parent.context).inflate(R.layout.gridview_item, parent, false)
// activity!!.layoutInflater.inflate(R.layout.gridview_item, parent, false)
else -> convertView
}
val tv = rowView.findViewById(R.id.item_gridview) as TextView
tv.text = items[position].first
return rowView
}
}
internal inner class AdapterItem // add more items
(var first: String)
override fun getItemCount(): Int {
return dataTitles.size + 2
}
override fun getItemViewType(position: Int): Int {
return when (position) {
0 -> typeHeader
1 -> typeGrid
else -> typeItem
}
}
}

Well, the error is pretty straightforward: you're not initializing dataTitles. When you label a variable with lateinit, Kotlin expects you to initialize it later. It's a way to avoid having to declare the variable as nullable.
To initialize it, you can do something like:
private val mutableList = mutableListOf<String>()
And you're doing the same with dataSubtitles.

Related

RecyclerView Adapter with ViewDataBinding

I am creating a GenericAdapter for handling single row|item layouts. Everything working fine only view-binding is not updating data..
I want to get RecyclerView.ViewHolder binding in callback ,I know I can bind it in adapter using BR.item and executePending
I want viewDataBinding context in a Callback
holder.binding.name.text = mutableList[pos]
Above line in TestActivity not working properly
GenericAdapter.kt
class GenericAdapter<T,VB:ViewDataBinding>(
var items:MutableList<T>,
#LayoutRes val resLayoutID:Int,
val onBind:(holder:GenericViewHolder<T,VB>,pos:Int) -> Unit
): RecyclerView.Adapter<GenericViewHolder<T,VB>>() {
lateinit var mItemBinding:VB
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GenericViewHolder<T,VB> {
val layoutInflater = LayoutInflater.from(parent.context)
mItemBinding = DataBindingUtil.inflate(layoutInflater, resLayoutID, parent, false)
return GenericViewHolder(mItemBinding)
}
override fun onBindViewHolder(holder: GenericViewHolder<T,VB>, position: Int) {
onBind(holder,position)
}
override fun getItemCount(): Int = items.size
}
GenericViewHolder.kt
class GenericViewHolder<T,VB: ViewDataBinding>(val binding: VB)
:RecyclerView.ViewHolder(binding.root){
val mItemBinding:VB = binding
}
TestActivity.kt
class TestActivity:AppCompatActivity() {
lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
populateList()
}
private fun populateList(){
val mutableList = mutableListOf<String>("apple","mango","tutti fruti","apricot",
"apple","mango","tutti fruti","apricot",
"apple","mango","tutti fruti","apricot",
"apple","mango","tutti fruti","apricot")
val mAdapter = GenericAdapter<String,ItemCountryBinding>(mutableList,R.layout.item_country){ holder,pos ->
//val nameTv = holder.itemView.findViewById<TextView>(R.id.name)
//nameTv.text = mutableList[pos]
holder.binding.name.text = mutableList[pos]
}
recyclerView.adapter = mAdapter
}
}
Where as below code working fine
val nameTv = holder.itemView.findViewById<TextView>(R.id.name)
nameTv.text = mutableList[pos]
I would recommend do onBind inside view holder.
I don't see reason why you need this callback.
You already passed mutableList to the adapter.
For example here is my ViewHolder
class NewsViewHolder(private val binding: ListItemNewsBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(news: RedditPost, itemClick: (RedditPost, View) -> Unit) {
with(binding) {
root.transitionName = news.thumbnail
root.setOnClickListener { itemClick.invoke(news, binding.root) }
title.text = news.title
image.setImageUrl(news.thumbnail)
author.text = news.author
xHoursAgo.text = news.created_utc
numComments.text = news.numComments
}
}
}
And
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (isLoadingMore && position == (itemCount - 1)) return
(holder as? NewsViewHolder)?.bind(news[position], itemClick)
}

android kotlin property does not change with passed method to adapter

i have defined a val in my fragment like so
private var selectionMode: Boolean = false
and a property to change it
fun enableSelectionMode() {
selectionMode = true
}
and i passed both to Adapter and want to call enableSelectionMode after clicking on each recycler item but nothing happen
here is my fragment:
class PostsFragment : Fragment() {
private val model: PostsViewModel by activityViewModels()
private var selectionMode: Boolean = false
fun enableSelectionMode() {
selectionMode = true
}
private lateinit var recyclerView: RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_posts, container, false)
recyclerView = view.findViewById(R.id.posts_recycler)
recyclerView.layoutManager = LinearLayoutManager(view.context)
model.posts.observe(viewLifecycleOwner, { items ->
recyclerView.adapter = PostsAdapter(items, model, selectionMode,
::enableSelectionMode)
})
return view
}
}
and my adapter
class PostsAdapter(
private val posts: List<Post>,
private val model: PostsViewModel,
private val selectionMode: Boolean,
private val enableIt: () -> Unit
) :
RecyclerView.Adapter<PostsAdapter.ViewHolder>() {
companion object {
private const val TYPE_FROM = 0
private const val TYPE_TO = 1
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var postContent: TextView = itemView.findViewById(R.id.post_content)
var selectPostCheckBox: ImageView = itemView.findViewById(R.id.post_select_checkbox)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(
if (viewType == TYPE_TO) R.layout.to_post else R.layout.from_post,
parent,
false
)
return ViewHolder(view)
}
#SuppressLint("CheckResult")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.selectPostCheckBox.visibility = if (selectionMode) View.VISIBLE else View.GONE
holder.postContent.text = selectionMode.toString()
holder.selectPostCheckBox.setImageResource(R.drawable.cursor_color)
holder.itemView.setOnClickListener() {
enableIt()
notifyDataSetChanged()
}
}
override fun getItemCount() = posts.size
override fun getItemViewType(position: Int): Int {
return posts[position].selfPost
}
}

TabLayout jumps to start of its witdth after notifyItemChanged()

I'm building quiz app and all the time I have trouble with notifying RecyclerView about updated item.
DiffUtil didn't work for me, anyway - I can use adapter.notifyItemChanged() but after this call my TabLayout jumps to start of it's width.
I have set onClickListener to my floatingButton to be sure that it's notifyItemChanged() issue.
Am I doing something wrong?
Fragment
class TestFragment : Fragment() {
private lateinit var viewModel: TestViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding: FragmentTestBinding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_test,
container,
false
)
val args = TestFragmentArgs.fromBundle(requireArguments())
val viewModelFactory = TestViewModelFactory(args.course)
viewModel = ViewModelProvider(this, viewModelFactory).get(TestViewModel::class.java)
binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner
val adapter = PagerAdapter(ClickListener { questionDatabase: QuestionDatabase, string: String ->
val questionUpdated = questionDatabase.apply { answer = string }
viewModel.updateAnswer(questionDatabase, questionUpdated)
})
binding.viewPager.adapter = adapter
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab: TabLayout.Tab, i: Int ->
tab.text = (i + 1).toString()
}.attach()
viewModel.pytania.observe(viewLifecycleOwner, Observer {
adapter.differ.submitList(it)
})
viewModel.score.observe(viewLifecycleOwner, Observer {
if (it != null) {
findNavController().navigate(
TestFragmentDirections.actionTestFragmentToScoreFragment(it)
)
viewModel.score.value = null
}
})
binding.bttnFinish.setOnClickListener {
adapter.notifyItemChanged(binding.viewPager.currentItem)
}
return binding.root
}
}
ViewModel
class TestViewModel(
test: String
): ViewModel() {
private val _pytania = MutableLiveData<List<QuestionDatabase>>()
val pytania: LiveData<List<QuestionDatabase>>
get() = _pytania
val score = MutableLiveData<Int?>()
init {
val listOfQuestions = mutableListOf<QuestionDatabase>()
for (x in 1..15) {
listOfQuestions.add(
QuestionDatabase(
question = "Question $x",
answerA = "AnswerA",
answerB = "AnswerB",
answerC = "AnswerC",
answerD = "AnswerD",
correctAnswer = "AnswerD",
image = 0,
questionNumber = 0
)
)
}
_pytania.value = listOfQuestions.toList()
}
fun updateAnswer(questionDatabase: QuestionDatabase, questionUpdated: QuestionDatabase) {
_pytania.value = _pytania.value?.replace(questionDatabase, questionUpdated)
}
}
ViewPagerAdapter
class PagerAdapter(
private val clickListener: ClickListener
) : RecyclerView.Adapter<ViewHolder>() {
private val differCallBack = object : DiffUtil.ItemCallback<QuestionDatabase>() {
override fun areItemsTheSame(oldItem: QuestionDatabase, newItem: QuestionDatabase): Boolean {
return oldItem.question == newItem.question
}
override fun areContentsTheSame(oldItem: QuestionDatabase, newItem: QuestionDatabase): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallBack)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder.from(parent)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(differ.currentList[position], clickListener)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
}
class ViewHolder private constructor(val binding: VpItemQuestionBinding): RecyclerView.ViewHolder(
binding.root
) {
fun bind(
question: QuestionDatabase,
clickListener: ClickListener
) {
binding.question = question
binding.onClickListener = clickListener
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = VpItemQuestionBinding.inflate(layoutInflater, parent, false)
return ViewHolder(binding)
}
}
}
class ClickListener(val clickListener: (QuestionDatabase, string: String) -> Unit) {
fun onClick(question: QuestionDatabase, string: String) = clickListener(question, string)
}
Before notifyItemChanged()
After notifyItemChanged()

getItemViewType method in Recyclerview Adapter does not working correctly

I have list_detail that contains DataDay and DataDetail objects inherit DetailType abstract class.
list_detail has DataDay object in its zero index, following indexes have DataDetail objects.
like below,,
abstract class DetailType {
abstract val type: Int
companion object {
val DAY_TYPE = 1
val DETAIL_TYPE = 2
}
}
data class DataDay(
var day: Long? = null
): DetailType() {
override val type: Int
get() = DetailType.DAY_TYPE
}
data class DataDetail(
var moneyUsed: Double? = null,
var type_used: String? = null
): DetailType() {
override val type: Int
get() = DetailType.DETAIL_TYPE
}
The problem is, when I use recyclerview to make list_detail show in order by their index,
their viewType doesn't match correctly at onCreateViewHolder and onBindViewHolder.
Zero Index in list_detail that have DataDay Object matches its viewType(DAY_TYPE). So it is not the problem.
Index over zero (index 1, 2, 3...), it's data on list should have DataDetail Object and their viewType also should have DETAIL_TYPE I think.. BUT, it doesn't enter onCreateViewHolder() or onBindViewHolder().. pass those methods, also not shown at screen! (Not produce any error on logcat)
Below is my code
class ContentActivity : AppCompatActivity(), View.OnClickListener {
val helper = DBHelper(this)
var list: MutableList<Long> = mutableListOf()
var list_detail: MutableList<DetailType> = mutableListOf()
var selected_day: Long? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_content)
selectContentDayDB()
selectMoneyDB()
}
fun selectContentDayDB() {
list = mutableListOf()
val db = helper.writableDatabase
val num = intent.getIntExtra("num", 0)
val cursor = db.rawQuery("select start_day, end_day from t_travel where num=?", arrayOf(num.toString()))
cursor.moveToNext()
val start = cursor.getLong(0)
val end = cursor.getLong(1) + 1000
for(i in start .. end step 24*60*60*1000) {
list.add(i)
}
recycler.layoutManager = LinearLayoutManager(this)
recycler.adapter = ContentAdapter(list)
}
inner class ContentViewHolder(view: View): RecyclerView.ViewHolder(view) {
val content_day = view.content_day
val content_month = view.content_month
}
inner class DateViewHolder(view: View): RecyclerView.ViewHolder(view) {
val content_day_text = view.content_day_text
}
inner class DetailViewHolder(view: View): RecyclerView.ViewHolder(view) {
val content_detail_text = view.content_detail_text
val content_type_text = view.content_type_text
val content_image = view.content_image
}
inner class ContentAdapter(val list: MutableList<Long>): RecyclerView.Adapter<ContentViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return ContentViewHolder(layoutInflater.inflate(R.layout.item_content, parent, false))
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ContentViewHolder, position: Int) {
val item = list[position]
holder.content_day.text = SimpleDateFormat("d").format(item).toString()
holder.content_month.text = SimpleDateFormat("M").format(item).toString()
holder.itemView.setOnClickListener {
list_detail = mutableListOf()
list_detail.add(DataDay(item))
selectDetailDB(item)
}
}
}
fun selectDetailDB(item: Long) {
val db = helper.writableDatabase
val num = intent.getIntExtra("num", 0)
val datecode = SimpleDateFormat("yyMMdd").format(item)
val isExistSQL = db.rawQuery("select count(*) from t_content where num=? and datecode=?",
arrayOf(num.toString(), datecode))
isExistSQL.moveToNext()
val isExist = isExistSQL.getInt(0)
if(isExist != 0){
val cursor = db.rawQuery("select type, moneyUsed from t_content where num=? and datecode=?",
arrayOf(num.toString(), datecode))
while(cursor.moveToNext()) {
val moneyUsed = cursor.getDouble(1)
val type = cursor.getString(0)
list_detail.add(DataDetail(moneyUsed, type))
}
}
recycler_content.layoutManager = LinearLayoutManager(this)
recycler_content.adapter = DetailAdapter(list_detail)
}
inner class DetailAdapter(val list: MutableList<DetailType>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemViewType(position: Int): Int {
return list[position].type
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when{
viewType == DetailType.DAY_TYPE -> {
val layoutInflater = LayoutInflater.from(parent.context)
return DateViewHolder(layoutInflater.inflate(R.layout.item_content_day, parent, false))
}
else -> {
val layoutInflater = LayoutInflater.from(parent.context)
return DetailViewHolder(layoutInflater.inflate(R.layout.item_content_detail, parent, false))
}
}
}
override fun getItemCount(): Int {
Log.d("ContentAct: getItem", list.size.toString())
return list.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val itemType = list[position]
when(itemType.type){
DetailType.DAY_TYPE -> {
val viewHolder = holder as DateViewHolder
val item = itemType as DataDay
viewHolder.content_day_text.text = SimpleDateFormat("yyyy MM dd").format(item.day)
}
DetailType.DETAIL_TYPE -> {
val viewHolder = holder as DetailViewHolder
val item = itemType as DataDetail
viewHolder.content_detail_text.text = item.moneyUsed.toString()
viewHolder.content_type_text.text = item.type_used
...
}
}
}
}
}
}
}
I solved it by myself.
The reason is in my layout xml.
My item_content_day.xml in recyclerView has height:match-parent property in all covered layout.
I can see my view when i scrolled down.. It was in below the screen.
If you have same situation like mine, Please check your layout.xml

How to obtain external array values for RecyclerView adapter

I'm trying to use a RecyclerView to show an array of values in CardViews in a specific order i.e. "Title A" & "Subtitle A" in 1 CardView; "Title B" & "Subtitle B" in another. Is there a way to obtain the values from the arrays in my fragment without having to create a new verbose class, or do I have to use a data class to achieve this?
Fragment class
class MyFragment : androidx.fragment.app.Fragment() {
private lateinit var mRecyclerView: RecyclerView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_rv, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
val v = view
mRecyclerView = v!!.findViewById<RecyclerView>(R.id.my_recyclerview)
mRecyclerView.layoutManager = LinearLayoutManager(activity)
val myList = mutableListOf(
RVAdapterTConnections.ITEM_A,
RVAdapterTConnections.ITEM_B,
RVAdapterTConnections.ITEM_B
)
val titlesList = mutableListOf(
"Title A",
"Title B"
)
val subtitlesList = mutableListOf(
"Subtitle A",
"Subtitle B"
)
val mAdapter = MyRVAdapter(myList, titlesList)
mRecyclerView.adapter = mAdapter
super.onActivityCreated(savedInstanceState)
}
}
Adapter class
internal class MyRVAdapter(private val listViewType: List<Int>, private val myList: List<CharSequence>) : RecyclerView.Adapter<MyRVAdapter.ViewHolder>() {
companion object {
const val ITEM_A = 1
const val ITEM_B = 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
ITEM_A -> ViewHolderItemA(inflater.inflate(R.layout.layout_item_a, parent, false))
else -> ViewHolderItemB(inflater.inflate(R.layout.layout_item_b, parent, false))
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val viewType = listViewType[position]
when (viewType) {
ITEM_A -> {
val viewHolderA = holder as ViewHolderItemA
viewHolderA.textView.text = "Lorem Ipsum"
}
ITEM_B -> {
val viewHolderB = holder as ViewHolderItemB
viewHolderB.ivExpandCollapse.setImageDrawable(ContextCompat.getDrawable(holder.ivExpandCollapse.context, R.drawable.ic_keyboard_arrow_down))
viewHolderB.tvTitle.text = titlesList[position]
viewHolderB.tvSubtitle.text = subtitlesList[position]
}
else -> {
val viewHolderA = holder as ViewHolderItemA
viewHolderA.textView.text = "Lorem Ipsum"
}
}
}
override fun getItemCount(): Int = listViewType.size
override fun getItemViewType(position: Int): Int = listViewType[position]
open inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
inner class ViewHolderItemA(itemView: View) : ViewHolder(itemView) {
val textView: TextView = itemView.findViewById(R.id.my_custom_tv)
}
inner class ViewHolderItemB(itemView: View) : ViewHolder(itemView) {
val tvTitle: TextView = itemView.findViewById(R.id.tv_title)
val tvSubtitle: TextView = itemView.findViewById(R.id.tv_subtitle)
}
}
Data class
data class MyItem (val title: String, val subtitle: String)
the view-type ordinary can be derived from the data model, most commonly from some type of groupId. these titlesList and subtitlesList need to be replaced; use BaseAdapter to populate the RecyclerView.Adapter. for example (it loads string resources, where SpinnerItem is a simple data model):
abstract class BaseArrayAdapter : BaseAdapter {
private var mItems: ArrayList<SpinnerItem>? = null
private var layoutInflater: LayoutInflater? = null
internal constructor(#NonNull context: Context) {
this.layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
}
internal constructor(#NonNull context: Context, #NonNull #ArrayRes arrayKeys: Int, #NonNull #ArrayRes arrayValues: Int) {
this.layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
this.setItems(context, arrayKeys, arrayValues)
}
#NonNull
#Override
override fun getItem(position: Int): SpinnerItem {
return this.mItems!!.get(position)
}
#Override
override fun getItemId(position: Int): Long {
return this.mItems!!.get(position).id!!
}
#NonNull
#Override
override fun getView(position: Int, #Nullable view: View?, #NonNull parent: ViewGroup): View {
var convertView = view
if (convertView == null) {
convertView = this.layoutInflater!!.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false)
}
convertView!!.setTag(this.mItems!!.get(position))
val textView: TextView = convertView.findViewById(android.R.id.text1)
textView.text = this.mItems!![position].name
textView.setAllCaps(true)
return convertView
}
private fun clearItems() {
if (this.mItems != null) {
this.mItems!!.clear()
} else {
this.mItems = ArrayList()
}
}
internal fun setItems(#NonNull context: Context, #NonNull #ArrayRes arrayKeys: Int, #NonNull #ArrayRes arrayValues: Int) {
this.clearItems()
val res = context.getResources()
val keys = res.getStringArray(arrayKeys)
val values = res.getStringArray(arrayValues)
for (i in keys.indices) {
this.mItems!!.add(i, SpinnerItem((i + 1).toLong(), keys[i], values[i]))
}
}
override fun getCount(): Int {
return this.mItems!!.size
}
}
some sub-class of the abstract class:
class SomeAdapter(#NonNull context: Context) : BaseArrayAdapter(context) {
init {
this.setItems(context, R.array.some_keys, R.array.some_values)
}
}
and then in the RecyclerView.Adapter:
init {
this.setItems(new SomeAdapter(context));
}

Categories

Resources