So I initially have 6 items in my RecyclerView. When I add an item I got a toast that's says that new item is added and shows that adapter items increased. But the new item is a duplicate of the item "6". Then I add to more items and ther are all "6". Then I scroll up and down and I see items "byButton"(that's the name of button added by clicking a button) that are between those duplicates of "6". And after a while the whole RecycleView reset and I still have 6 items just like at the beginning. I don't know what's wrong with my code.
class ConnectDeviceUI(val listAdapter: DeviceListAdapter): AnkoComponent<ConnectBleActivity> {
lateinit var addItemButton: FloatingActionButton
override fun createView(ui: AnkoContext<ConnectBleActivity>): View = with(ui) {
return relativeLayout() {
lparams(width= matchParent, height = matchParent)
textView("List of BLE devices"){
setTextAppearance(android.R.style.TextAppearance_Material_Large)
}
addItemButton = floatingActionButton {
imageResource = android.R.drawable.ic_input_add
}.lparams{
margin = dip(10)
alignParentBottom()
alignParentEnd()
alignParentRight()
gravity = Gravity.BOTTOM or Gravity.END
}
recyclerView(){
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)
lparams(width= matchParent, height = matchParent)
adapter = listAdapter
}
}
}
}
class RowLayout(): AnkoComponent<ViewGroup>{
override fun createView(ui: AnkoContext<ViewGroup>): View = with(ui) {
return linearLayout(){
lparams(width= matchParent, height = wrapContent)
setPadding(0,dip(50),0,dip(50))
textView {
id = R.id.ble_item
setTextAppearance(android.R.style.TextAppearance_Material_Large)
setPadding(0,0,dip(100),0)
}.lparams(width = wrapContent, height = wrapContent )
button{
id = R.id.ble_item_button
}.lparams(width = wrapContent, height = wrapContent)
}
}
}
class ConnectBleActivity : AppCompatActivity(), AnkoLogger {
lateinit var BleDevicesList: ArrayList<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
BleDevicesList = arrayListOf("1", "2","3", "4", "5", "6")
var adapter = DeviceListAdapter(BleDevicesList)
var ui = ConnectDeviceUI(adapter)
ui.setContentView(this)
ui.addItemButton.onClick {
adapter.put()
toast("New item added. Number of items: ${adapter.itemCount} ")
}
}
}
class DeviceListAdapter(var deviceList: ArrayList<String>): RecyclerView.Adapter<DeviceListHolder>(){
override fun onBindViewHolder(holder: DeviceListHolder?, position: Int) {
holder?.bindItems(deviceList[position])
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): DeviceListHolder {
return DeviceListHolder(RowLayout().createView(AnkoContext.create(parent!!.context, parent)))
}
override fun getItemCount(): Int {
return deviceList.size
}
fun put(){
val randomString = UUID.randomUUID().toString()
deviceList.add(deviceList.lastIndex, "byButton")
notifyItemInserted(deviceList.lastIndex)
}
fun drop(){
deviceList.removeAt(deviceList.lastIndex)
notifyItemRemoved(deviceList.lastIndex)
}
}
class DeviceListHolder(var view: View): RecyclerView.ViewHolder(view){
val name: TextView = view.find(R.id.ble_item)
val bt_name: Button = view.find(R.id.ble_item_button)
fun bindItems(listItem: String){
name.text = listItem
bt_name.text = "Test"
}
}
Using List.lastIndex() after modifying the list itself, results in different values being updated in the model and the view
deviceList.add(deviceList.lastIndex, "byButton")
notifyItemInserted(deviceList.lastIndex)
The notification tells the RecyclerView to update the last item only. This contains a "6" while the old position is not updated at all. To resolve this issue, you have to use the same index for both.
val index = deviceList.lastIndex
deviceList.add(index, "byButton")
notifyItemInserted(index)
Related
I am new to alert dialogs and was hoping somebody could help me with this. I want to develop a single choice alert dialog and have it show in a recyclerview textview along side an incremental counter.
I have searched all types of documentation but all I can find is how to display the single choice item in either a Toast or a single text view.
I know the code I have is incorrect, but after numerous other attempts, this is the closest I got to getting the result I am seeking. I was able to get it to set the most recent choice but then the other choices change into what look like memory allocations after the button is pressed.
Screenshot:
Here is my code:
Main Activity (I realize that tv_choice.setText(multiItems[i]) is part of the problem it in my dialogAlert(). This is what I need help with.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val itemsList = generateItemsList()
private val adapter = MyAdapter(itemsList)
var count = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(false)
binding.button.setOnClickListener {
addItemsToRecyclerView()
}
}
private fun generateItemsList(): ArrayList<Items> {
return ArrayList()
}
fun addItemsToRecyclerView() {
val addItems = Items(getCount(), "Your Choice Is:", dialogAlert())
itemsList.add(addItems)
adapter.notifyItemInserted(itemsList.size - 1)
}
private fun getCount(): String {
count += 1
return count.toString()
}
fun dialogAlert(): String {
val multiItems = arrayOf("Item 1", "Item 2", "Item 3")
val singleChoice = AlertDialog.Builder(this)
.setTitle("Choose one:")
.setSingleChoiceItems(multiItems, 1) { dialogInterface, i ->
tv_choice.setText(multiItems[i])
}
.setPositiveButton("ok") { _, _ ->
}
.create()
singleChoice.show()
val singleChoiceString = singleChoice.toString()
return singleChoiceString
}
}
The Adapter:
class MyAdapter(private val rvDisplay: MutableList<Items>) : RecyclerView
.Adapter<MyAdapter.AdapterViewHolder>(){
class AdapterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val textView1: TextView = itemView.findViewById(R.id.tv_count)
val textView2: TextView = itemView.findViewById(R.id.tv_choice_string)
val textView3: TextView = itemView.findViewById(R.id.tv_choice)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AdapterViewHolder {
val myItemView = LayoutInflater.from(parent.context).inflate(
R.layout.rv_items,
parent, false
)
return AdapterViewHolder(myItemView)
}
override fun onBindViewHolder(holder: MyAdapter.AdapterViewHolder, position: Int) {
val currentDisplay = rvDisplay[position]
holder.itemView.apply {
holder.textView1.text = currentDisplay.count
holder.textView2.text = currentDisplay.choiceString
holder.textView3.text = currentDisplay.choice
}
}
override fun getItemCount() = rvDisplay.size
}
While you tried to add the dialog's selected value to the recycler view, what you actually did was adding the dialogAlert() returned value to the recycler view.
Instead of "adding" an item when the button is clicked, you should add the item once the dialog is closed. So first present the dialog:
binding.button.setOnClickListener {
dialogAlert()
}
Remove the return value from dialogAlert() method and then, when selecting an option from the dialog, add it to the recycler view:
fun dialogAlert() {
val multiItems = arrayOf("Item 1", "Item 2", "Item 3")
val singleChoice = AlertDialog.Builder(this)
.setTitle("Choose one:")
.setSingleChoiceItems(multiItems, 1) { dialogInterface, i ->
addItemsToRecyclerView(multiItems[i])
}
.create()
singleChoice.show()
}
Change the method to receive a String (your item):
fun addItemsToRecyclerView(item: String) {
val addItems = Items(getCount(), "Your Choice Is:", item)
itemsList.add(addItems)
adapter.notifyItemInserted(itemsList.size - 1)
}
Note that I did not run this code so it might need some adjustments.
I have an arraylist (called Itemlist) of all recyclerview elements. In each element there are 2 textviews - a german and english word. only one of them is shown (because they overlap). when i click on the element it shows the other language (for example: the german word is set to gone and the english word is visible now).
Now I want a function which sets all english textviews (in every element) to gone and the german to visible. My problem is - i dont know how to reach all elements in this arraylist and check the visibility of the textviews. in my example it resets only the first word.
For better understanding
Here is the code:
fun reset_to_EN() {
ItemList.forEach { test_if_german() }
}
OR
fun reset_to_EN2() {
for (item in ItemList) {
test_if_german()
}
}
Check visibility
fun test_if_german(){
if (text_view_de.visibility == View.VISIBLE) {
text_view_en.visibility = View.VISIBLE
text_view_de.visibility = View.GONE
}
adapter.notifyDataSetChanged()
}
If you can please show me a code example for better understanding.
Thanks to everyone who tries to help.
Or here is the whole code for the adapter and mainActivity if it's needed:
class Adapter(
val c: Context,
private val ArrList: ArrayList<Item>):
RecyclerView.Adapter<Adapter.ViewHolder>()
{
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
return ViewHolder(inflater)
}
override fun getItemCount() = ArrList.size
inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v), View.OnClickListener {
var textViewDe: TextView = v.text_view_de
var textViewEn: TextView = v.text_view_en
private var menueImage: Button
init {
v.setOnClickListener(this)
textViewDe = v.findViewById(R.id.text_view_de)
textViewEn = v.findViewById(R.id.text_view_en)
menueImage = v.findViewById(R.id.menu_button)
menueImage.setOnClickListener { popupMenu(it) }
}
private fun popupMenu(v:View) {
val drop = PopupMenu(c, v)
val position = ArrList[adapterPosition]
drop.inflate(R.menu.drop_menu)
drop.setOnMenuItemClickListener {
when(it.itemId){
R.id.edit_menu->{
val v2 = LayoutInflater.from(c).inflate(R.layout.add_item_layout,null)
val DE = v2.findViewById<EditText>(R.id.editText)
val EN = v2.findViewById<EditText>(R.id.editText2)
AlertDialog.Builder(c)
.setView(v2)
.setPositiveButton("Ok"){
dialog,_->
position.Englisch = DE.text.toString()
position.Deutsch = EN.text.toString()
notifyDataSetChanged()
//Toast.makeText(c,"User Information is Edited",Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
.setNegativeButton("Cancel"){
dialog,_->
dialog.dismiss()
}
.create()
.show()
true
}
R.id.delete_menu-> {
ArrList.removeAt(adapterPosition)
notifyDataSetChanged()
//Toast.makeText(c,"entfernt",Toast.LENGTH_SHORT).show()
true
}
else -> true
}
}
drop.show()
val popup = PopupMenu::class.java.getDeclaredField("mPopup")
popup.isAccessible = true
val menu = popup.get(drop)
menu.javaClass.getDeclaredMethod("setForceShowIcon",Boolean::class.java)
.invoke(menu,true)
}
override fun onClick(p0: View?) {
if (textViewDe.visibility == View.VISIBLE) {
textViewDe.visibility = View.GONE
textViewEn.visibility = View.VISIBLE
} else {
textViewDe.visibility = View.VISIBLE
textViewEn.visibility = View.GONE
}
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = ArrList[position]
holder.textViewDe.text = currentItem.Deutsch
holder.textViewEn.text = currentItem.Englisch
}
And MainActivity:
class MainActivity : AppCompatActivity() {
//DEFINITION
private lateinit var addButton: FloatingActionButton
private lateinit var ItemList: ArrayList<Item>
private lateinit var recy: RecyclerView
private lateinit var adapter: Adapter
//ONCREATE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//FINDVIEWBYID
addButton = findViewById(R.id.addingBtn)
ItemList = ArrayList()
recy = findViewById(R.id.recycler_view)
//RECYCLERVIEW
adapter = Adapter(this, ItemList)
recy.layoutManager = LinearLayoutManager(this)
recy.adapter = adapter
//FUNCTION-CALL
addButton.setOnClickListener { addInfo() }
}
//FUNKTIONENS
private fun addInfo() {
val inflter = LayoutInflater.from(this)
val v = inflter.inflate(R.layout.add_item_layout, null) //
val eng = v.findViewById<EditText>(R.id.editText)
val deu = v.findViewById<EditText>(R.id.editText2)
val addDialog = AlertDialog.Builder(this)
addDialog.setView(v)
addDialog.setPositiveButton("OK"){ dialog, _->
val eng2 = eng.text.toString()
val deu2 = deu.text.toString()
val UUID = UUID.randomUUID()
ItemList.add(Item(UUID, eng2, deu2))
adapter.notifyDataSetChanged()
//Toast.makeText(this, "Adding Success", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
addDialog.setNegativeButton("Cancel"){ dialog, _->
dialog.dismiss()
}
addDialog.create()
addDialog.show()
}
fun clearData() {
ItemList.clear()
adapter.notifyDataSetChanged()
Toast.makeText(this, "Alles gelöscht", Toast.LENGTH_SHORT).show()
}
fun reset_all_EN() {
//ArrayList = ItemList
val size: Int = ItemList.size
for (i in 0 until size) {
if (text_view_de.visibility == View.VISIBLE) {
text_view_en.visibility = View.VISIBLE
text_view_de.visibility = View.GONE
}
adapter.notifyDataSetChanged()
}
}
fun reset_to_EN() {
// using forEach() method
ItemList.forEach { test_if_german() }
}
fun reset_to_EN2() {
for (item in ItemList) {
test_if_german()
}
}
fun test_if_german(){
if (text_view_de.visibility == View.VISIBLE) {
text_view_en.visibility = View.VISIBLE
text_view_de.visibility = View.GONE
}
adapter.notifyDataSetChanged()
}
//MENU CLASSES
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.open_menu -> {
val intent = Intent(this, InfoActivity::class.java)
startActivity(intent)
}
R.id.open_menu2 -> {
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
}
R.id.reset_all -> {
reset_to_EN2()
}
}
return super.onOptionsItemSelected(item)
}
}
Since I don't see any declaration of text_view_de or text_view_en, I'm guessing you're using synthetic view properties from the deprecated Android Kotlin Extensions. Assuming that is the case:
When you use text_view_de, it is performing a search in your view hierarchy for the first view it finds with the matching ID. So even though you are doing it within a for loop that iterates through your list of items, you are only working with the same view, over and over.
Edit:
I realized you want to be able to toggle individual views and you were only asking how to add a button to reset all views back to the same language. If this is the case, it does not make sense to add a property to the adapter that controls the state of all views at once like I had suggested in the previous revision of this answer.
Instead, you need to change your data model to have a Boolean that determines which specific language that specific item should show. The problem with how you're doing it now in your click listener is that it is trying to use the Views themselves to determine what state the item is when you change it, but this will cause weird glitches when items scroll off of the screen and back on because ViewHolders get recycled and assigned to different items when they go off and back on screen.
To get started, add a Boolean for the state of the item to your Item class. I don't know exactly what your class looks like now, so adapt this as needed:
data class Item (
val UUID: Long,
val english: String,
val deutsch: String,
var isShowDeutch: Boolean = true
)
A good practice is to have your Adapter class expose a callback for items being clicked so the outside class (Activity) is responsible for manipulating the data model and the Adapter's responsibility is limited to connecting data to views, not manipulating data. So create a callback that the Activity can implement that toggles a single Item's isShowDeutsch property. And when you bind data to a view, use that item's isShowDeutsch to determine visibility.
In Adapter class:
var onItemClickListener: ((itemPosition: Int)->Unit)? = null
//...
// In ViewHolder:
override fun onClick(view: View) {
itemClickListener?.invoke(adapterPosition)
}
//...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = ArrList[position]
holder.textViewDe.text = currentItem.Deutsch
holder.textViewEn.text = currentItem.Englisch
holder.textViewDe.isVisible = currentItem.isShowDeutsch
holder.textViewEn.isVibible = !currentItem.isShowDeutsch
}
In your Activity when you set up your adapter, you can define a click listener for it that toggles the state of that single item and notifies the adapter of the change:
//RECYCLERVIEW
adapter = Adapter(this, ItemList)
recy.layoutManager = LinearLayoutManager(this)
recy.adapter = adapter
adapter.onItemClickListener = { position ->
ItemList[position].apply { isShowDeutsch = !isShowDeutsch }
adapter.notifyItemChanged(position)
}
And finally, to reset all items back to their original language, you can iterate the items in your list and then notify the adapter. This is more appropriate to do in your Activity, since the Adapter should not be responsible for manipulating data.
fun resetLanguage() {
for (item in ItemList) {
item.isShowDeutsch = true
}
adapter.notifyDataSetChanged()
}
I also recommend you change lateinit var ItemList: ArrayList<Item> to val ItemList = ArrayList<Item>(). It is error prone to have a mutable list type in a mutable var property because there are two different ways to change it and it creates the possibility of having your adapter looking at a different list than the one your Activity is working with.
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)
}
}
}
How can I use setOnClickListener in each item in my ListView?
my xml :
<ListView
android:id="#+id/tv1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
in your kotlin activity:
override fun onCreate(savedInstanceState: Bundle?) {
val listView: ListView = findViewById(R.id.yourListViewId)
listView.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, i, l ->
//YOUR CODE HERE
}
}
Nothing like getting to the party late. We are posting this answer because we struggled with setting a OnLongClickListener in our RecyclerAdapter Why because as you enter the code if the RETURN value is not included before adding the lines of code between the opening statement and the return the compiler complains and one would think they are just wrong here is a little code hope it helps anyone new to OnLongClickListener
class PersonRecyclerAdapter(contactList: List<Contact>, internal var context: Context) : RecyclerView.Adapter<PersonRecyclerAdapter.ViewHolder>() {
private var contactList: List<Contact> = ArrayList()
init { this.contactList = contactList }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.new_single_card,parent,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return contactList.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val items = contactList[position]
holder.item.text = items.name
holder.bindCheckBox()
// This code calls the function below in the inner class
// too much code manipulation
holder.list_new_card.setOnLongClickListener { view ->
holder.ckBox.isChecked = false
holder.ckBox.isEnabled = true
holder.item.text = items.name
true
}
/*holder.list_new_card.setOnClickListener {
holder.ckBox.isChecked = false
holder.ckBox.isEnabled = true
holder.item.text = items.name
//val i = Intent(context, MainActivity::class.java)
//i.putExtra("Mode", "E")
//i.putExtra("Id", items.id)
//i.putExtra("ET",items.name)
//i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
//context.startActivity(i)
// This code attaches a listener to the tvName in the new_single_card.xml
}*/
holder.editCLICK.setOnClickListener {
val i = Intent(context, MainActivity::class.java)
i.putExtra("FROM", "U")
i.putExtra("MainActId",items.id)
i.putExtra("ET",items.name)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(i)
}
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var item: TextView = view.findViewById(R.id.tvName) as TextView
var list_new_card: CardView = view.findViewById(R.id.list_new_card) as CardView
var editCLICK: RelativeLayout = view.findViewById(R.id.editCLICK) as RelativeLayout
var ckBox:CheckBox = view.findViewById(R.id.ckBox)as CheckBox
// This is how you declare a instance of the Widiget you want to work with
fun bindCheckBox(){// Create function and BIND it in the onBindViewHolder function
ckBox.setOnCheckedChangeListener { view,isChecked ->
if(ckBox.isChecked){
item.visibility = View.VISIBLE
item.setTextColor(Color.parseColor("#FF0000"))
item.text = "Click & HOLD Me to View Item"
ckBox.isEnabled = false
}else
item.setTextColor(Color.parseColor("#000000"))
}
}
}
}
Note different ways to include listeners in RecyclerAdapter
I've been trying to make RecyclerView work in my app where the list items are ImageViews, and the images get downloaded and put inside (asynchronously) in the onBindViewHolder method. I'm not facing any errors in my code, but for some reason
only the list items which will be visible (even partially) to the user
when the activity loads, have images loaded into them.
Though I can't see the images, I observed that the height and width of these items have been allocated correctly. And since the images get downloaded first, and then the ImageView's dimensions are determined I figure that the problem has got something to do with RecyclerView itself? If someone can shed some light on this, it would be great. Thanks.
I would also like to add, that if the Activity is paused and then resumed (by clicking on the "square" navigation button and then resuming it), the images of all the list items load correctly.
Pic #1
Pic #2
Here's my code:
onCreate method:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
recyclerView {
id = ViewID.ID_LIST
}
val imgList = ArrayList<ImageView>()
imgList.add(ImageView(ctx))
imgList.add(ImageView(ctx))
imgList.add(ImageView(ctx))
imgList.add(ImageView(ctx))
val lv = findViewById(ViewID.ID_LIST) as RecyclerView
lv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
lv.adapter = ImageRecyclerAdapter(ctx, imgList)
}
The RecyclerView.Adapter class:
private class ImageRecyclerAdapter(val context: Context, val imageList: ArrayList<ImageView>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onViewRecycled(holder: RecyclerView.ViewHolder?) {
super.onViewRecycled(holder)
if (holder != null) {
val v = holder.itemView as ImageView
v.setImageBitmap(null)
}
}
override fun onBindViewHolder(p: RecyclerView.ViewHolder, position: Int) {
val v = p.itemView as ImageView
Ion.with(v)
.load("https://pbs.twimg.com/profile_images/616076655547682816/6gMRtQyY.jpg")
.setCallback({ exception, t ->
if (t != null) {
val dm = Point()
context.windowManager.defaultDisplay.getRealSize(dm)
val w = t.maxWidth
val h = t.maxHeight
val params = t.layoutParams
if (params != null) {
params.width = dm.x
params.height = (dm.x * (h.toDouble() / w.toDouble())).toInt()
t.layoutParams = params
t.requestLayout()
}
}
})
}
override fun getItemCount(): Int {
return imageList.size
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
val v = ImageView(context)
return object : RecyclerView.ViewHolder(v) {}
}
}
It worked after I made the binding of data into a Synchronous request, and I moved the ImageView manipulation (changing LayoutParams) into the onViewAttachedToWindow overridden method of my adapter.
onViewAttachedToWindow:
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder?) {
super.onViewAttachedToWindow(holder)
val t = holder?.itemView as ImageView
val dm = Point()
context.windowManager.defaultDisplay.getRealSize(dm)
val w = t.maxWidth
val h = t.maxHeight
val params = t.layoutParams
if (params != null) {
params.width = dm.x
params.height = (dm.x * (h.toDouble() / w.toDouble())).toInt()
t.layoutParams = params
t.requestLayout()
}
}
onBindViewHolder:
override fun onBindViewHolder(p: RecyclerView.ViewHolder, position: Int) {
val v = p.itemView as ImageView
Ion.with(v)
.load(imageList[position].toString())
.tryGet()
}