How to change attribute of view programatically from the view in my recyclerView in my fragment? - android

I set the margin of the view (card view) in my xml of my item file, this xml item file will be used in for my recyclerView adapter.
As you can see in my xml below, that I have given margin to top, bottom, start and end. and I want to change the margin from my fragment
Here is my xml file, item_category_list.xml:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
android:id="#+id/cardView_item_category_list" android:layout_marginStart="8dp" android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp" android:layout_marginTop="8dp">
<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="wrap_content"
android:background="#android:color/background_light">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
app:srcCompat="#drawable/logo_apps"
android:id="#+id/categoryImageView_Item"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="24dp"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="24dp"
app:layout_constraintDimensionRatio="w,1:1" android:scaleType="centerCrop"/>
<TextView
android:text="#string/Category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/categoryName_textView_item"
app:layout_constraintTop_toBottomOf="#+id/categoryImageView_Item"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="4dp"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="4dp"
android:textAlignment="center"
android:minLines="1"
android:maxLines="2"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="10sp"
app:autoSizeMaxTextSize="15sp"
app:autoSizeStepGranularity="1sp"
android:layout_marginBottom="24dp"
android:layout_marginTop="24dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Here is the adapter:
class CategoryAdapter(val context: Context, val categories: List<Category>) : RecyclerView.Adapter<CategoryAdapter.ViewHolderCategory>() {
private lateinit var mListener : CategoryAdapterListener
interface CategoryAdapterListener {
fun onItemClick(position: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderCategory {
val layoutInflater = LayoutInflater.from(parent.context)
val itemView = layoutInflater.inflate(R.layout.item_category_list,parent, false)
return ViewHolderCategory(itemView,mListener)
}
override fun getItemCount(): Int {
return categories.size
}
override fun onBindViewHolder(holder: ViewHolderCategory, position: Int) {
val category = categories[position]
holder.categoryNameTextView.text = category.name
Glide
.with(context)
.load(category.getFormattedImageURL())
.into(holder.categoryImageView)
}
inner class ViewHolderCategory(itemView: View, listener: CategoryAdapterListener) : RecyclerView.ViewHolder(itemView) {
val categoryImageView = itemView.findViewById<ImageView>(R.id.categoryImageView_Item)
val categoryNameTextView = itemView.findViewById<TextView>(R.id.categoryName_textView_item)
val cardView = itemView.findViewById<CardView>(R.id.cardView_item_category_list)
init {
itemView.setOnClickListener {
val position = adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position)
}
}
}
}
fun setCategoryAdapterListener(listener: CategoryAdapterListener) {
mListener = listener
}
}
and in the fragment, I set the adapter to the recycler view:
val categoryAdapter = CategoryAdapter(mContext,parentCategory)
val layoutManager = GridLayoutManager(mContext,4,RecyclerView.VERTICAL,false)
recyclerViewParentCategory.adapter = categoryAdapter
recyclerViewParentCategory.layoutManager = layoutManager
recyclerViewParentCategory.setHasFixedSize(true)
I want to change that margin in card view in my item_category_list.xml programatically in my java/kotlin file (in my fragment file), so I can change the margin from my fragment.
So how can I achieve it ? Java/Kotlin any language is preferred.

First Of all its a long way . So i'm just suggesting a way .
First of all . In your Fragment when some action happen you need to change cardview
size in adapter list item xml.
So . You need a interface for that (Let's say interface ChangeMargin). create
interface in Fragment and implement that interface in your adapter like this
class CategoryAdapter(val context: Context, val categories: List<Category>):RecyclerView.Adapter<CategoryAdapter.ViewHolderCategory>(),ChangeMargin()
For how to create interface so can go through this
Now in that interface you need to get cardview and assign new margin .
#Override
public void ChangeMargin() {
val linear_params=LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT)
linear_params.setMargins(leftMargin,topmargin,rightMargin,bottomMargin)
cardView?.layoutParams=linear_params
}
and don't forget to notify adapter

You can do something like this.
Make id of cardview , create instance of it in your adapter and do this code
ViewGroup.MarginLayoutParams layoutParams =
(ViewGroup.MarginLayoutParams) myCardView.getLayoutParams();
layoutParams.setMargins(10, 10, 10, 10);
myCardView.requestLayout();

To set margins to the cardView, you will have to create layoutParams, set margins to it and then set it as cardView LayoutParams like:
inner class ViewHolderCategory(itemView: View, listener: CategoryAdapterListener) : RecyclerView.ViewHolder(itemView) {
val categoryImageView = itemView.findViewById<ImageView>(R.id.categoryImageView_Item)
val categoryNameTextView = itemView.findViewById<TextView>(R.id.categoryName_textView_item)
val cardView = itemView.findViewById<CardView>(R.id.cardView_item_category_list)
//Main code here
val lparams=LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT)
lparams.setMargins(leftMargin,topmargin,rightMargin,bottomMargin)
cardView?.layoutParams=lparams
}

Related

listview items are not showing when i set the height to wrap or match or 0dp, they only show up when i use specific number

my listview has a relative layout parent, it is set to wrap hight and match width, the problem is in the listview height, when i set it to 100dp it works fine, the items show, but when i set it to wrap or match parent it clips and only show one or non of the items, i can see that there is a scroll bar at the side as well, how can i make it wrap?
<RelativeLayout
android:id="#+id/expandable_rl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/xlarge">
<ListView
android:id="#+id/lisview"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
app:layout_constraintVertical_bias="1.0"
android:layout_alignParentBottom="true"
app:layout_constraintHorizontal_bias="0.0" />
</RelativeLayout>
and this is how i am setting it, its just to test it, its located in a recycler view
holder.list.adapter = ArrayAdapter(holder.itemView.context, R.layout.simple_item, arrayListOf("hello","hi","testing"))
this is how i expand the expandable layout
holder.itemView.setOnClickListener {
if (unitsList[position].isExpandable) {
holder.expandableRL.visibility = if (holder.expandableRL.visibility == View.GONE) View.VISIBLE else View.GONE
}
}
i tried using notifyItemChanged(position) but it made it expand then immediately collapse for some reason
i am new here and don't know how to fix this at the moment
A fully wrapped list means it doesn't scroll, as all of items are visible.
If that is the case, why using a ListView in the first place.
Here is a suggestion to make use of LinearLayout instead.
XML for RecyclerView item:
<androidx.constraintlayout.widget.ConstraintLayout
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"
>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Click Me" />
<LinearLayout
android:id="#+id/expandable_rl"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:orientation="vertical">
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
And Here's the adapter:
class RecyclerAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.recycler_item,
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as? ViewHolder)?.itemView?.let { itemView ->
val expandable = itemView.findViewById<LinearLayout>(R.id.expandable_rl)
createItems(expandable)
itemView.findViewById<Button>(R.id.button).setOnClickListener {
expandable.visibility = View.VISIBLE
}
}
}
private fun createItems(expandable: LinearLayout) {
listOf("Hi", "Hello", "Goodbye").forEach { word ->
val item = createItem(expandable.context, word)
expandable.addView(item)
}
}
private fun createItem(context: Context, word: String): View {
return LinearLayout(context).apply {
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
addView(
TextView(context).apply {
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
text = word
}
)
}
}
override fun getItemCount(): Int {
return 30
}
class ViewHolder(view: View): RecyclerView.ViewHolder(view)
}
This is a basic design, but you can take it from here and design what you need.

Different width of each horizontal RecyclerViews items

I get a problem with my horizontal RecyclerView. I need to create RecyclerView with different width of each item. I use wrap_content for this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
android:id="#+id/recyclerItemLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardPreventCornerOverlap="false"
app:cardCornerRadius="#dimen/_10sdp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
app:cardElevation="0dp"
app:cardBackgroundColor="#android:color/darker_gray"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp">
<TextView
android:id="#+id/recyclerItemText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:textSize="#dimen/_17sdp"
android:text="test"
android:textColor="#color/colorKeyboardRecyclerViewItemText"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_marginTop="7dp"
android:layout_marginBottom="7dp"/>
</androidx.cardview.widget.CardView>
But when I scroll recyclerview and get to the first element I got this:
I think it is because the adapter redraws items every time. Here is code of my adapter:
class KeyboardAdapter(private val fontsNames: FontsData, private val fontButtonCallback: (Int) -> Unit): RecyclerView.Adapter<KeyboardAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.keyboard_recyclerview_item, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return fontsNames.fontsArrayEn.count()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemText.text = fontsNames.fontsArrayEn[position].name
val selectedColor = holder.itemLayout.context.resources.getColor(R.color.colorKeyboardRecyclerViewSelectedItem)
val backgroundColor = holder.itemLayout.context.resources.getColor(android.R.color.transparent)
holder.itemLayout.setOnClickListener{
fontButtonCallback(position)
changeIsSelectedState(position)
fontsNames.fontsArrayEn[position].isSelected = true
notifyDataSetChanged()
}
/* holder.itemLayout.post{ val itemHeight = holder.itemLayout.height.toFloat()
val itemRadius = itemHeight /2.5
holder.itemLayout.radius = Utils().intToDp(holder.itemLayout.context, itemRadius.toFloat())} */
if (fontsNames.fontsArrayEn[position].isSelected)
holder.itemLayout.setCardBackgroundColor(selectedColor)
else
holder.itemLayout.setCardBackgroundColor(backgroundColor)
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val itemLayout = itemView.findViewById<CardView>(R.id.recyclerItemLayout)!!
val itemText = itemView.findViewById<TextView>(R.id.recyclerItemText)!!
}
private fun changeIsSelectedState(position: Int){
for (i in 0 until fontsNames.fontsArrayEn.count()){
fontsNames.fontsArrayEn[i].isSelected = i == position
}
}
}
And i have one more question. How I can set cardCornerRadius dynamically depends of item height ?
Thanks in advance!
The TextView inside the card is the problem.
The text view is match_parent
android:layout_width="match_parent"
android:layout_height="match_parent"
But the parent is wrap_content.
Change the TextView to wrap_content and then every word is gonna be the size of the TextView and the CardView will have the size of the child.

Error in RecyclerViewAdapter's onBindViewHolder() Method ㅠㅠ [duplicate]

Why do I get a NullPointerException in my ViewHolder's bindItems() method?
I've highlighted the line where I get the NullPointerException. The blogpost_author ID exists, as you can see in the XML, so what's the problem here? How is findViewById<TextView>(R.id.blogpost_author) returning null?
Adapter and ViewHolder code:
class BlogPostAdapter(val blogList: ArrayList<BlogPost>) : RecyclerView.Adapter<BlogPostAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : BlogPostAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.blog_post_list, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return blogList.size
}
override fun onBindViewHolder(holder: BlogPostAdapter.ViewHolder, position: Int) {
holder.bindItems(blogList[position])
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(blogPost: BlogPost) {
val blogPostAuthor = itemView.findViewById<TextView>(R.id.blogpost_author) // THIS LINE - NULL POINTER EXCEPTION
val blogPostTitle = itemView.findViewById<TextView>(R.id.blogpost_title)
blogPostAuthor.text = blogPost.author
blogPostTitle.text = blogPost.title
}
}
}
Activity code:
class BlogPostListActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.blog_post_list)
// Get the RecyclerView from XML itself
val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
// Add a layout manager - What does a layout manager do?
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
// Create an array list to store blogposts using the the data class blogPost
val blogPosts = ArrayList<BlogPost>()
// Add some dummy data to the list
blogPosts.add(BlogPost(123, "First Blog Post", "John"))
blogPosts.add(BlogPost(456, "Second Blog Post", "Bob"))
blogPosts.add(BlogPost(789, "Third Blog Post", "Mary"))
// Create an adapter
val adapter = BlogPostAdapter(blogPosts)
// Add the adapter to the recyclerview
recyclerView.adapter = adapter
}
}
Kotlin data class:
data class BlogPost(val id: Int, val title: String, val author: String)
XML for RecyclerView:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
tools:context="com.topzap.android.kotlinlistapptest.BlogPostListActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
XML for CardView layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/blogpost_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="AuthorPlaceHolder"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Large"
/>
<TextView
android:id="#+id/blogpost_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="TitlePlaceHolder"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
You may be inflating the wrong layout within your RecyclerView.
This line within your onCreateViewHolder method:
val v = LayoutInflater.from(parent.context).inflate(R.layout.blog_post_list, parent, false)
You are inflating the blog_post_list.xml, which I'm assuming is the wrong layout file due to the fact you're also inflating that layout within your BlogPostListActivity here:
setContentView(R.layout.blog_post_list)
So when this line is called:
val blogPostAuthor = itemView.findViewById<TextView>(R.id.blogpost_author)
It is looking for the id 'blogpost_author' within R.layout.blog_post_list and as you can see there is no blogpost_author TextView within that layout so it returns null.
To sort it out, it should be straight forward and just change the layout resource that you're assigning to each ViewHolder within your onCreateViewHolder method with the correct layout for your CardView layout.
Which means the line should read something like:
val v = LayoutInflater.from(parent.context).inflate(R.layout.your_card_layout, parent, false)

Image gets replaced in recylerview while scrolling, android?

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
}

Android RecyclerView Adapter DataBinding - cannot find symbol {layout}BindingImpl

I have a Fragment that displays a list of cities with weather informations. I am using a RecyclerView and I am trying to implement the Data Binding Library in my RecyclerView Adapter but for some reason I get this compile error :
> error: cannot find symbol import
com.example.zach.weatherapp.databinding.CityListItemBindingImpl;
> ^
> symbol: class CityListItemBindingImpl
> location: package com.example.zach.weatherapp.databinding
It's an auto generated class so i really don't know where the error is. I had the same error previously for other layouts when there was someting wrong in the xml file but here it seems fine.
ForecastAdapter.kt
package com.example.zach.weatherapp.Adapter
import ...
class ForecastAdapter(var myDataset: List<City>) :
RecyclerView.Adapter<ForecastAdapter.ForecastViewHolder>() {
var context:Context?=null
// 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.
class ForecastViewHolder(var binding: CityListItemBinding) : RecyclerView.ViewHolder(binding.root){
fun bind(city: City){
binding.city = city
}
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): ForecastAdapter.ForecastViewHolder {
context = parent.context
val layoutIdForListItem = R.layout.city_list_item
val inflater = LayoutInflater.from(context)
val shouldAttachToParentImmediately = false
val binding = DataBindingUtil.inflate<CityListItemBinding>(inflater,layoutIdForListItem,parent,shouldAttachToParentImmediately)
//val view = inflater.inflate(layoutIdForListItem, parent, shouldAttachToParentImmediately)
return ForecastViewHolder(binding)
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(holder: ForecastViewHolder, position: Int) {
val city = myDataset[position]
holder.bind(city)
Glide.with(context)
.load("http://openweathermap.org/img/w/${city.weather[0].icon}.png")
.into(holder.binding.forceastImageView)
holder.binding.container.setOnClickListener{ view: View ->
Timber.d("Clicked on city %s",city.name)
Navigation.findNavController(view).navigate(ListFragmentDirections.actionListFragmentToForecastDetailsFragment(city.id))}
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = myDataset.size
}
city_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="city" type="com.example.zach.weatherapp.data.City"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/container">
<TextView
tools:text="Caen"
android:text="#{city.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="#+id/city_name_textview"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="16dp"
android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent"
android:fontFamily="#font/roboto_light" android:textSize="22sp" android:textStyle="bold"
android:maxLines="1" android:ellipsize="end"/>
<TextView
tools:text="Sunny"
android:text="#{city.weather[0].description}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/city_forecast_textview" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="16dp"
app:layout_constraintTop_toBottomOf="#+id/city_name_textview" android:fontFamily="#font/roboto_light"
android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent"/>
<ImageView
android:layout_width="48dp"
android:layout_height="48dp" app:srcCompat="#drawable/sunny"
android:id="#+id/forceast_imageView" android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent" android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintVertical_bias="0.562"
android:layout_marginEnd="32dp" app:layout_constraintEnd_toStartOf="#+id/temperatures_layout"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="#+id/temperatures_layout"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="16dp" android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
tools:text="15°"
android:text="#{city.main.temp_max}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="#+id/max_temperature_textview"
android:fontFamily="#font/roboto_light"
tools:layout_editor_absoluteY="17dp" tools:layout_editor_absoluteX="313dp"/>
<TextView
tools:text="9°"
android:text="#{city.main.temp_min}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/min_temperature_textview"
android:fontFamily="#font/roboto_light" tools:layout_editor_absoluteY="45dp"
tools:layout_editor_absoluteX="321dp" android:layout_gravity="right"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
It might just be an Android Studio error because the xml file seems fine.
UPDATE :
Error seems to come from Xml. I removed the android:text="#{city.xxx}" in my xml layout and instead updated my textViews manually in my ViewHolder bind method like so :
fun bind(boundCity: City){
with(binding){
cityNameTextview.text = boundCity.name
cityForecastTextview.text = boundCity.weather[0].description
maxTemperatureTextview.text = "${boundCity.main.temp_max}°"
minTemperatureTextview.text = "${boundCity.main.temp_min}°"
Glide.with(root.context)
.load("http://openweathermap.org/img/w/${boundCity.weather[0].icon}.png")
.into(forceastImageView)
container.setOnClickListener{ view: View ->
Timber.d("Clicked on city %s",boundCity.name)
Navigation.findNavController(view).navigate(ListFragmentDirections.actionListFragmentToForecastDetailsFragment(boundCity.id))}
}
}
And I no longer get the error. The error comes whenever I add android:text="#{city.xx}" in my textviews and bind the city variable in the bind method. I still don't know why though....
This should work for you I believe;
class ForecastAdapter(private var myDataset: List<City>) : RecyclerView.Adapter<ForecastAdapter.ForecastViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ForecastAdapter.ForecastViewHolder {
val itemBinding = CityListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ForecastViewHolder(itemBinding)
}
override fun onBindViewHolder(holder: ForecastViewHolder, position: Int) {
val city = myDataset[position]
holder.bind(city)
}
override fun getItemCount() = myDataset.size
inner class ForecastViewHolder(var binding: CityListItemBinding) : RecyclerView.ViewHolder(binding.root){
fun bind(boundCity: City){
with(binding) {
city = boundCity
Glide.with(root.context)
.load("http://openweathermap.org/img/w/${city.weather[0].icon}.png")
.into(forceastImageView)
container.setOnClickListener { view ->
Timber.d("Clicked on city %s", city.name)
Navigation.findNavController(view).navigate(ListFragmentDirections.actionListFragmentToForecastDetailsFragment(city.id))
}
}
}
Hey you could try adding the following line after the <data> tag :
<import type="android.view.View" />
I found that worked for me when I had that error.

Categories

Resources