Why doesn't my function allow me to set a content description for my ImageView? It seems to allow me to set a drawable resource and text though.
class MyAdapter(
private val dataIVPlayOrPause: Drawable,
private val dataTVSong: String
) : RecyclerView.Adapter<RVAdapterEmbark.MyViewHolder>() {
private val typeHeader = 1
private val typeItem = 2
override fun onCreateViewHolder(parent: ViewGroup, type: Int): MyViewHolder {
return when (type) {
typeHeader -> MyViewHolder(inflateHelper(R.layout.header, parent))
typeItem -> MyViewHolder(inflateHelper(R.layout.body, parent))
else -> MyViewHolder(inflateHelper(R.layout.body, parent))
}
}
override fun onBindViewHolder(viewHolder: MyViewHolder, position: Int) {
if (getItemViewType(position) == typeHeader) {
} else if (getItemViewType(position) == typeItem) {
val ivPlayPause = viewHolder.itemView. iv_Play_Pause
ivPlayPause(R.drawable.play)
ivPlayPause = R.string.play.toString()
val buttonClickListener = View.OnClickListener {
if (tvSongName.text == null) {
playSong(tvSongName, ivPlayPause)
} else {
pauseSong(tvSongName, ivPlayPause)
}
}
}
}
private fun inflateHelper(resId: Int, parent: ViewGroup): View {
return LayoutInflater.from(parent.context).inflate(resId, parent, false)
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun getItemCount(): Int {
return dataTitle.size + 1
}
override fun getItemViewType(position: Int): Int {
return if (position == 0) typeHeader
else typeItem
}
private fun playSong(
tvSongName: TextView,
ivPlayPause: ImageView
) {
tvSongName.text = "Song name"
ivPlayPause.setImageResource(R.drawable.pause)
ivPlayPause.contentDescription = getString(R.string.pause)
}
}
Since you are in a RecyclerView.Adapter, you can't access the Activity, Fragment or Context instance in which getString() is declared.
In this case you can use the Context of your ImageView to get the string:
ivPlayPause.contentDescription = ivPlayPause.context.getString(R.string.pause)
Related
I have a recyclerview that can have three different views base on the data with three different record types. If the data is composed of all type 1 records or both type 1 and type 2 records, then all of the data is displayed properly. But if a type 3 record is present, then no data following that type 3 record is displayed. And I am not getting any sort of error that I can find.
Any following type 1 and type 2 records are not displayed.
Here is the code for my recyclerview adapter:
class ShipsAdapter (private val stateroomInfo: ArrayList<StateroomAdapterData>,
private val listener: OnItemClickListener):
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var rowType = 0
override fun getItemViewType(position: Int): Int {
rowType = when (stateroomInfo[position].adapterRecordType) {
Constants.SHIP_ROW -> Constants.SHIP_ROW
Constants.STATEROOM_ROW -> Constants.STATEROOM_ROW
else -> Constants.STATEROOM_PROPERTIES_ROW
}
return rowType
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
when (rowType){
Constants.SHIP_ROW -> {
val view = ListShipsRecyclerItemRowBinding.inflate(LayoutInflater.from(parent.context),
parent, false)
ListShipsViewHolder(view)
}
Constants.STATEROOM_ROW -> {
val view = ListStateroomsRecyclerItemRowBinding.inflate(LayoutInflater.from(parent.context),
parent, false)
ListStateroomsViewHolder(view)
}
else -> {
val view = ListStateroomPropertiesRecyclerItemRowBinding.inflate(LayoutInflater.from(parent.context),
parent, false)
ListStateroomPropertiesViewHolder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (rowType) {
Constants.SHIP_ROW -> (holder as ListShipsViewHolder).bind(position)
Constants.STATEROOM_ROW -> (holder as ListStateroomsViewHolder).bind(position)
Constants.STATEROOM_PROPERTIES_ROW -> (holder as ListStateroomPropertiesViewHolder).bind(position)
}
}
override fun getItemCount(): Int {
return stateroomInfo.size
}
inner class ListShipsViewHolder(shipsRow: ListShipsRecyclerItemRowBinding):
RecyclerView.ViewHolder(shipsRow.root),
View.OnClickListener {
private val tvShip = shipsRow.tvShip
private var ivEditShip = shipsRow.ivEditShip
private var ivDeleteShip = shipsRow.ivDeleteShip
private var ivStateroom = shipsRow.ivStateroom
init {
ivEditShip.setOnClickListener(this)
ivDeleteShip.setOnClickListener(this)
ivStateroom.setOnClickListener(this)
}
override fun onClick(v: View?) {
if (adapterPosition != RecyclerView.NO_POSITION)
if (v != null) {
when (v.id) {
R.id.ivEditShip -> listener.onItemClicked(adapterPosition, Constants.EDIT_SHIP_CLICKED)
R.id.ivDeleteShip -> listener.onItemClicked(adapterPosition, Constants.DELETE_SHIP_CLICKED)
R.id.ivStateroom -> listener.onItemClicked(adapterPosition, Constants.STATEROOM_CLICKED)
}
}
}
fun bind(position: Int) {
val shipData = stateroomInfo[position]
tvShip.text = shipData.ship
}
}
inner class ListStateroomsViewHolder(stateroomRow: ListStateroomsRecyclerItemRowBinding):
RecyclerView.ViewHolder(stateroomRow.root),
View.OnClickListener {
private val tvStateroom = stateroomRow.tvStateroom
private var ivEditStateroom = stateroomRow.ivEditStateroom
private var ivDeleteStateroom = stateroomRow.ivDeleteStateroom
init {
ivEditStateroom.setOnClickListener(this)
ivDeleteStateroom.setOnClickListener(this)
}
override fun onClick(v: View?) {
if (adapterPosition != RecyclerView.NO_POSITION)
if (v != null) {
when (v.id) {
R.id.ivEditStateroom -> listener.onItemClicked(adapterPosition, Constants.EDIT_STATEROOM_CLICKED)
R.id.ivDeleteStateroom -> listener.onItemClicked(adapterPosition, Constants.DELETE_STATEROOM_CLICKED)
}
}
}
fun bind(position: Int) {
val stateroomData = stateroomInfo[position]
tvStateroom.text = stateroomData.stateroom
}
}
inner class ListStateroomPropertiesViewHolder(stateroomPropertiesRow: ListStateroomPropertiesRecyclerItemRowBinding):
RecyclerView.ViewHolder(stateroomPropertiesRow.root),
View.OnClickListener {
private val tvBedrooms = stateroomPropertiesRow.tvBedrooms
private val tvBaths = stateroomPropertiesRow.tvBathrooms
private val tvConnecting = stateroomPropertiesRow.tvIsConnecting
private val ivEditStateroomProperties = stateroomPropertiesRow.ivEditStateroomProperties
init {
ivEditStateroomProperties.setOnClickListener(this)
}
fun bind(position: Int) {
val stateroomPropertiesData = stateroomInfo[position]
tvBedrooms.text = stateroomPropertiesData.numBedrooms
tvBaths.text = stateroomPropertiesData.numBaths
tvConnecting.text = stateroomPropertiesData.connectingSuite
}
override fun onClick(v: View?) {
if (adapterPosition != RecyclerView.NO_POSITION)
if (v != null) {
listener.onItemClicked(adapterPosition, Constants.EDIT_STATEROOM_PROPERTIES_CLICKED)
}
}
}
// this is required to communicate with the click listener in the Fragments
interface OnItemClickListener {
fun onItemClicked(position: Int, clickType: Int)
}
}
I am trying to show multiple type of views in a recyclerview with a header and 5 rows followed by another header and 5 rows but only 4 rows are appearing.
Here is the log output from the adapter in the onBindViewHolder
Here is the code from the adapter
class DailyFragAdapter(
private val activityData: (DetailActivityData) -> Unit,
private val dates: List<Date>,
private val list : ArrayList<TabType1>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
/*
ListAdapter<TabType1, RecyclerView.ViewHolder>(Diff())*/ {
private lateinit var context: Context
private val HEADER = 1
private val ROW = 2
/*private class Diff : DiffUtil.ItemCallback<TabType1>() {
override fun areItemsTheSame(oldItem: TabType1, newItem: TabType1): Boolean {
return oldItem.header == newItem.header && oldItem.cps.cps[0].id == newItem.cps.cps[0].id
}
override fun areContentsTheSame(
oldItem: TabType1,
newItem: TabType1
): Boolean {
return oldItem.hashCode() == newItem.hashCode()
}
}*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
context = parent.context
val layoutInflater = LayoutInflater.from(context)
return if (viewType == 2) {
DVH(DailyFragRecyclerItemBinding.inflate(layoutInflater, parent, false))
} else {
TitleHolder(DailyTableHeaderBinding.inflate(layoutInflater, parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val data: TabType1 = list[position]
if (holder is DVH) {
data.cps.cps.forEach {
Timber.i("is: a row")
holder.bind(it)
}
}else{
Timber.i("is: header")
holder as TitleHolder
holder.bind(data.header)
}
}
override fun getItemViewType(position: Int): Int {
val tabType1 = list[position]
return if (tabType1.header.title == "") {
ROW
} else {
HEADER
}
}
inner class TitleHolder(binding: DailyTableHeaderBinding) :
RecyclerView.ViewHolder(binding.root) {
private val groupHeader: TextView = binding.title
fun bind(title: Header) {
groupHeader.text = title.title
}
}
inner class DVH(binding: DailyFragRecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
private var cpname: TextView = binding.cpName
private var day1: FrameLayout = binding.frameLayout
private var day2: FrameLayout = binding.frameLayout2
private var day3: FrameLayout = binding.frameLayout3
private var day4: FrameLayout = binding.frameLayout4
private var dayContainer: ArrayList<FrameLayout> = ArrayList()
fun bind(cpVo: CheckingPointVo) {
dayContainer.addAll(arrayListOf(day1, day2, day3, day4))
cpname.apply {
text = cpVo.name
setOnClickListener {
activityData.invoke(DetailActivityData(cpVo.id, cpVo.pcID))
}
}
val map = cpVo.chartEntriesMap
for (i in dates.indices) {
val dateID = BkpDateUtil.getDateId(dates[i])
Timber.i("dateID $dateID")
var ceVo: List<ChartEntryVo>? = map[dateID]
if (ceVo == null) {
ceVo = ArrayList<ChartEntryVo>()
ceVo.add(ChartEntryVo(0, dateID, 0L, 0L, "", false))
}
val entryValue = ceVo[0].value
when (cpVo.cpType) {
CheckingPointType.YES_NO -> {
val fl: FrameLayout = dayContainer[i]
fl.setOnClickListener {
openYesNoDialog(cpVo, ceVo[0])
}
if (entryValue == 1L) {
setIconInChartEntry(fl, R.drawable.ic_tick, cpVo)
} else {
setIconInChartEntry(fl, R.drawable.ic_no_entry, cpVo)
}
}
CheckingPointType.QUANTIFIABLE -> {
}
CheckingPointType.COUNTABLE -> {
}
CheckingPointType.CATEGORY -> {
}
CheckingPointType.TEXT -> {
}
}
}
dayContainer.clear()
}
}
private fun setIconInChartEntry(fl: FrameLayout, resID: Int, cpVo: CheckingPointVo) {
fl.getChildAt(0).visibility = GONE
val image: ImageView = fl.getChildAt(1) as ImageView
image.visibility = VISIBLE
image.setImageResource(resID)
/*image.setOnClickListener {
activityData.invoke(DetailActivityData(cpVo.id, cpVo.pcID))
}*/
}
private fun openYesNoDialog(cpVo: CheckingPointVo, ce: ChartEntryVo) {
val builder = AlertDialog.Builder(context)
val dataSourceArray = BkpUiUtil.getYesNoArray()
val date = getDateFromId(ce.dateKey)
val title: String = getDayText(date, 1) + " - " + cpVo.name
builder.setTitle(title)
builder.setSingleChoiceItems(
dataSourceArray, BkpUiUtil.getYesNoIndex(ce.value.toString())
) { dialog, which ->
ce.value = BkpUiUtil.getYesNoId(which)
activityData.invoke(
DetailActivityData(
cpvo = cpVo,
cevo = ce,updateChart = true
))
dialog.dismiss()
}
val d = builder.create()
d.show()
}
override fun getItemCount() = list.size
}
data class DetailActivityData(var cpID: Long = 0, var pcID: Long = 0, var cpvo:CheckingPointVo = CheckingPointVo(), var cevo:ChartEntryVo= ChartEntryVo(), var updateChart : Boolean = false)
data class TabType1(
val header: Header = Header(""), val cps: CheckingPointVoList = CheckingPointVoList(
cps = listOf(
CheckingPointVo()
)
)
)
This is how the adapter is given the data.
val data: ArrayList<TabType1> = arrayListOf(
TabType1(
header = Header("Group One")
),
TabType1(
cps = CheckingPointVoList(it)
),
TabType1(
header = Header("Group Two")
),
TabType1(
cps = CheckingPointVoList(it)
)
)
if(it1.updateChart){
vm.updateChartEntry(it1.cpvo,it1.cevo)
}else{
Intent(requireContext(), CpDetailActivity::class.java).apply {
putExtra("cprId", it1.cpID)
putExtra("pcId", it1.pcID)
requireActivity().startActivity(this)
}
}
}, arraylist,dayslist)
This is the output that I get.
What am I missing?
An Adapter should adapt ONE list of data, not multiple lists nested within others. Meaning you need an Adapter and RecyclerView for each list.
If you want to do that you need to add an Adapter/RecyclerView to DVH and display your CheckingPoint list in there.
look here ->
override fun getItemCount() = list.size
Its only going to bind 4 times because you only gave it 4 items.
And here you are just rebinding the same ViewHolder, you need to pass in the data to the ViewHolder and have it display the list of "cps"
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val data: TabType1 = list[position]
if (holder is DVH) {
holder.bind(data) //HERE
}else{
Timber.i("is: header")
holder as TitleHolder
holder.bind(data.header)
}
}
inner class DVH(binding: DailyFragRecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
private var checkingPointVoRecyclerView: RecyclerView = binding.recyclerVew
private var checkingPointVoAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> = CheckingPointVoAdapter(dates)
checkingPointVoRecyclerView.adapter = checkingPointVoAdapter
fun bind(data: TabType1) {
checkingPointVoAdapter.list = data.cps
checkingPointVoAdapter.notifyDataSetChanged()
}
}
class CheckingPointVoAdapter(
private val dates: List<Date>,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(){
public var list: List<CheckingPointVo> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
context = parent.context
val layoutInflater = LayoutInflater.from(context)
return ViewHolder(CheckingPointRecyclerItemBinding.inflate(layoutInflater, parent, false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val cpv: CheckingPointVo = list[position]
holder as ViewHolder
holder.bind(cpv)
}
inner class ViewHolder(binding: CheckingPointRecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
private var cpname: TextView = binding.cpName
private var day1: FrameLayout = binding.frameLayout
private var day2: FrameLayout = binding.frameLayout2
private var day3: FrameLayout = binding.frameLayout3
private var day4: FrameLayout = binding.frameLayout4
private var dayContainer: ArrayList<FrameLayout> = ArrayList()
fun bind(cpVo: CheckingPointVo) {
dayContainer.addAll(arrayListOf(day1, day2, day3, day4))
cpname.apply {
text = cpVo.name
setOnClickListener {
activityData.invoke(DetailActivityData(cpVo.id, cpVo.pcID))
}
}
val map = cpVo.chartEntriesMap
for (i in dates.indices) {
val dateID = BkpDateUtil.getDateId(dates[i])
Timber.i("dateID $dateID")
var ceVo: List<ChartEntryVo>? = map[dateID]
if (ceVo == null) {
ceVo = ArrayList<ChartEntryVo>()
ceVo.add(ChartEntryVo(0, dateID, 0L, 0L, "", false))
}
val entryValue = ceVo[0].value
when (cpVo.cpType) {
CheckingPointType.YES_NO -> {
val fl: FrameLayout = dayContainer[i]
fl.setOnClickListener {
openYesNoDialog(cpVo, ceVo[0])
}
if (entryValue == 1L) {
setIconInChartEntry(fl, R.drawable.ic_tick, cpVo)
} else {
setIconInChartEntry(fl, R.drawable.ic_no_entry, cpVo)
}
}
CheckingPointType.QUANTIFIABLE -> {
}
CheckingPointType.COUNTABLE -> {
}
CheckingPointType.CATEGORY -> {
}
CheckingPointType.TEXT -> {
}
}
}
dayContainer.clear()
}
}
}
I did not test this but this is like 90% of what you need.
OnBindViewHolder gives you a view or you can imagine it as a row
, then you bind data to that row (setting text, etc..)
let's look at what you actually did in OnBindViewHolder
data.cps.cps.forEach { // you bind the data to the same row multiple times
Timber.i("is: a row")
holder.bind(it)
}
But there is only one row.
To solve this you need to pass a list of header items and row items only
sealed class DataItem {
abstract val id: Long
data class RowItem(val row: Row) : DataItem() {
override val id = row.id
}
data class HeaderItem(val header: Header) : DataItem() {
override val id = header.id
}
}
The Transform your row and header data to the DataItem Like this
val rowItems: List<DataItem> = rowList.map { DataItem.RowItem(it) }
val headertems: List<DataItem> = headerList.map { DataItem.BankItem(it) }
val items = rowItems+ headertems
//then pass the items to the adapter
So your adapter now will create a new ViewHoler to each item in the list and you can check for it as
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_ITEM_ROW -> DVH(DailyFragRecyclerItemBinding.inflate(layoutInflater, parent, false))
ITEM_VIEW_TYPE_ITEM_HEADER -> TitleHolder(DailyTableHeaderBinding.inflate(layoutInflater, parent, false))
else -> throw ClassCastException("Unknown viewType $viewType")
}
}
then bind data to each view as
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DVH-> {
val item = getItem(position) as DataItem.RowItem
holder.bind(item)
}
is TitleHolder -> holder.bind(item)
}
}
Finally you need to adjust getItemViewType
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is DataItem.RowItem -> ITEM_VIEW_TYPE_ITEM_ROW
is DataItem.HeaderItem -> ITEM_VIEW_TYPE_ITEM_HEADER
}
}
There are two Recyclerview in same activity rv1 and rv2. Selected item of rv1 will show in rv2
rv1:
Here I select multiple items
rv2:
it should shows like this
Adapter class of rv1:
class ServiceJobAdapter(val context: Context, var list:ArrayList<JobRespo>,var listener:OnItemClick):
RecyclerView.Adapter<ServiceJobAdapter.ItemsCarrier>(){
var currentSelectedIndex= -1
var selectedItem = SparseBooleanArray()
var animationItemsIndex = SparseBooleanArray()
private val reverseAllAnimations = false
var holder:ItemsCarrier? =null
class ItemsCarrier(itemView: View) : RecyclerView.ViewHolder(itemView)
{
var jobName = itemView.findViewById<TextView>(R.id.job_name)
var jobPrice = itemView.findViewById<TextView>(R.id.job_price)
var iconBack = itemView.findViewById(R.id.icon_back) as RelativeLayout
var iconFront = itemView.findViewById(R.id.icon_front) as RelativeLayout
var iconContainer = itemView.findViewById(R.id.icon_container) as CardView
fun binde(jobRespo: JobRespo) {
jobName.text = jobRespo.repDesc
jobPrice.text="₹"+jobRespo.repRice
if (iconFront.visibility == View.VISIBLE)
{
jobRespo.setChecked(false)
}else{
jobRespo.setChecked(true)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemsCarrier {
val view = LayoutInflater.from(context).inflate(R.layout.job_row,parent,false)
return ItemsCarrier(view)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ItemsCarrier, position: Int) {
this.holder = holder
holder.itemView.isActivated = selectedItem[position,false]
holder.binde(list[position])
applyIconAnimation(holder, position)
// apply click events
applyClickEvents(holder, position)
}
private fun applyClickEvents(holder: ItemsCarrier, position: Int) {
holder.iconContainer.setOnClickListener {
listener.onIconClicked(position)
listener.AllItem(list[position]) }
}
private fun applyIconAnimation(holder: ItemsCarrier, position: Int)
{
if (selectedItem.get(position, false)) {
holder.iconFront!!.visibility = View.GONE
resetIconYAxis(holder.iconBack)
holder.iconBack.visibility = View.VISIBLE
holder.iconBack.alpha = 1f
if (currentSelectedIndex == position) {
FlipAnimator.flipView(context, holder.iconBack, holder.iconFront, true)
resetCurrentIndex()
}
} else {
holder.iconBack.visibility = View.GONE
resetIconYAxis(holder.iconFront)
holder.iconFront.visibility = View.VISIBLE
holder.iconFront.alpha = 1f
if (reverseAllAnimations && animationItemsIndex.get(
position,
false
) || currentSelectedIndex == position
) {
FlipAnimator.flipView(context, holder.iconBack, holder.iconFront, false)
resetCurrentIndex() } } }
private fun resetIconYAxis(view: RelativeLayout?)
{
if (view!!.rotationY != 0f) {
view.rotationY = 0f
}
}
private fun resetCurrentIndex() {
currentSelectedIndex = -1
}
fun toggleSelection(pos: Int) {
currentSelectedIndex = pos
if (selectedItem.get(pos, false)) {
selectedItem.delete(pos)
animationItemsIndex.delete(pos)
} else {
selectedItem.put(pos, true)
animationItemsIndex.put(pos, true)
}
notifyItemChanged(pos)
}
fun getSelectedItems(): ArrayList<JobRespo>
{
val selectItems = ArrayList<JobRespo>()
for(item in list)
{
if (!item.isChecked())
{
selectItems.add(item)
}
}
return selectItems}}
Using Interface
interface OnItemClick{
fun onIconClicked(position: Int)
fun AllItem(jobs:JobRespo)}
Implement interface in Activity
override fun onIconClicked(position: Int) {
mAdapter!!.toggleSelection(position)
}
override fun AllItem(jobs: JobRespo) {
val selectedItems:ArrayList<JobRespo>
=mAdapter!!.getSelectedItems()
selectIte.addAll(selectedItems)
}
Adapter class of 2nd Recyclerview:
lass SelectItemAdapter(val context: Context, var list:List<JobRespo>): RecyclerView.Adapter<SelectItemAdapter.ItemsCarriers>(){
class ItemsCarriers(itemView: View) : RecyclerView.ViewHolder(itemView) {
var itemName = itemView.findViewById<TextView>(R.id.item_name)
var itemPrice= itemView.findViewById<TextView>(R.id.item_peice)
var itmDelet =itemView.findViewById<LinearLayout>(R.id.item_delete)
fun bind(job: JobRespo) {
itemName.text = job.repDesc
itemPrice.text = job.repRice }
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemsCarriers {
val root = LayoutInflater.from(context).inflate(R.layout.select_item_row,parent,false)
return ItemsCarriers(root)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ItemsCarriers, position: Int) {
holder.bind(list[position])}}
Now how can i pass multiselected data from one recyclerview to anathor recyclerview of same activity?
Thanks your consideration and guidded to me :)
You can create a method in a second adapter to update the selected value like below and use it when you getting selected items.
fun setSelectedData(data:ArrayList<JobRespo>){
this.list.clear()
this.list.addAll(data)
notifyDataSetChanged ();
}
What's the correct way to implement AdMob ads (as a different view type) inside a Kotlin RecyclerView that contains an additional (but different) view type? I've not seen any helpful tutorials online. The issue I'm having is with the onCreateViewHolder method as I'm unsure of the correct way to modify it.
class AdapterMain(
private val mCtx: Context,
var myList: MutableList<ItemRV>
) : androidx.recyclerview.widget.RecyclerView.Adapter<AdapterMain
.MyViewHolder>() {
private val myListFull = myList.toMutableList()
private var mClickListener: ItemClickListener? = null
private val itemRV = 1
private val itemAD = 2
override fun getItemViewType(position: Int): Int {
return if (position % 5 == 0) {
itemRV
} else {
itemAD
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) {
return if (viewType == itemAD) {
val adLoader = AdLoader.Builder(mCtx, "ca-app-pub-5544923106349792~1702536043")
.forUnifiedNativeAd { ad : UnifiedNativeAd ->
// Show the ad.
}
.withAdListener(object : AdListener() {
override fun onAdFailedToLoad(errorCode: Int) {
// Handle the failure by logging, altering the UI, and so on.
}
})
.withNativeAdOptions(
NativeAdOptions.Builder()
.build())
.build()
adLoader.loadAd(AdRequest.Builder().build())
} else {
val inflater = LayoutInflater.from(mCtx)
val v = inflater.inflate(R.layout.rv_item, parent, false)
return MyViewHolder(v)
}
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
if (position == itemAD){
} else {
val product = myList[holder.adapterPosition]
holder.tvTitle.text = product.itemName
}
}
override fun getItemCount(): Int {
return myList.size
}
inner class MyViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView
.ViewHolder(itemView), View.OnClickListener {
var tvTitle: TextView = itemView.tv_title
}
interface ItemClickListener {
fun onItemClick(view: View, position: Int)
}
}
What you want to do is create 2 classes that extend ViewHolder; one for your normal content, and one for your ad view. You'll need to change some of your functions to use the generic RecyclerView.ViewHolder instead of your MyViewHolder as it could be either one.
In your onCreateViewHolder, you'll want to create one or the other, and return that.
And then in your onBindViewHolder, that's where you'll want to load/show your ad.
class AdapterMain(
private val mCtx: Context,
var myList: MutableList<ItemRV>
) : androidx.recyclerview.widget.RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val myListFull = myList.toMutableList()
private var mClickListener: ItemClickListener? = null
private val itemRV = 1
private val itemAD = 2
override fun getItemViewType(position: Int): Int {
return if (position % 5 == 0) {
itemRV
} else {
itemAD
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) {
// Create an ad view holder
return if (viewType == itemAD) {
val v = LayoutInflater.from(mCtx).inflate(R.layout.ad_item, parent, false)
AdViewHolder(v)
} else {
val v = LayoutInflater.from(mCtx).inflate(R.layout.rv_item, parent, false)
MyViewHolder(v)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder) {
// This is where you want to load/show the ad.
is AdViewHolder -> {
val adLoader = AdLoader.Builder(mCtx, "ca-app-pub-5544923106349792~1702536043")
.forUnifiedNativeAd { ad : UnifiedNativeAd ->
// Show the ad.
}
.withAdListener(object : AdListener() {
override fun onAdFailedToLoad(errorCode: Int) {
// Handle the failure by logging, altering the UI, and so on.
}
})
.withNativeAdOptions(
NativeAdOptions.Builder()
.build())
.build()
adLoader.loadAd(AdRequest.Builder().build())
}
is MyViewHolder -> {
val product = myList[holder.adapterPosition]
holder.tvTitle.text = product.itemName
}
}
}
override fun getItemCount(): Int {
return myList.size
}
inner class MyViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView
.ViewHolder(itemView), View.OnClickListener {
var tvTitle: TextView = itemView.tv_title
}
inner class AdViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView
.ViewHolder(itemView), View.OnClickListener {
// do any ad setup
}
interface ItemClickListener {
fun onItemClick(view: View, position: Int)
}
}
so i'm trying to do connection between 2 ListViews, after clicking on 1 item in first ListView, it changes an Array (depending on what i've cliked), that Array goes as a constructor to the second ListView, which changes background depending on what is in array, which means: I click on button in 1. ListView, 2. ListView react (in this sample changes background). I found something called "notifyDataSetChanged", but that didn't help me at all, tried to make a update method in second ListView as well, neither that worked out. Appreciate any help, thanks
class ChoosingSpells : AppCompatActivity() {
private var learnedSpells = listOf(3,4,0,0,5,5)
private val chosenSpells = arrayOf(5,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
private var clickedSpell = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_choosing_spells)
buttonChoose.visibility = View.INVISIBLE
val listView = findViewById<ListView>(R.id.choosing_listview)
choosing_listview.adapter = LearnedSpellsView(textLabel,textLevel,textDescription,textStats, learnedSpells, clickedSpell, buttonChoose)
chosen_listView.adapter = ChosenSpellsView(chosenSpells)
buttonChoose.setOnClickListener{
for (i in 1..19) {
if(chosenSpells[i] != 0){
chosenSpells[i] = clickedSpell
buttonChoose.text = chosenSpells[i].toString()
break
}
}
}
}
private class LearnedSpellsView(var textViewLabel: TextView, var textViewLevel: TextView, var textViewDescription: TextView, var textViewStats: TextView, val learnedSpells: List<Int>, var clickedSpell:Int, var buttonChoose: Button) : BaseAdapter() {
override fun getCount(): Int {
return (learnedSpells.size/2+1)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Any {
return "TEST STRING"
}
override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View {
val rowMain: View
if (convertView == null) {
val layoutInflater = LayoutInflater.from(viewGroup!!.context)
rowMain = layoutInflater.inflate(R.layout.row_choosingspells, viewGroup, false)
val viewHolder = ViewHolder(rowMain.button1, rowMain.button2)
rowMain.tag = viewHolder
} else {
rowMain = convertView
}
val viewHolder = rowMain.tag as ViewHolder
try{
viewHolder.button1.setBackgroundResource(getDrawable(learnedSpells[if(position==0){0}else{position*2}]))
viewHolder.button2.setBackgroundResource(getDrawable(learnedSpells[if(position==0){1}else{position*2+1}]))
if(learnedSpells[if(position==0){0}else{position*2}]!=0){
viewHolder.button1.setOnClickListener {
textViewLabel.text = spellSpec(learnedSpells[if(position==0){0}else{position*2}],0)
textViewLevel.text = spellSpec(learnedSpells[if(position==0){0}else{position*2}],3)
textViewStats.text = spellSpec(learnedSpells[if(position==0){0}else{position*2}],2)
textViewDescription.text = spellSpec(learnedSpells[if(position==0){0}else{position*2}],4)
clickedSpell = learnedSpells[if(position==0){0}else{position*2}]
buttonChoose.visibility = View.VISIBLE
}
}else{
viewHolder.button1.isClickable = false
}
}catch(e:Exception){
viewHolder.button1.isClickable = false
viewHolder.button1.setBackgroundResource(getDrawable(0))
}
try{
if(learnedSpells[if(position==0){1}else{position*2+1}]!=0){
viewHolder.button2.setOnClickListener {
textViewLabel.text = spellSpec(learnedSpells[if(position==0){1}else{position*2+1}],0)
textViewLevel.text = spellSpec(learnedSpells[if(position==0){1}else{position*2+1}],3)
textViewStats.text = spellSpec(learnedSpells[if(position==0){1}else{position*2+1}],2)
textViewDescription.text = spellSpec(learnedSpells[if(position==0){1}else{position*2+1}],4)
clickedSpell = learnedSpells[if(position==0){1}else{position*2+1}]
buttonChoose.visibility = View.VISIBLE
}
}else{
viewHolder.button2.isClickable = false
}
}catch(e:Exception){
viewHolder.button2.isClickable = false
viewHolder.button2.setBackgroundResource(getDrawable(0))
}
return rowMain
}
private fun getDrawable(index:Int): Int {
return(when(index) {
3 -> R.drawable.firespell
4 -> R.drawable.icespell
5 -> R.drawable.windspell
0 -> R.drawable.shield
else -> NULL
}
)
}
private class ViewHolder(val button1: TextView, val button2: TextView)
}
private class ChosenSpellsView(var chosenSpells: Array<Int>) : BaseAdapter() {
override fun getCount(): Int {
return 20
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Any {
return "TEST STRING"
}
fun updateAdapter(chsenSpells: Array<Int>) {
this.chosenSpells = chsenSpells
notifyDataSetChanged()
}
override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View {
val rowMain: View
if (convertView == null) {
val layoutInflater = LayoutInflater.from(viewGroup!!.context)
rowMain = layoutInflater.inflate(R.layout.row_chosen_spells, viewGroup, false)
val viewHolder = ViewHolder(rowMain.button1)
rowMain.tag = viewHolder
} else {
rowMain = convertView
}
val viewHolder = rowMain.tag as ViewHolder
viewHolder.button1.setBackgroundResource(getDrawable(chosenSpells[position]))
viewHolder.button1.text = (position+1).toString()
viewHolder.button1.gravity = Gravity.LEFT;
viewHolder.button1.setOnClickListener {
chosenSpells[position] = 0
viewHolder.button1.setBackgroundResource(getDrawable(chosenSpells[position]))
}
return rowMain
}
private fun getDrawable(index:Int): Int {
return(when(index) {
3 -> R.drawable.firespell
4 -> R.drawable.icespell
5 -> R.drawable.windspell
0 -> R.drawable.shield //empty slot
else -> NULL
}
)
}
private class ViewHolder(val button1: TextView)
}
}
Used notifyDataSetChanged() out of the Adapter and works well.