I have two scenario to highlight the item in recyclerview first one is when user click on any item so that clicked item should be highlighted and and second scenario is when last or recent item added into the list that time that last added item should be highlighted.
So my first scenario(onClick) is working fine but problem is in my second scenario so whenever I'm adding item into the list so two items are highlighted. Please suggest me where I am wrong. and one more thing that recent or last item should be perform auto click also. so How can I achieve it.
class CarItemAdapter(
private val activity: MainActivity,
private val carList: ArrayList<CarEntity>,
private val carViewModel: CarViewModel,
private val settings: Settings
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var listener: OnItemsClickListener? = null
var rowIndex = 100
var listItemCount = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return when (viewType) {
VIEW_TYPE_ADDITEM -> ViewHolderAddCarItem(SettingsCarAddItemTileBinding.inflate(layoutInflater, parent, false))
VIEW_TYPE_ITEM -> ViewHolderCarItem(SettingsCarItemTileBinding.inflate(layoutInflater, parent, false))
else -> throw IllegalArgumentException("Invalid view type")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ViewHolderCarItem -> holder.bind(carList[position -1], position-1)
is ViewHolderAddCarItem -> holder.bind()
}
}
inner class ViewHolderAddCarItem internal constructor(private var binding: SettingsCarAddItemTileBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind() {
binding.lifecycleOwner = activity
binding.handler = EventHandler()
binding.userSpecificCarSubtitle.setText(R.string.user_specific_car_subtitle)
}
inner class EventHandler {
fun onItemClicked() {
activity.showSubPage(Car360AddVehiclePage(activity), true)
}
}
}
inner class ViewHolderCarItem internal constructor(private var binding: SettingsCarItemTileBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(carEntity: CarEntity, position: Int) {
Timber.d("Data store position %s %s", position, carList.size)
listItemCount = itemCount
binding.lifecycleOwner = activity
val bmp = BitmapFactory.decodeByteArray(carEntity.image, 0, Objects.requireNonNull<ByteArray>(carEntity.image).size)
binding.carImage.setImageBitmap(bmp)
binding.carName.text = carEntity.label
binding.layoutCar.setOnClickListener {
listItemCount = 100
listener?.onItemClick(carEntity)
settings.finNumber = carEntity.finNumber
settings.selectedCarType = activity.getString(R.string.settings_category_view_sub_title_for_user_specific_car)
settings.isCarSelected = true
rowIndex = position
notifyDataSetChanged()
}
binding.deleteButton.setOnClickListener {
GlobalScope.launch(Dispatchers.IO) { carViewModel.deleteByFinNumber(carEntity.finNumber) }
carList.removeAt(position)
notifyDataSetChanged()
}
if(position == listItemCount-2){
binding.layoutCar.setBackgroundColor(activity.getColor(R.color.petrol))
binding.carName.setTextColor(activity.getColor(R.color.white))
}else{
binding.layoutCar.setBackgroundColor(activity.getColor(R.color.coolGray))
binding.carName.setTextColor(activity.getColor(R.color.coolGray_80k))
}
if (rowIndex == position) {
binding.layoutCar.setBackgroundColor(activity.getColor(R.color.petrol))
binding.carName.setTextColor(activity.getColor(R.color.white))
}
}
}
override fun getItemViewType(position: Int): Int {
return if (position == 0 && position <= carList.size) {
VIEW_TYPE_ADDITEM
} else VIEW_TYPE_ITEM
}
override fun getItemCount(): Int {
return carList.size + 1
}
interface OnItemsClickListener {
fun onItemClick(carEntity: CarEntity)
}
fun setWhenClickListener(listener: OnItemsClickListener) {
this.listener = listener
}
companion object {
const val VIEW_TYPE_ITEM = 0
const val VIEW_TYPE_ADDITEM = 1
}
}
MyFragmentSubPage : where I'm adding data into the list
if (isDialogVisible) {
Dialog imageDownloadCheckDialog = Dialog.createProgressBarDialog(getContext(), R.string.image_progressbar_title);
imageDownloadCheckDialog.setCancelable(false);
imageDownloadCheckDialog.show();
carViewModel.getGetDismissDialog().observe(getActivity(), isDismissDialog -> {
if (isDismissDialog) {
imageDownloadCheckDialog.dismiss();
carViewModel.dismissDialog(false);
new Thread(() -> {
CarEntity carEntity = carViewModel.getImageFor340Degree(vinNumber, "340");
// Here I am adding data into the list
recyclerImageList.add(carEntity);
}).start();
}
});
}
RecyclerView recyclerView = binding.getRoot().findViewById(R.id.list);
if (recyclerView != null) {
layoutManager = new GridLayoutManager(getContext(), 2);
recyclerView.setLayoutManager(layoutManager);
}
carItemAdapter = new CarItemAdapter(getActivity(), recyclerImageList, eventHandler, carViewModel, settings);
assert recyclerView != null;
recyclerView.setAdapter(carItemAdapter);
recyclerView.getRecycledViewPool().setMaxRecycledViews(carItemAdapter.VIEW_TYPE_ITEM, 50);
First make a CarEntity var inside your adapter called selectedCar.
Make a function inside your adapter called submitItem
fun submitItem(car: CarEntity) {
selectedCar = car //set the selected car to the new car
notifyItemChanged(rowIndex)//rebind old selected car
carList.add(car) //add new car to list
rowIndex = carList.size() - 1 //set current selected index
notifyItemInserted(rowIndex)//notify the change at selected index
}
And your dialog
new Thread(() -> {
CarEntity carEntity = carViewModel.getImageFor340Degree(vinNumber, "340");
// Here I am adding data into the list
requireActivity().runOnUiThread{
carItemAdapter.submitItem(carEntity);
}
}).start();
and your button
binding.layoutCar.setOnClickListener {
listItemCount = 100
listener?.onItemClick(carEntity)
settings.finNumber = carEntity.finNumber
settings.selectedCarType = activity.getString(R.string.settings_category_view_sub_title_for_user_specific_car)
selectedCar = carEntity //set the select car on click
notifyItemChanged(rowIndex) //notify old row has changed
notifyItemChanged(position) //notify new row has changed
rowIndex = position // set current selected row
}
and on bind to set selected view stuff
if(carEntity == selectedCar){
//highlight row
}
Related
In my application I have one fragment and in this fragment I have one recyclerview and 2 button.
Button 1 is Select all and button 2 is Deselect all.
I write below codes for recyclerview:
`
private lateinit var binding: ItemDayMyBinding
private lateinit var context: Context
private val TYPE_HEADER = 0
private val TYPE_DAY = 1
private var firstDayDayOfWeek = 0
private var totalDays = 0
private var todayPosition = -1
private val addedDateList = mutableListOf<PersianDate>()
private val removedDateList = mutableListOf<PersianDate>()
private val selectedDays = mutableListOf<DayEntity>()
init {
firstDayDayOfWeek = items[0].dayOfWeek
totalDays = items.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
binding = ItemDayMyBinding.inflate(LayoutInflater.from(parent.context), parent, false)
context = parent.context
return ViewHolder()
}
override fun getItemCount() = 7 * 7
override fun getItemViewType(position: Int): Int {
return if (isPositionHeader(position)) {
TYPE_HEADER
} else {
TYPE_DAY
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(position)
holder.setIsRecyclable(false)
}
inner class ViewHolder : RecyclerView.ViewHolder(binding.root) {
//Bind data
fun bind(pos: Int) {
binding.apply {
var position = pos
position += 6 - (position % 7) * 2
//Check
if (totalDays < position - 6 - firstDayDayOfWeek) {
return
} else {
//Day
if (!isPositionHeader(position)) {
if (position - 7 - firstDayDayOfWeek >= 0) {
val day = items[position - 7 - firstDayDayOfWeek]
dayTxt.isVisible = true
//Day text options
dayTxt.text = day.num
dayTxt.setTextColor(ContextCompat.getColor(context, R.color.black))
//Holiday
if (day.isHoliday) {
dayTxt.setTextColor(ContextCompat.getColor(context, R.color.mystic))
} else {
dayTxt.setTextColor(ContextCompat.getColor(context, R.color.black))
//Today
if (day.isToday) {
todayPosition = position
}
//Previous of today
if (position < todayPosition) {
dayTxt.setTextColor(ContextCompat.getColor(context, R.color.spanishGray))
} else {
dayTxt.setTextColor(ContextCompat.getColor(context, R.color.black))
}
}
} else {
dayTxt.isVisible = false
}
} else {
//Header
dayTxt.text = NAME_OF_DAYS_OF_WEEK_NAME[position]
dayTxt.setTextColor(ContextCompat.getColor(context, R.color.weldonBlue))
}
}
}
}
}
private fun isPositionHeader(position: Int) = position < 7
I want when click on select all button, select all today and next days.
Not previous days!
Searched in stackoverflow and find this:
`
ArrayList<Item> selected = new ArrayList<Item>();
ArrayList<Item> items = new ArrayList<Item>();
public void selecteAll() {
selected.clear();
selected.addAll(items);
notifyDataSetChanged();
}
public void clearAll() {
selected.clear();
notifyDataSetChanged();
}
public void bindView() {
Item item = items.get(position);
if(selected.contains(item) {
// Do selected action
} else {
// Non selecetd ctions
}
}
`
In this solution just select all of items, but I want just select today and next days!
How can I it?
Not getting exactly what you have in Item and other data but yes below code can give you hint what you can do
I want when click on select all button, select all today and next days.
As per your requirement , you first need to determine that you need to perform selection operation or not and from where
So first you declare one boolean in your adapter class
private boolean needToSelectDays = false
after declaring it in adapter , you can make change in selectAll function like this
public void selecteAll() {
needToSelectDays = true
notifyDataSetChanged();
}
public void clearAll() {
needToSelectDays = false
notifyDataSetChanged();
}
in above code we are managing boolean variable only .. now it is time of use it and as per your code , you are binding data in ViewHolder class so you can add this code within your existing code
fun bind(pos: Int) {
// your existing code
if(needToSelectDays && dayGettingFromItem >= currentDay){
// you can write here logic of selecting date
}else{
// you can write here logic of unselecting dat
}
}
hope it will help you
Jacson
When you create adapter for recycler view then you pass list of model of items
so just create one variable like isSelected = false
on select all button click change all item model to selected is true and for deselect all button click for all item is selected is false
and if you need select only today and next days then set is selected true for only today and next day
after that notify dataset chenge so resule as you want
I have got the following for setting the background color for a single item when clicking on it:
// Get the listView on the Home Fragment
val contactList = findViewById<ListView>(R.id.listViewContacts)
// Create IDs for each element
val id : Int = R.id.txtListElement
// Fill the ListView with the custom contact_list_template
arrayAdapter = ArrayAdapter(this,
R.layout.contact_list_template, id, contactSimple)
contactList.adapter = arrayAdapter
contactList.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view,
position, _ ->
val selectedItem = adapterView.getItemAtPosition(position) as String
val itemIdAtPos = adapterView.getItemIdAtPosition(position)
view.setBackgroundColor(ContextCompat.getColor(this, R.color.purple_200))
...
}
But how can I set the color for every object inside the ListView?
I tried
contactList.setBackgroundColor(ContextCompat.getColor(this, R.color.white)) but that does not seem to work.
Try to define your custom BaseAdapter for the ListView. (I assume that the contact_list_template XML contains a TextView with id title).
class ListViewContactAdapter(
private val contactList: List<String>
) : BaseAdapter() {
private val lastClicked = ""
override fun getCount(): Int = contactList.size
override fun getItem(position: Int): String = contactList[position]
override fun getItemId(position: Int): Long = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = convertView ?: LayoutInflater.from(parent.context).inflate(R.layout.contact_list_template, parent, false)
val holder = ViewHolderContact(view)
val contact = getItem(position)
holder.title.text = contact
if (contact == lastClicked) {
// Selected background
view.setBackgroundColor(ContextCompat.getColor(this, ...))
} else {
// Unselected background
view.setBackgroundColor(ContextCompat.getColor(this, ...))
}
view.setOnClickListener {
lastClicked = contact
notifyDataSetChanged()
}
return view
}
class ViewHolderContact(itemView: View) {
val title = itemView.findViewById<TextView>(R.id.title)
}
}
You can then set the adapter of the list with:
val contactList = findViewById<ListView>(R.id.listViewContacts)
contactList.adapter = ListViewContactAdapter(contactSimple)
I have created a custom spinner adapter which returns two views (item_new_area & item_area), item_new_area is static with an option Add New and item_area populated dynamic.
When Add new is selected,I want to launch the dialog for add new area but i keep on getting an error that lateinit property listener has not been initialized
Custom Spinner Adapter
class AreaSpinnerAdapter(private val inflater: LayoutInflater) : BaseAdapter() {
var areas: List<AreaEntity>? = null
lateinit var listener: OnItemSelectedListener
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
return when (getItemViewType(position)) {
1 -> {
val binding: ItemNewAreaBinding = DataBindingUtil.inflate<ItemNewAreaBinding>(
inflater,
R.layout.item_new_area,
parent, false
).also {
it.root.tag = it
}
binding.addNew.setOnClickListener {
listener.onClick()
}
binding.root
}
else -> {
val binding: ItemAreaBinding = DataBindingUtil.inflate<ItemAreaBinding>(
inflater,
R.layout.item_area,
parent, false
).also {
it.root.tag = it
}
binding.area = getItem(position)
binding.root
}
}
}
override fun getItemViewType(position: Int): Int {
return if (position == 1) {
1
} else {
2
}
}
fun setOnItemClickListener(listener: OnItemSelectedListener) {
this.listener = listener
}
interface OnItemSelectedListener {
fun onClick()
}
}
I try to set the on Item Clicked listener in the onCreateView method of my fragment:
val spinnerAdapter = AreaSpinnerAdapter(layoutInflater)
spinnerAdapter.setOnItemClickListener(object :
AreaSpinnerAdapter.OnItemSelectedListener {
override fun onClick() {
addNewAreaDialog()
}
})
binding?.spinnerArea?.adapter = spinnerAdapter
Error Log
kotlin.UninitializedPropertyAccessException: lateinit property listener has not been initialized
at com.test.adapter.AreaSpinnerAdapter.getListener(AreaSpinnerAdapter.kt:15)
at com.test.adapter.AreaSpinnerAdapter$getView$1.onClick(AreaSpinnerAdapter.kt:50)
line 15 = lateinit var listener: OnItemSelectedListener
line 25 = listener.onClick()
I know that am supposed to initialize the listener before i call getView method but for some reasons am failing to initialize the listener, Any help on how to do it shall be be greatly appreciated. Thanks
You need to move the listener AreaSpinnerAdapter to the constructor.
class AreaSpinnerAdapter(
private val inflater: LayoutInflater,
private val listener: OnItemSelectedListener
) : BaseAdapter() {
var areas: List<AreaEntity>? = null
and then call it like
val spinnerAdapter = AreaSpinnerAdapter(layoutInflater,
object: AreaSpinnerAdapter.OnItemSelectedListener {
override fun onClick() {
addNewAreaDialog()
}
})
I'm newbie in android with kotlin. I have a recycler view with a Linearlayout. When I click over itemView I change the background for select it. But the app changes background for two itemViews. I don't know what happen. This is my code:
MenuActivity
class MenuActivity : AppCompatActivity() {
private val section = SectionParameters.builder().itemResourceId(R.layout.list_item_grid_menu)
.headerResourceId(R.layout.header_layout)
.build()
private val categoryService= CategoriaServiceDbImpl()
private val manageSharedPrefrences = ManageSharedPrefrences()
private var namedbanko = ""
private var defaultSection = 1
private var indexDefaultSection = 0
private var categories = emptyList<Categoria>()
var categoryListAdapter: CategoryListGridRecycleAdapter? = null
var summaryRecycleAdapter: SumaryRecyclerAdapter? = null
var viewSection:View? = null
var posIni:Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu)
namedbanko = manageSharedPrefrences.getValueSharedPreference(SessionEnum.CONNECTION.KEY,SessionEnum.SESSION.KEY,this)
/**
* Secciones
*/
sections(defaultSection,indexDefaultSection)
/**
* Lista de productos
*/
val categoryDefault = this.categories.get(this.indexDefaultSection);
val sectionAdapter = SectionedRecyclerViewAdapter()
val productosService = ProductoServiceDbImpl()
productosService.namedb = namedbanko
val listProducts = productosService.getProductoByTipo(defaultSection)
title_section_selected.text = categoryDefault.nombre
sectionAdapter.addSection(ComponentStatelessMenu(this,"",listProducts,section ))
val recycleView: RecyclerView = recyclerlist_menu
val glm = GridLayoutManager(this,2)
glm.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
when (sectionAdapter.getSectionItemViewType(position)) {
SectionedRecyclerViewAdapter.VIEW_TYPE_HEADER -> return 2
else -> return 1
}
}
}
//recycleView.layoutManager = LinearLayoutManager (this)
recycleView.layoutManager = glm
recycleView.setNestedScrollingEnabled(true)
recycleView.adapter = sectionAdapter
val recyclerViewSummary : RecyclerView = recycler_summary
val layoutManager = LinearLayoutManager(this)
recyclerViewSummary.layoutManager =layoutManager
this.summaryRecycleAdapter = SumaryRecyclerAdapter(this)
recyclerViewSummary.adapter = this.summaryRecycleAdapter
}
fun sections(selectedSection:Number,position:Int){
this.categoryListAdapter = CategoryListGridRecycleAdapter(this,selectedSection)
val layoutSections = LinearLayoutManager(this)
layoutSections.orientation = LinearLayoutManager.HORIZONTAL
recycler_sections_menu.layoutManager = layoutSections
recycler_sections_menu.overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS
if(this.categories.isEmpty()){
this.categories = getSections()
}else{
var i = 0
while(i<this.categories.size){
this.categories.get(i).selected = StateEnum.N.VALUE
i++
}
}
categoryListAdapter?.setCategoryList(this.categories)
recycler_sections_menu.adapter = categoryListAdapter
if(position > 0){
recycler_sections_menu.scrollToPosition(position.toInt()-1)
}
/*val namedb = connectionService.getNameDb(this.applicationContext)
categoryService.namedb = namedb
val listCategory = categoryService.listProductByCategory(0)
val section_category = SectionParameters.builder().itemResourceId(R.layout.list_item_section)
.headerResourceId(R.layout.header_layout)
.build()
val sectionAdapterCategory : SectionedRecyclerViewAdapter = SectionedRecyclerViewAdapter()
sectionAdapterCategory.addSection(CategoriasStatelessSection(getString(R.string.title_sections),listCategory,section_category))
val recycleView: RecyclerView = recycler_sections_menu
val lm = LinearLayoutManager(this)
lm.orientation = LinearLayoutManager.HORIZONTAL
recycleView.layoutManager = lm
recycleView.setNestedScrollingEnabled(true)
recycleView.adapter = sectionAdapterCategory*/
}
fun refreshProductsSection(category: Categoria){
val sectionAdapter : SectionedRecyclerViewAdapter = SectionedRecyclerViewAdapter()
val productosService = ProductoServiceDbImpl()
productosService.namedb = namedbanko
val listProducts = productosService.getProductoByTipo(category.codigo)
sectionAdapter.addSection(ComponentStatelessMenu(this,"",listProducts,section ))
val recycleView: RecyclerView = recyclerlist_menu
val glm = GridLayoutManager(this,2)
glm.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
when (sectionAdapter.getSectionItemViewType(position)) {
SectionedRecyclerViewAdapter.VIEW_TYPE_HEADER -> return 2
else -> return 1
}
}
}
//recycleView.layoutManager = LinearLayoutManager (this)
recycleView.layoutManager = glm
recycleView.setNestedScrollingEnabled(true)
recycleView.adapter = sectionAdapter
}
fun changeColorSelectedSection(view: View,position: Int){
if(this.viewSection!=null){
this.viewSection!!.setBackgroundResource(0)
}
view.setBackgroundColor(getColor(R.color.colorSectionSelected))
categoryListAdapter!!.notifyDataSetChanged()
this.viewSection = view
}
fun getSections():List<Categoria>{
categoryService.namedb = namedbanko
return categoryService.listCategorias()
}
}
The MenuActivity class saves the last itemView selected, then It refreshes it.
This activity has the function changeColorSelectedSection that notifies the change. This is my Adapter for Recycle:
class CategoryListGridRecycleAdapter(val menuActivity: MenuActivity,val categorySelected:Number):RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var listSections = listOf<Categoria>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return CategoryListViewHolder(menuActivity, LayoutInflater.from(parent.context).inflate(R.layout.list_item_section,parent,false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val categoryViewHolder = holder as CategoryListViewHolder
/*if(this.categorySelected == listSections[position].codigo)
{
listSections[position].selected = StateEnum.S.VALUE
}else{
listSections[position].selected = StateEnum.N.VALUE
}*/
categoryViewHolder.onBindItemView(listSections[position],position)
}
override fun getItemCount(): Int = listSections.size
fun setCategoryList(listOfCategory:List<Categoria>){
this.listSections = listOfCategory
}
}
The bind for item is into CategoryListViewHolder:
class CategoryListViewHolder(val menuActivity: MenuActivity, itemCategoryView:View): RecyclerView.ViewHolder(itemCategoryView) {
/**
* Función que le coloca las características a la sección dibujada
* #param itemSection Objeto con la infornación de la categoria
* #param position Posición de la categoria que se está configurando
*/
fun onBindItemView(itemSection: Categoria, position: Int){
itemView.title_section_menu.text = itemSection.nombre
/**
* Cargar imagen BLOB
*/
val blob:ByteArray? = itemSection.imagen
try {
itemView.imgSection.scaleType = ImageView.ScaleType.CENTER_INSIDE
itemView.imgSection.adjustViewBounds = true
if(blob!=null) {
val inputStream = blob!!.inputStream()
itemView.imgSection.setImageBitmap(BitmapFactory.decodeStream(inputStream))
}else{
itemView.imgSection.setImageResource(R.drawable.btn_star)
}
}catch (e:Exception){
print("Error onBindItemView "+e.message)
}
/**
* Click para cargar los prodictos de la sección
*/
itemView.setOnClickListener {
view -> actionSection(view,itemSection,position)
}
}
/**
* Función que cambia el fondo de selección
* #param itemSection Objeto de la sección seleccionada
* #param view Vista del front que se seleccionó
* #param position Índice del objeto seleccionado
*/
private fun actionSection(view: View,itemSection: Categoria,position: Int){
menuActivity.changeColorSelectedSection(view,position)
}
}
You're using a RecyclerView, which recycles its views. So when you are changing the background of a specific view and that view is used again when you scroll down in the list, the background will be the same as it is currently set for that item. For example, if I see 5 items on my screen, and I click on item 1 making it selected, the view for item 1 is now selected. But when I scroll down to item 6 and item 1 goes off screen, the view for item 1 is reused for item 6, and is still in its state.
In order to counter this, you should not be keeping track of the selected view but rather the selected item, and then update the view according to which item it represents. In a RecyclerView, one view is not for one item, it is used for multiple items.
Here's a solution with minimal code changes:
MenuActivity
var selectedPosition: Int = -1
...
fun changeColorSelectedSection(position: Int) {
selectedPosition = position
categoryListAdapter?.notifyDataSetChanged()
}
CategoryListViewHolder
...
fun onBindItemView(itemSection: Categoria, position: Int) {
...
val backgroundResourceId = if (position == menuActivity.selectedPosition) R.color.colorSectionSelected else 0
itemView.setBackgroundResource(backgroundResourceId)
}
I am implementing RecyclerView and want to get details of selected items.
I am following a tutorial given here. But I want to get some string key instead of item position.
For example, if i do like this:
for (selection in selectionTracker?.selection!!)
Log.e("tag", selection.toString())
I get indexes as output, but I want to get string keys here.
But I don't know what further changes should be made if I do like this:
fun getItemDetails() = object: ItemDetailsLookup.ItemDetails<Long>() {
override fun getSelectionKey() = itemId
override fun getPosition() = adapterPosition
}
and change it into:
fun getItemDetails() = object: ItemDetailsLookup.ItemDetails<Long>() {
override fun getSelectionKey() = myData[adapterPosition].myKey // a string
override fun getPosition() = adapterPosition
}
----EDIT----
These are my codes:
The adapter class:
class AdapterSubjectsIndexRV (
private val indexList: ArrayList<ModelSubjectsIndex>,
val itemClick: (String) -> Unit
): RecyclerView.Adapter<AdapterSubjectsIndexRV.MyViewHolder>() {
// every recycler view item has unique id
init {
setHasStableIds(true)
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val courseValue = itemView.findViewById<TextView>(R.id.course_value)!!
val courseCode = itemView.findViewById<TextView>(R.id.course_code)!!
val courseName = itemView.findViewById<TextView>(R.id.course_name)!!
val progressValue = itemView.findViewById<TextView>(R.id.progress_value)!!
val progressBar = itemView.findViewById<ProgressBar>(R.id.progress_bar)!!
val selectedOverlay = itemView.findViewById<View>(R.id.subjects_card_view_selected)!!
// set click events
init {
itemView.setOnClickListener {
itemClick(courseCode.text.toString())
}
}
// get item details
fun getItemDetails() = object: ItemDetailsLookup.ItemDetails<String>() {
// override fun getSelectionKey() = itemId
override fun getSelectionKey() = indexList[adapterPosition].courseCode
override fun getPosition() = adapterPosition
}
}
// lookup class
class MyItemDetailsLookup(private val rv: RecyclerView): ItemDetailsLookup<String>() {
override fun getItemDetails(e: MotionEvent): ItemDetails<String>? {
val v = rv.findChildViewUnder(e.x, e.y)
return if (v != null) {
(rv.getChildViewHolder(v) as MyViewHolder).getItemDetails()
} else null
}
}
// set tracker
var tracker: SelectionTracker<Long>? = null
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AdapterSubjectsIndexRV.MyViewHolder {
// create a new view
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.subjects_card, parent, false)
return MyViewHolder(itemView)
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.courseValue.text = indexList[position].courseValue
holder.courseCode.text = indexList[position].courseCode
holder.courseName.text = indexList[position].courseName
holder.progressValue.text = "${indexList[position].progress}%"
holder.progressBar.progress = indexList[position].progress
// Highlight the item if it's selected
holder.selectedOverlay.visibility = if (tracker!!.isSelected(position.toLong())) View.VISIBLE else View.INVISIBLE
}
// Return the size of your data set (invoked by the layout manager)
override fun getItemCount() = indexList.size
override fun getItemId(position: Int): Long {
return position.toLong()
}
}
And this is how I am setting my fragment:
val rvAdapter = AdapterSubjectsIndexRV(getSubjectsIndexList(subjectsList)) {
// if not in selection mode
if (selectionTracker?.selection?.size() == 0) {
listener.showSubjectDetails(it)
}
}
// set recycler view
val recyclerView = theView.findViewById<RecyclerView>(R.id.subjects_recycler_view)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(activity)
adapter = rvAdapter
}
// set selection tracker
selectionTracker = SelectionTracker
.Builder<Long>(
"subjects_index_selection",
recyclerView,
StableIdKeyProvider(recyclerView),
AdapterSubjectsIndexRV.MyItemDetailsLookup(recyclerView),
StorageStrategy.createLongStorage()
).withSelectionPredicate(
SelectionPredicates.createSelectAnything()
).build()
rvAdapter.tracker = selectionTracker
if(savedInstanceState != null)
selectionTracker?.onRestoreInstanceState(savedInstanceState)
return theView
Change the generic type from <Long> to <String>, then you will be able to return a string key.
fun getItemDetails() = object: ItemDetailsLookup.ItemDetails<String>() {
override fun getSelectionKey() = myData[adapterPosition].myKey
// ...
}
I am a little bit confused by your code, but the best way to get the details is to do it on the `onBindViewHolder method. Call your on click method and then within that do your method to get the string.