i want set many buttons (i mean clickable views) in item of recyclerView like every item has download,play,stop,delete how can i do that? if i setOnlickListener like holder.download_image.setOnClickListenr(){} its works for all item i want every item has difrent link for download
class RecyclerAdapter(private val soundList: List<SoundItem>,private val mListener: AdapterView.OnItemClickListener?) :
RecyclerView.Adapter<RecyclerAdapter.RecyclerViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.recycler_view, parent, false)
return RecyclerViewHolder(itemView)
}
override fun onBindViewHolder(holder: RecyclerViewHolder, position: Int) {
val currnetItem = soundList[position]
holder.soundNmae.text = currnetItem.soundName
holder.play_image.setImageResource(currnetItem.playImage)
holder.stop_image.setImageResource(currnetItem.stopImage)
holder.download_image.setImageResource(currnetItem.donloadImage)
holder.delete_image.setImageResource(currnetItem.deleteImage)
}
override fun getItemCount() = soundList.size
class RecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val soundNmae = itemView.soundName
val play_image = itemView.play_image
val stop_image = itemView.stop_image
val download_image = itemView.download_image
val delete_image = itemView.delete_image
}
}
this is acivity for recyclerView im new in kotlin sorry if my question is maybe simple or i couldent say if what is my mean
class RelaxSoundActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_relax_sound)
val exampleList=generatorSoundList(500)
recyceler_view.adapter=RecyclerAdapter(exampleList)
recyceler_view.layoutManager=LinearLayoutManager(this)
recyceler_view.setHasFixedSize(true)
}
fun generatorSoundList(size:Int ):List<SoundItem>{
val list=ArrayList<SoundItem>()
for(i in 0 until size){
val drawable=when(i % 5){
0->R.drawable.ic_play_arrow_black_24dp
1->R.drawable.ic_play_arrow_black_24dp
2->R.drawable.ic_play_arrow_black_24dp
3->R.drawable.ic_play_arrow_black_24dp
else->R.drawable.ic_play_arrow_black_24dp
}
val drawable2=when(i % 5){
0->R.drawable.ic_stop_black_24dp
1->R.drawable.ic_stop_black_24dp
2->R.drawable.ic_stop_black_24dp
3->R.drawable.ic_stop_black_24dp
else->R.drawable.ic_stop_black_24dp
}
val drawable3=when(i % 5){
0->R.drawable.ic_file_download_black_24dp
1->R.drawable.ic_file_download_black_24dp
2->R.drawable.ic_file_download_black_24dp
3->R.drawable.ic_file_download_black_24dp
else->R.drawable.ic_file_download_black_24dp
}
val drawable4=when(i % 5){
0->R.drawable.ic_delete_black_24dp
1->R.drawable.ic_delete_black_24dp
2->R.drawable.ic_delete_black_24dp
3->R.drawable.ic_delete_black_24dp
else->R.drawable.ic_delete_black_24dp
}
val item=SoundItem("item $i" ,drawable,drawable2,drawable3,drawable4)
list+=item
}
return list
}
}
and recycler_view.xml file is here
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="wrap_content"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="8dp"
>
<TextView
android:id="#+id/soundName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView"
android:textSize="20dp"/>
<ImageView
android:id="#+id/play_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="#drawable/ic_play_arrow_black_24dp" />
<ImageView
android:id="#+id/stop_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="#drawable/ic_stop_black_24dp" />
<ImageView
android:id="#+id/download_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="#drawable/ic_file_download_black_24dp" />
<ImageView
android:id="#+id/delete_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="#drawable/ic_delete_black_24dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
you can do it in multiple ways. You can add click listeners on your views and directly perform the operation in your adapter or you can transfer function in your recycler view holder class.
So for short cut I can just give you the way that you can understand the process.
In you adapter onBindViewHolder you can add
holder.download_image.setOnCLickListener{
val downloadLink = currnetItem.getDownloadLink()
// Download task start by this download link
}
So this one click listener on download image will be effected on each item and perform separately.
IMO you have to attach an clicklistener to each button, and then you could either make a callback to the adapter/activity and handle it from there on.
If you yous the View.OnClickListener, then you always have the clicked view. From there on, it is just a matter of writing a switch statement, where you can determine via the id of the clicked view, which action was selected.
If you need extra data, you could just add a tag to the view, and pass it via the clickListener.
Related
I am trying to fetch the data from Google Spreadsheet and display it in a recyclerView in Kotlin. I could do that without any error but the issue I am facing is when I scroll up or down the data in the recyclerView get disappeared. When I scroll up and then scroll down I can see that all the data that went up is missing and the same with scrolling down. But if I scroll up for more I can see one line of data after every few scrolls.
Another issue I have is with the date that is being displayed. My data in the Google Spreadsheet starts from 01-Jan-2023 (this is how it's shown in the spreadsheet, and without time in it), when it's shown in the recyclerView, all dates are one day earlier. I mean, it shows 31-Dec-2022 for 01-Jan-2023, 01-Jan-2023 for 02-Jan-2023 and so on.
Can somebody help correct my mistakes and improve my code? I have been after this for a couple of days and I couldn't fix the issue.
My code is,
SalesData.kt
class SalesData : AppCompatActivity() {
private lateinit var binding: ActivitySalesDataBinding
#SuppressLint("NotifyDataSetChanged")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySalesDataBinding.inflate(layoutInflater)
setContentView(binding.root)
val salesList = arrayListOf<SalesDataModel>()
val queue = Volley.newRequestQueue(this)
val url = "https://script.google.com/macros/s/AKfsdaffdbghjhfWVM2FeIH3gZY5kAnb6JVeWpg2XeBOZyU6sghhfkuytytg/exec"
val jsonObjectRequest = object: JsonObjectRequest(
Request.Method.GET,url,null,
Response.Listener {
val data = it.getJSONArray("items")
for(i in 0 until data.length()){
val salesJasonObject = data.getJSONObject(i)
val dt = salesJasonObject.getString("Date")
val dateFmt = SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(dt)
val formattedDatesString = dateFmt?.let { it1 -> SimpleDateFormat("dd-MMM-yyyy", Locale.US).format(it1) }
val salesObject = formattedDatesString?.let { it1 ->
SalesDataModel(
// salesJasonObject.getString("Date"),
it1,
salesJasonObject.getString("Branch"),
salesJasonObject.getDouble("NetSale"),
salesJasonObject.getDouble("Profit"),
)
}
if (salesObject != null) {
salesList.add(salesObject)
}
val adapter = SalesDataRecyclerAdapter(this#SalesData,salesList)
binding.rvSalesData.adapter = adapter
binding.rvSalesData.layoutManager = LinearLayoutManager(this#SalesData)
binding.rvSalesData.setHasFixedSize(true)
adapter.notifyDataSetChanged()
}
Toast.makeText(this#SalesData, "Data loaded successfully", Toast.LENGTH_LONG).show()
},Response.ErrorListener {
Toast.makeText(this#SalesData, it.toString(), Toast.LENGTH_LONG).show()
}
){
override fun getHeaders(): MutableMap<String, String> {
return super.getHeaders()
}
}
Toast.makeText(this#SalesData, "Hi", Toast.LENGTH_LONG).show()
queue.add(jsonObjectRequest)
}
}
SalesDataRecyclerAdapter.kt
class SalesDataRecyclerAdapter(
val context: Context,
private val saleDataList:ArrayList<SalesDataModel>
):RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return MyViewHolder(
SalesDataLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent, false
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val model = saleDataList[position]
if (holder is MyViewHolder){
holder.binding.tvSales.text = model.salesAmount.toString()
holder.binding.tvBranch.text = model.branch
holder.binding.tvDate.text = model.date
holder.binding.tvProfit.text = model.profit.toString()
}
}
override fun getItemCount(): Int {
return saleDataList.size
}
class MyViewHolder(val binding: SalesDataLayoutBinding) : RecyclerView.ViewHolder(binding.root)
}
activity_sales_data.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
tools:context=".SalesData">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!--
<androidx.core.widget.ContentLoadingProgressBar
android:id="#+id/progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/new_green"
android:padding="10dp"
android:text="SALES DATA"
android:textColor="#color/white"
android:textSize="24sp"
android:layout_gravity="bottom|end"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvSalesData"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
sales_data_layout.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="Date"
android:layout_weight="1"/>
<TextView
android:id="#+id/tvBranch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="Branch"
android:layout_weight="1"/>
<TextView
android:id="#+id/tvSales"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="Sales"
android:layout_weight="1"/>
<TextView
android:id="#+id/tvProfit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="Profit"
android:layout_weight="1"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Since your root view in sales_data_layout.xml has the size:
android:layout_width="match_parent"
android:layout_height="match_parent"
Each item will take up the whole parent area, which in your case will end up with each individual item taking up the whole screen, and thus needing multiple scrolls to see the next item. You probably want to change the height to wrap_content for the root view, to see more items on the screen at once.
Add a comparator that tells the recylcer view exactly when to redraw.
class WordsComparator : DiffUtil.ItemCallback<Word>() {
override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean {
//=== here doesn't work for complex objects
// simple high-speed code goes here it is called over and over
// my app the same item has the same id easy compare
return (oldItem._id == newItem._id)
}
override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean { // you developer have to compare the contents of complex objects
// you need high speed code here for best results
// if possible don't call any functions that could do other
// unecessary things.
// compare the contents of the complex items.
return (oldItem._id == newItem._id
&& oldItem.checked == newItem.checked
&& oldItem.word == newItem.word
&& oldItem.color == newItem.color
&& oldItem.recolor == newItem.recolor
&& oldItem.rechecked == newItem.rechecked)
}
}
This is what I created
And what I want is like this below
Actually in here, I want my cards should look like cards in a wallet (as shown in the 2nd image above) which I can scroll like the native stack card view as shown in first image, problem I am facing is I am not able to align cards vertically straight, cards get cut if I try to do so.
I want to achieve this behaviour using Android Native stackview widget only.
My code is as below:
ActivityMain.kt
class MainActivity : AppCompatActivity() {
lateinit var cardAdapter: CardAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val stackView = findViewById<StackView>(R.id.stack_view)
cardAdapter= CardAdapter(numberWord(),numberImage(),R.layout.item_card,this)
stackView.adapter=cardAdapter
}
// the method numberWord() is used to
// add the text below corresponding images.
private fun numberWord(): List<String> {
val word: MutableList<String> = ArrayList()
word.add("One")
word.add("Two")
word.add("Three")
word.add("Four")
word.add("Five")
return word
}
// the method numberWord() is used to call
// the images that are added to the stack.
private fun numberImage(): List<Int>{
val image: MutableList<Int> = ArrayList()
image.add(R.drawable.ic_filter)
image.add(R.drawable.ic_filter)
image.add(R.drawable.ic_filter)
image.add(R.drawable.ic_filter)
image.add(R.drawable.ic_filter)
return image
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<!--We have used RelativeLayout for layout-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">
<!--Add StackView-->
<StackView
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="#+id/stack_view"
android:layoutDirection="ltr"
android:layout_width="400dp"
android:layout_height="300dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
CardAdapter.kt
class CardAdapter
(
var numberWord: List<String>,
var numberImage: List<Int>,
var itemLayout: Int,
var c: Context
) : ArrayAdapter<Any?>(
c, itemLayout, numberWord
) {
// getCount() is called to return
// the total number of words to be used
override fun getCount(): Int {
return numberWord.size
}
// getView() is called to get position,
// parent and view of the images.
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
if (convertView == null) {
convertView = LayoutInflater.from(parent.context).inflate(itemLayout, parent, false)
}
val word = numberWord[position]
val image = numberImage[position]
val textView = convertView!!.findViewById<TextView>(R.id.text_view)
val imageView = convertView.findViewById<ImageView>(R.id.image_view)
textView.text = word
imageView.setImageResource(image)
return convertView
}
}
item_card.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="180dp"
android:background="#drawable/border_bg"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_filter" />
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40sp"
android:textStyle="bold" />
</LinearLayout>
you guys can refer android native stackview: https://developer.android.com/reference/android/widget/StackView
I tried many different solution, I guess we can achieve that with third party library but that's not what I want. I want to create solution with using native android stackview.
Any help will be great.
I'm working on a dynamicViews (not sure if that's the right word for creating a view from a json file).
I'm getting the schema from a JSON file, I've stepped up the recycleView and its adapter, so far so good, each Recycleview item (must or not) contain a number of EditText whose number is unknown in advance, so based on the Json file, I have to inflate inside.
I searched a lot but the similar solution I found for Heterogene Recycleview: the idea was to use separate layout and inflate each of them according to your needs inside onCreateViewHolder but the developer who published the solution knew in advance what is the combination of all possible views and he just switch.
class Adapter_base_Display(private val listener: Display_Fragment,
activity: FragmentActivity ,
liste_display : ArrayList<DisplaySections>)
: RecyclerView.Adapter<Base_DisplayViewHolder>() {
private val activityIns = activity
private val liste_display_Recycle_adapter = liste_display
interface Base_DisplayListener {
fun onClickeddisplay(position: Int)
}
private val items = ArrayList<DisplaySections>()
fun setItems(items: ArrayList<DisplaySections>) {
this.items.clear()
this.items.addAll(items)
notifyDataSetChanged()
}
fun clear() {
val size: Int = items.size
items.clear()
notifyItemRangeRemoved(0, size)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Base_DisplayViewHolder {
val binding: ItemDisplayBinding =
ItemDisplayBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Base_DisplayViewHolder(
binding,
listener as Base_DisplayListener,
activityIns,
parent,
liste_display_Recycle_adapter)
}
override fun getItemCount(): Int = items.size
override fun onBindViewHolder(holder: Base_DisplayViewHolder, position: Int) =
holder.bind(items[position])
}
class Base_DisplayViewHolder(
private val itemBinding: ItemDisplayBinding,
private val listener: Adapter_base_Display.Base_DisplayListener,
private val activityIns: FragmentActivity,
private var parent: ViewGroup,
private val items: ArrayList<DisplaySections>,
) : RecyclerView.ViewHolder(itemBinding.root),
View.OnClickListener {
init {
itemBinding.root.setOnClickListener(this)
}
fun bind(item: DisplaySections) {
itemBinding.textView2.text = item.name
}
override fun onClick(v: View?) {
listener.onClickeddisplay(adapterPosition)
}
}
The EditText I want to inflate multiple time
<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/edittext_isplay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="TextView"
android:maxLines="3"
android:textColor="#color/black"
android:textSize="18sp" />
data class DisplaySections(
val id : Int,
val name : String,
val createdAt : String,
val updatedAt : String,
val displayTypeId : Int,
val displayCustomFields : List<DisplayCustomFields> // Contains the elements that will be displayed as EditText
The Base layout-Recycleview Item which is common for all scenarios
<LinearLayout
android:id="#+id/parent_edittext" // ALl EditText container
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:id="#+id/camera_linear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="#+id/addphoto"
android:layout_width="316dp"
android:layout_height="250dp"
android:layout_gravity="center"
android:layout_marginTop="#dimen/_20sdp"
android:src="#drawable/ajouter_photo"
app:tint="#color/clear_grey" />
<TextView
android:id="#+id/camera_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Ajouter des photos"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/plus_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_20sdp"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/my_photo_recycle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
I going to post the solution I found.
To solve this problem, we absolutely must use a nested RecyclerView;
As I said above, I want to display a list of items with the same common layout (Imageview + Textview), but the tricky part here is the dynamic part of each item.
For recap:
Each element (may or may not) contain N-1 (EditText), it depends on what it gets from a json file.
if you want to solve this problem by creating multiple Viewholder and switch depending on which "ViewHolderType" you are wrong !, you will just create an infinite layout files, it doesn't make sense.
if you create more than one (EditText) and only change the visibility it may work, but if you get for example 100 EditText from the Json file you are not going to manually create 100 Edittext.
if you want to programmatically generate an EditText, you will affect every item in your view Recycle since you cannot create view inside OnbindViewHolder function.
the only way I found to solve this problem is to create a parent-child RecycleView whenever there is an (EditText) you send it to the child adapter and you keep your parent element safe in the parent adapter.
You can also put a condition (NULL tester) inside the Parent-OnbindViewholder whenever there is no data, you just don't call Child-adapter.
I hope this solution will be useful to anyone who has had this problem, and if you have another solution I will be very happy to test them.
I am displaying a list of countries along with their flags in recylerview
The 1st element does not have a image and uses a default image which is visible on launch of page
But when I scroll and come back to it the image gets changed to some random from the list which should not happen
This is my adapter
class CountryAdapter(private val list: MutableList<Data?>?) :
RecyclerView.Adapter<CountryAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ElementCountryBinding.inflate(inflater)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val country: Data? = list?.get(position)
if (country != null) {
holder.bind(country)
}
holder.itemView.setOnClickListener {
}
}
override fun getItemCount(): Int = list!!.size
inner class ViewHolder(val binding: ElementCountryBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(country: Data) {
binding.data = country
if (country.filePath != null)
Glide.with(binding.root.context)
.load(country.filePath!!.trim()).into(binding.ivFlag)
}
}
}
This is the xml layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.mountmeru.model.Data" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="#+id/main_cardview"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginBottom="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_flag"
android:layout_width="100dp"
android:layout_height="70dp"
android:layout_marginStart="10dp"
android:adjustViewBounds="true"
android:src="#drawable/ic_share"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvCountryName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="#{data.countryName}"
app:layout_constraintBottom_toBottomOf="#+id/iv_flag"
app:layout_constraintLeft_toRightOf="#+id/iv_flag"
app:layout_constraintTop_toTopOf="#+id/iv_flag" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
< /RelativeLayout>
</layout>
screenshot
So the default image you specified in your XML layout is the ic_share, this means that when onBindViewHolder is called, the image gets substituted by:
.load(country.filePath!!.trim()).into(binding.ivFlag)
However, you never specified that at position 0, the icon must be ic_share, so because of RecyclerView's nature, when you scroll downwards and upwards and the first itemHolder is created (again) it uses a recycled view from further down, and as you're not setting ic_share to iv_flag at position 0 it just uses the recycled view image.
If you just add a line of code like #ADM suggested in your bind method like this:
if(adapterPosition==0){
binding.ivFlag.setImageResource(R.drawable.ic_share)
}
With the ic_share, I think that should make it work
That's normal due to the recycling mechanism of views in RV/LV. To avoid that set it to null
if (country.filePath != null)
Glide.with(binding.root.context)
.load(country.filePath!!.trim()).into(binding.ivFlag)
else
binding.ivFlag.setImageDrawable(null)
assuming ivFlag is an ImageView, or a default/placeholder if you have it
This is happening because you never set ic_share during bind View.
inner class ViewHolder(val binding: ElementCountryBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(country: Data) {
binding.data = country
if(adapterPosition==0){
binding.ivFlag.setImageResource(R.drawable.binding.ivFlag)
}else {
if (country.filePath != null)
Glide.with(binding.root.context)
.load(country.filePath!!.trim()).into(binding.ivFlag)
}
}
}
Having the function getItemViewType also solves the problem
override fun getItemViewType(position: Int): Int {
return position
}
I'm currently trying to create a dynamic header with a recyclerView. I have written the ListAdapter aswell as the ViewHolder. The custom list elements are added, and also the numer of the elements within the list is correct, but somehow it's not showing the object data, but only the dummyText that was added at the layoutdesign.
HeaderlistAdapter:
class HeaderListAdapter(val context: Context, val headers: List<CustomHeader>) : RecyclerView.Adapter<HeaderViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): HeaderViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.ui_basic_custom_list_element_header, parent, false)
return HeaderViewHolder(view)
}
override fun getItemCount(): Int {
return headers.size
}
override fun onBindViewHolder(holder: HeaderViewHolder?, position: Int) {
holder?.bindHeader(headers[position])
}
fun setFocus(step:UIStep)
{
for(header in headers)
header.Active=header.MainContent==step
notifyDataSetChanged()
}
}
HeaderViewHolder:
class HeaderViewHolder:RecyclerView.ViewHolder{
#Bind(R.id.ui_adapter_main) var mainText:TextView?=null
#Bind(R.id.ui_adapter_additional) var additionalText:TextView?=null
#Bind(R.id.ui_adapter_layout) var layout:LinearLayout?=null
constructor(itemView: View): super(itemView){
ButterKnife.bind(this,itemView)
}
fun bindHeader(header:CustomHeader){
if(header.Active) {
mainText?.text = header.MainContent.description
additionalText?.text=header.AdditionalText
layout?.setBackgroundColor(R.color.colorBackgroundActive.toInt())
}
else{
mainText?.text=header.MainContent.number.toString()
additionalText?.text=""
layout?.setBackgroundColor(R.color.colorBackgroundInactive.toInt())
}
}
}
Here is, how the listAdapter looks within the view
<android.support.v7.widget.RecyclerView
android:id="#+id/ui_basic_lv_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="#color/colorBackgroundInactive"
android:layout_weight="1" />
Below here you se the xml of the custom element
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="#color/colorBackgroundInactive"
android:textColor="#color/colorHeaderFont"
android:id="#+id/ui_adapter_layout">
<TextView
android:id="#+id/ui_adapter_main"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Main Info"
android:textSize="36sp"/>
<TextView
android:id="#+id/ui_adapter_additional"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="additional"
android:gravity="center_vertical"/>
Looks like there was something wrong with the
#Bind
I replaced that by using findViewById within the binHeader function:
fun bindHeader(header:CustomHeader){
val mainText = itemView.findViewById<TextView>(R.id.ui_adapter_main)
val additionalText = itemView.findViewById<TextView>(R.id.ui_adapter_additional)
val layout = itemView.findViewById<LinearLayout>(R.id.ui_adapter_layout)
if(header.Active) {
mainText?.text = header.MainContent.description
additionalText?.text=header.AdditionalText
layout?.setBackgroundColor(R.color.colorBackgroundActive.toInt())
}
else{
mainText?.text=header.MainContent.number.toString()
additionalText?.text=""
layout?.setBackgroundColor(R.color.colorBackgroundInactive.toInt())
}
}
contentList may be null ,if contentList is Null, the method following '?' will not execute . and after setting the adapter can not call notifyDataSetChanged ;
You should set layout manager for recyclerview
myRecyclerView.setLayoutManager(linearLayoutManagerVertical);