Change Alpha/Opacity of Recycleradapter - android

I'm using a RecyclerAdapter for the first time. I implemented it via a tutorial and it works fine so far. The way I'm using it is like a popup, so you click on a button and this button changes the opacity of the RecyclerView to 0.8 so it get's visible. Now I want to make the whole RecyclerView invisible after Clicking on an RecyclerItem. Cause the RecyclerView calls another Class "RecyclerAdapter" I'm wondering how I can address the RecyclerView there.
class RecyclerAdapter(private var titles: List<String>, private var details: List<String>, private var images:List<Int>) : RecyclerView.Adapter<RecyclerAdapter.ViewHolder>(){
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val itemTitle: TextView = itemView.findViewById(R.id.ks_title)
val itemDetail: TextView = itemView.findViewById(R.id.ks_descr)
val itemImage: ImageView = itemView.findViewById(R.id.ks_image)
init {
itemView.setOnClickListener { v: View ->
val position: Int = adapterPosition
Toast.makeText(
itemView.context,
"Kartensatz # ${position + 1} gewählt",
Toast.LENGTH_SHORT
).show()
SpielEinstellungen.kartensatz = adapterPosition + 1
// -> NEED TO CHANGE ALPHA OF RECYCLERVIEW TO 0 HERE )
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.kartensaetze,parent,false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return titles.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemTitle.text = titles[position]
holder.itemDetail.text = details[position]
holder.itemImage.setImageResource(images[position])
}
}

The best way is described in this answer: Is there a better way of getting a reference to the parent RecyclerView from the adapter?
lateinit var recycler: RecyclerView
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
recycler = recyclerView
}
You introduce a local variable in the RecyclerAdapter which is initialized when the onAttachedToRecyclerView is called, then you can use that.
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val itemTitle: TextView = itemView.findViewById(R.id.ks_title)
val itemDetail: TextView = itemView.findViewById(R.id.ks_descr)
val itemImage: ImageView = itemView.findViewById(R.id.ks_image)
init {
itemView.setOnClickListener {
Toast.makeText(itemView.context,
"Kartensatz # ${adapterPosition + 1} gewählt",
Toast.LENGTH_SHORT).show()
SpielEinstellungen.kartensatz = adapterPosition + 1
recycler.alpha(0f)
}
}
}

Related

Kotlin RecyclerView delete only removes bottom row

Recyclerview contains a photo and some text. Normal use case is that when the cardview is clicked the photo is selected. However, user might want to delete the photo from the list. There is an icon in the cardview (btnDelete) that can be clicked to delete a photo based on a selectClickListener in the adapter. The correct item is deleted from the database table. If the recyclerView is reloaded the correct photos are included. However, when the user is in the recyclerView and clicks a delete icon the clicked picture stays visible but the bottom cardview on the list disappears. This happens whether one card is "deleted" or numerous cards are "deleted". The bottom card is always deleted.
RecyclerView is populated from sqlite.
Regardless if removeAt is used the bottom cardview is removed when the delete key is clicked.
Tried numerous alternatives including removeAt, notifyItemRemoved, notifyItemRangeChanged. Nothing worked. Some options would reshuffle the cards so that duplicates show, deleted cards come back, etc. Wondering if it is the GlobalScope throwing everything off?
class PhotoAdapter constructor(
viewModel: TheViewModel,
val clickListener: (DBClasses.photos) -> Unit
): RecyclerView.Adapter<PhotoAdapter.CardViewHolder>() {
lateinit private var idPhotoID: TextView
lateinit private var idUploaded: TextView
lateinit private var idStatus: TextView
lateinit private var idPic: ImageView
lateinit private var idDelete: ImageView
val vh = viewModel
var data = mutableListOf<DBClasses.photos>()
set(value) {
field = value
notifyDataSetChanged()
}
inner class CardViewHolder (val binding: PhotoViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(photo: DBClasses.photos, clickListener: (DBClasses.photos) -> Unit) {
itemView.setOnClickListener { clickListener(photo) }
binding.btnDelete.setOnClickListener(){
removeItem(bindingAdapterPosition, vh)
data.removeAt(bindingAdapterPosition)
notifyDataSetChanged()
}
}
}
override fun getItemCount() = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val binding = PhotoViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
idPhotoID = binding.photoId
idUploaded = binding.tvUploaded
idStatus = binding.tvStatus
idPic = binding.imageView
idDelete = binding.btnDelete
return CardViewHolder(binding)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
var gpath: String = "/storage/self/primary/Android/data/com.prod.TheAppName/files/Pictures"
val parentDirectory = path
val dirFileObj = File(parentDirectory)
val item = data[position]
Picasso.get()
.load(File(dirFileObj.toString() + File.separator + item.photo_name))
.resize(225,150)
.centerCrop()
.into(idPic)
idPhotoID.text = item.photo_id.toString()
val rawdate: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-d HH:mm:ss.SSS", Locale.ENGLISH)
val actualdate = LocalDate.parse(item.upload_date, rawdate).toString()
idUploaded.text = actual-date
idStatus.text = item.status
holder.bind(data[position],clickListener)
}
fun removeItem(position: Int, viewModel: TheViewModel) {
val positionID = data[position].photo_id
GlobalScope.launch () {
viewModel.inactivateRecyclerViewPhotos(positionID)
}
}
}

How to implement onClickListener for a specific element inside RecyclerView itemView in Kotlin Android? [duplicate]

This question already has answers here:
RecyclerView onClick
(49 answers)
Closed 1 year ago.
I want to implement an onClickListener for the followButton inside an item in a RecylerView. I haven't managed to find any tutorial/question which uses the way I followed and am completely clueless about the required approach in Kotlin.
Here is the code for the adapter class where I have just managed to successfully implement an onItemClickListener for the itemView.
class adapterClass(private val exampleList : List<objectClass>, private val listener : onItemClickListener) : RecyclerView.Adapter<adapterClass.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.example_item, parent, false)
return ViewHolder(itemView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = exampleList[position]
val url: String = currentItem.imageResourceLink
val circularProgressDrawable = CircularProgressDrawable(holder.itemView.context)
circularProgressDrawable.strokeWidth = 10f
circularProgressDrawable.centerRadius = 100f
circularProgressDrawable.start()
GlideApp.with(holder.itemView.context).load(url).circleCrop().placeholder(circularProgressDrawable).error(R.drawable.error).fallback(R.drawable.fallback).transition(DrawableTransitionOptions.withCrossFade()).into(holder.imageView)
holder.textView1.text = currentItem.text1
holder.textView2.text = currentItem.text2
}
override fun getItemCount(): Int = exampleList.size
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView), View.OnClickListener{
val imageView: ImageView = itemView.findViewById(R.id.imageView)
val textView1: TextView = itemView.findViewById<TextView>(R.id.textView)
val textView2: TextView = itemView.findViewById<TextView>(R.id.textView2)
val followButton: Button = itemView.findViewById(R.id.followButton)
init {
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
val position : Int = adapterPosition
if(position != RecyclerView.NO_POSITION) {
listener.onItemClick(position)
}
}
}
interface onItemClickListener{
fun onItemClick(position:Int)
}
}
If possible, I would like the same way to be followed as is currently used(onClickListener in ViewHolder), to ensure reusability of this adapter throughout the app.
Thanks.
You are setting OnClickListener for itemView which makes the view clickable.. If you want to set OnClickListener for only followButton just set OnClickListner only for followButton.
init {
followButton .setOnClickListener(this)
}

When I delete an item in recyclerview and then add a new item, the items I deleted appear again in my Android App.How can I fix it? Any solution?

When I delete an item in recyclerview and then I add a new item, the items I deleted appear again on my Android app. I used the init in my Adapter to call the setonClickLister. I think that I need to call this code in my Activity but how will ı do ? I use the kotlin and how can ı fix it ? I shared my adapter code below to see clearly, thanx
class NoteAdapter(private var titleText: ArrayList<String>, private var imageButton: ArrayList<String>, private var noteText: ArrayList<String>) : RecyclerView.Adapter<NoteAdapter.ViewHolder>() {
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemTitle : TextView = itemView.findViewById(R.id.recyclerTitleText)
val itemImage : ImageView = itemView.findViewById(R.id.recyclerImage)
val itemDelete : ImageView = itemView.findViewById(R.id.delete)
init {
itemView.setOnClickListener { v: View ->
// Toast.makeText(itemView.context,"You clicked on item # ${position + 1}", Toast.LENGTH_SHORT).show()
val intent = Intent(itemView.context, PastNotesActivity::class.java)
intent.putExtra("oldTitle", titleText[position])
intent.putExtra("oldNote", noteText[position])
intent.putExtra("oldImage", imageButton[position])
itemView.context.startActivity(intent)
}
itemDelete.setOnClickListener { v: View ->
titleText.removeAt(position)
imageButton.removeAt(position)
notifyItemRemoved(position)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recycler_row, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemTitle.text = titleText[position]
Picasso.get().load(imageButton[position]).resize(150,150).into(holder.itemImage)
}
override fun getItemCount(): Int {
return titleText.size
}
}
by the way, ı tried this code, but it does not work
notifyItemRemoved(position)
notifyItemRangeChanged(position, titletext.size)
I have some suggests:
-You shouldn't use inner ViewHolder like that.
-And clarify your activity, adapter and viewholder.
-Create your own Listener or a callback function to handle the action from the viewholder.
-Create your data class/map/... to manage or store your data, shouldn't use like that.
Put button click inside onBindViewHolder:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemTitle.text = titleText[position]
Picasso.get().load(imageButton[position]).resize(150,150).into(holder.itemImage)
val itemDelete : ImageView = itemView.findViewById(R.id.delete)
itemDelete.setOnClickListener { v: View ->
titleText.removeAt(position)
imageButton.removeAt(position)
notifyItemRemoved(position)
}
}

Editing list item on list view

Imagine we have a simple list of items. Each item contains only a short title.
To handle the list we are using RecyclerView with ListAdapter and ViewHolders.
Each item/view is not editable unless we click it.
In this scenario I am using one view model for list and one for item under edit.
Unfortunately all my attempts failed.
I have tried to use two different view holders but the list was flickering, after all inflating view (in this case binding) is heavy.
Another shot I was giving to use the same view holder but with two various bind methods - one binding plain item, second binding with viewmodel instead of data object but it failed as well - suddenly a few rows were editable.
Has anyone solved it ?
class MistakesAdapter(private val editViewModel: MistakeEditViewModel) :
ListAdapter<Mistake, RecyclerView.ViewHolder>(MistakesDiffCallback()) {
companion object{
const val ITEM_PLAIN_VIEW_TYPE = 0
const val ITEM_EDITABLE_VIEW_TYPE = 1
}
private var itemPositionUnderEdit = -1
private val listener = object: MistakeItemListener{
override fun onClick(view: View, position: Int) {
Timber.d("OnClick : edit - $itemPositionUnderEdit, clickPos - $position")
editViewModel.onEditMistake(getItem(position))
itemPositionUnderEdit = position
notifyItemChanged(itemPositionUnderEdit)
}
}
override fun getItemViewType(position: Int) =
when (position) {
itemPositionUnderEdit -> ITEM_EDITABLE_VIEW_TYPE
else -> ITEM_PLAIN_VIEW_TYPE
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
when (viewType) {
ITEM_EDITABLE_VIEW_TYPE -> EditableMistakeViewHolder.from(parent)
else -> MistakeViewHolder.from(parent)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is EditableMistakeViewHolder -> holder.bind(editViewModel, listener)
is MistakeViewHolder -> holder.bind(getItem(position), listener)
else -> throw ClassCastException("Unknown view holder type")
}
}
class MistakeViewHolder private constructor(private val binding: ListItemMistakesBinding) :
RecyclerView.ViewHolder(binding.root) {
companion object {
fun from(viewGroup: ViewGroup): MistakeViewHolder {
val inflater = LayoutInflater.from(viewGroup.context)
val binding = ListItemMistakesBinding.inflate(inflater, viewGroup, false)
return MistakeViewHolder(binding)
}
}
fun bind(item: Mistake, listener: MistakeItemListener) {
binding.apply {
mistake = item
inputType = InputType.TYPE_NULL
this.listener = listener
position = adapterPosition
executePendingBindings()
}
}
}
class EditableMistakeViewHolder private constructor(private val binding: ListItemMistakesBinding)
: RecyclerView.ViewHolder(binding.root) {
companion object{
fun from(viewGroup: ViewGroup): EditableMistakeViewHolder {
val inflater = LayoutInflater.from(viewGroup.context)
val binding = ListItemMistakesBinding.inflate(inflater, viewGroup, false)
return EditableMistakeViewHolder(binding)
}
}
fun bind(viewModel: MistakeEditViewModel, listener: MistakeItemListener){
binding.apply {
this.viewModel = viewModel
inputType = InputType.TYPE_CLASS_TEXT
this.listener = listener
position = adapterPosition
root.setBackgroundColor(Color.GRAY)
}
}
}
}
class MistakeEditViewModel(private val repository: MistakesRepository) : ViewModel() {
#VisibleForTesting
var mistakeUnderEdit: Mistake? = null
//two-way binding
val mistakeName = MutableLiveData<String>()
fun onEditMistake(mistake: Mistake) {
mistakeUnderEdit = mistake
mistakeName.value = mistake.name
}
}
By changing my approach to the problem I solved it.
I make all list items editable but at the same time I am following focus.
To cut the long story short, I invoke item view model methods with help of OnFocusChangeListener and TextWatcher on my editTexts.

(Kotlin) Position of RecyclerView returns -1 when trying to click on an item

I'm new to Android development (and Kotlin).
I'm trying to implement a RecyclerView (which works fine) and when I click on a specific row it opens a new activity (Intent).
However, whenever I've press/click on one of the rows, I'm only able to get the value "-1" returned.
I've tried a number of different approaches (you should see the number of tabs in my browser).
This seems like it should be a fairly straightforward occurrence for something as common as a RecyclerView, but for whatever reason I'm unable to get it working.
Here is my RecyclerView Adapter file:
class PNHLePlayerAdapter (val players : ArrayList<PNHLePlayer>, val context: Context) : RecyclerView.Adapter<ViewHolder>() {
var onItemClick: ((Int)->Unit) = {}
// Gets the number of items in the list
override fun getItemCount(): Int {
return players.size
}
// Inflates the item views
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(context).inflate(
R.layout.pnhle_list_item,
parent,
false
)
val viewHolder = ViewHolder(itemView)
itemView.setOnClickListener {
onItemClick(viewHolder.adapterPosition)
}
return ViewHolder(itemView)
}
// Binds each item in the ArrayList to a view
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.tvPlayerName?.text = players[position].Name
holder.tvPlayerRank?.text = position.toString()
holder.tvPNHLe?.text = players[position].PNHLe.toString()
holder.tvTeam?.text = players[position].Team
holder.ivLeague?.setImageResource(leagueImageID)
}
}
class ViewHolder (view: View) : RecyclerView.ViewHolder(view) {
val linLayout = view.hor1LinearLayout
val ivTeam = view.teamImageView
val tvPlayerName = view.playerNameTextView
val tvPlayerRank = view.rankNumTextView
val tvPNHLe = view.pnhleTextView
val tvTeam = view.teamTextView
val ivLeague = view.leagueImageView
}
As you can see, there is a class property "onItemClick" which uses a lambda as the click callback.
I setOnClickListener in the onCreateViewHolder method after the view is inflated.
Next, in my Activity I add the list to my Adapter and set the call back.
However, every time I 'Toast' the position it is displayed as '-1'.
val adapter = PNHLePlayerAdapter(list, this)
adapter.onItemClick = { position ->
Toast.makeText(this, position.toString(),Toast.LENGTH_SHORT).show()
var intent = Intent(this, PlayerCardActivity::class.java)
//startActivity(intent)
}
rv_player_list.adapter = adapter
Perhaps I'm not thinking about this properly, but shouldn't the position represent the row number of the item out of the RecyclerView???
Ideally, I need to use the position so that I can obtain the correct item from the 'list' (ArrayList) so that I can pass information to my next Activity using the Intent
I found the issue.
Change this line in onCreateViewHolder:
return ViewHolder(itemView)
to this one:
return viewHolder
I would reorganize the adapter like this:
class PNHLePlayerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<Adapter.ViewHolder>() {
interface AdapterListener {
fun onItemSelected(position: Int?)
}
var players: List<Player> = listOf()
set(value) {
field = value
this.notifyDataSetChanged()
}
var listener: AdapterListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_car_selector, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(position)
}
override fun getItemCount(): Int {
return brands.size
}
inner class ViewHolder(view: View): androidx.recyclerview.widget.RecyclerView.ViewHolder(view) {
private var position: Int? = null
private val baseView: LinearLayout? = view.findViewById(R.id.baseView) as LinearLayout?
...
init {
baseView?.setOnClickListener {
listener?.onManufacturerSelected(position)
}
}
fun bind(position: Int) {
this.position = position
...
}
}
}
And from your activity/fragment set the listener as adapter.listener = this, and implement the onItemSelected(position: Int?)
override fun onItemSelected(position: Int?) {
...
}

Categories

Resources