I am trying to create a CardView within a RecyclerView but I can't get it to launch since the app crashes after starting with this error "RecyclerView has no LayoutManager". I've tried to apply fixes suggested by other posts regarding the same problem but got no luck so far.
Thank you in advance.
HomeActivity.kt
class HomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
// Retrieves data from source
val arrayList = ArrayList<PreviewCardModel>()
arrayList.add(PreviewCardModel("Product A","500mg / 1000mg", R.drawable.image, 500))
arrayList.add(PreviewCardModel("Product D","Sample", R.drawable.image, 5040))
arrayList.add(PreviewCardModel("Product E","Sample", R.drawable.image, 5500))
arrayList.add(PreviewCardModel("Product F","Sample", R.drawable.image, 2500))
val myAdapter = CardAdapter(arrayList, this)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,false)
recyclerView.adapter = myAdapter
CardAdapter.kt
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.sample.appname.R
import com.sample.appname.model.PreviewCardModel
import kotlinx.android.synthetic.main.preview_card.view.*
class CardAdapter (private val arrayList: ArrayList<PreviewCardModel>, val context: Context) :
RecyclerView.Adapter<CardAdapter.CardViewHolder>() {
class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems (model: PreviewCardModel) {
itemView.previewName.text = model.title
itemView.previewDesc.text = model.desc
itemView.previewPrice.text = model.price.toString()
itemView.previewImage.setImageResource(model.image)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.preview_card, parent, false)
return CardViewHolder(view)
}
// Returns size of data list
override fun getItemCount(): Int {
return arrayList.size
}
// Displays data at a certain position
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
holder.bindItems(arrayList[position])
}
}
activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<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:padding="16dp"
tools:context=".HomeActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#color/browser_actions_title_color"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:orientation="horizontal"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
This is the error I am encountering.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sample.appname, PID: 5333
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sample.appname/com.sample.appname.HomeActivity}: android.view.InflateException: Binary XML file line #54 in com.sample.appname:layout/activity_home: RecyclerView has no LayoutManager androidx.recyclerview.widget.RecyclerView{b2c2d71 VFED..... ......I. 0,0-0,0 #7f09016f app:id/recyclerView}, adapter:null, layout:null, context:com.sample.appname.HomeActivity#5dcb507
preview_card.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="120dp"
android:padding="10sp"
app:cardCornerRadius="3dp"
app:cardElevation="3dp"
app:cardUseCompatPadding="true">
<ImageView
android:id="#+id/previewImage"
android:layout_width="80dp"
android:layout_height="80dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="#drawable/heart"
android:contentDescription="#string/product_image" />
<TextView
android:id="#+id/previewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/product_name"
android:textSize="11sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/previewImage" />
<TextView
android:id="#+id/previewDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SAMPLE"
android:textSize="8sp"
android:textColor="#color/colorPrimary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/previewName"
tools:ignore="SmallSp" />
<TextView
android:id="#+id/previewPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="#string/samplePrice"
android:textColor="#color/colorPrimary"
android:textSize="11sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.cardview.widget.CardView>
This error occurs when you've created same layout for multiple SDK or orientation and not mentioned the view in all the layout files, say for: activity_main.xml(v21)or activity_main(land) and so on. All the layouts should contain all the views with same IDs.
FIX: I had another activity_home(v21) layout that was cause the problems. Make sure you don't have multiple layouts that will cause problems. It was detecting no LayoutManager in the v21 version layout.
Related
So I am trying to create a simple Note App, where the user gives data, gets stored in a database, and is displayed using a recycler view. Up until now, I can confirm that data is being stored in my database, and that data is also being retrieved from it and being initialized to a variable in the adapter class, but for some reason, the Adapter's OnCreateViewHolder(), OnBindViewHolder() and getItemCount() functions are not being called even after notifying the adapter of the change in data. This is my MainActivity and Adapter class.
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: NoteViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val noteAdapter = NotesRVAdapter(this)
notesRV.adapter = noteAdapter
notesRV.layoutManager = LinearLayoutManager(this)
viewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(NoteViewModel::class.java)
//access getAllNotes from NoteViewModel class from created instance
viewModel.getAllNotes.observe(
this,
Observer { list ->
list?.let {
Log.d("TAG","Observing")
NotesRVAdapter(this).updateList(it as ArrayList<NoteEntity>)
// Toast.makeText(this,"$it",Toast.LENGTH_LONG).show()
}
},
)
}
fun createNote(view: View) {
val intent = Intent(this,SecondActivity::class.java) // for creating a note
startActivity(intent)
}
}
Adapter Class
class NotesRVAdapter(private val context: Context) : RecyclerView.Adapter<NotesRVAdapter.NotesVH>() {
private var noteItem = ArrayList<NoteEntity>()
inner class NotesVH(noteView: View): RecyclerView.ViewHolder(noteView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotesVH {
val view = LayoutInflater.from(parent.context).inflate(R.layout.note_item,parent,false)
return NotesVH(view)
}
override fun onBindViewHolder(holder: NotesVH, position: Int) {
holder.itemView.Heading.text = noteItem[position].heading
holder.itemView.Description.text = noteItem[position].text
holder.itemView.Priority.text = noteItem[position].priority.toString()
}
override fun getItemCount(): Int {
return noteItem.size
}
fun updateList(list: ArrayList<NoteEntity>){
noteItem.clear()
noteItem.addAll(list)
// Toast.makeText(context,"${noteItem[0].text}",Toast.LENGTH_LONG).show()
notifyDataSetChanged()
}
}
The updateList function is getting called in mainactivity and the list is being passed in the noteitem and the toast also works, but that's it. All the override functions seem to be not working as I tried running a Log statement in them, but there was no entry for any Log in the Logcat.
I don't think there's a problem in the XML file as I could see the preview using the tools statement, but if someone needs to check it, here it is:
note_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:paddingHorizontal="30dp"
android:paddingVertical="30dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="#+id/Heading"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintRight_toLeftOf="#id/Priority"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text = "Note Heading"
android:textSize="35sp"
android:textStyle="bold"
android:textColor="#color/black"
/>
<TextView
android:id="#+id/Description"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="#id/Heading"
app:layout_constraintRight_toLeftOf="#id/Priority"
tools:text="Description"
android:textSize="25sp"
android:textColor="#color/black"
/>
<TextView
android:id="#+id/Priority"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1"
android:textSize="60sp"
android:textColor="#color/black"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/notesRV"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="0dp"
android:layout_height="0dp"
tools:listitem="#layout/note_item"
/>
<ImageView
android:id="#+id/createNote"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginBottom="80dp"
android:layout_marginRight="40dp"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="#drawable/ic_baseline_add_24"
android:onClick="createNote"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I would appreciate it if someone could help me with this issue. Thanks!
you are creating a new adapter instance here which is not attached to your recyclerview
NotesRVAdapter(this).updateList(it as ArrayList<NoteEntity>)
change it to the one attached to your recyclerview and that will be
noteAdapter.updateList(it as ArrayList<NoteEntity>)
Problem: If the ImageView is VISIBLE and the fragment_list_element_content TextView has only a few lines of text, margins above and below fragment_list_element_text_view_group are too large. If the ImageView is GONE and the fragment_list_element_content TextView has many lines of text, margins above and below fragment_list_element_text_view_group are too small.
xml of my problematic Layout:
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/fragment_list_element_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/roundrect_fragment_list_element_background"
android:elevation="#dimen/fragment_list_element_background_elevation"
android:layout_marginTop="#dimen/fragment_list_element_background_margin_top"
android:layout_marginStart="#dimen/fragment_list_element_background_margin_start"
android:layout_marginEnd="#dimen/fragment_list_element_background_margin_end"
android:layout_marginBottom="#dimen/fragment_list_element_background_margin_bottom"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="#+id/fragment_list_element_image_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/placeholder_image"
android:contentDescription="#string/fragment_list_element_image_view_content_description"
android:adjustViewBounds="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/fragment_list_element_text_view_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/fragment_list_element_textviews_margin_top"
android:layout_marginStart="#dimen/fragment_list_element_textviews_margin_start"
android:layout_marginEnd="#dimen/fragment_list_element_textviews_margin_end"
android:layout_marginBottom="#dimen/fragment_list_element_textviews_margin_bottom"
app:layout_constraintTop_toBottomOf="#id/fragment_list_element_image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="#+id/fragment_list_element_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/default_date_string"
android:textSize="#dimen/fragment_list_element_date_font_size"
android:textColor="#color/font_color_grey"
android:textAllCaps="true"
android:maxLines="1"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="#id/fragment_list_element_title" />
<TextView
android:id="#+id/fragment_list_element_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/default_text"
android:textSize="#dimen/fragment_list_element_title_font_size"
android:textColor="#color/font_color_black"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="#id/fragment_list_element_date"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="#id/fragment_list_element_content" />
<TextView
android:id="#+id/fragment_list_element_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/default_text"
android:textSize="#dimen/fragment_list_element_content_font_size"
android:textColor="#color/font_color_grey"
app:layout_constraintTop_toBottomOf="#id/fragment_list_element_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
inflation of the layout in my RecyclerViewAdapter:
import android.annotation.SuppressLint
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import my.project.R
import java.text.SimpleDateFormat
class MyListAdapter(private val elementList: List<Element>)
: RecyclerView.Adapter<MyListAdapter.ViewHolder>() {
class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val background: ConstraintLayout = view.findViewById(R.id.news_list_element_background)
val imageView: ImageView = view.findViewById(R.id.news_list_element_image_view)
val date: TextView = view.findViewById(R.id.news_list_element_date)
val title: TextView = view.findViewById(R.id.news_list_element_title)
val content: TextView = view.findViewById(R.id.news_list_element_content)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.fragment_list_element,
parent,
false
)
return ViewHolder(itemView)
}
#SuppressLint("SimpleDateFormat")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val element = elementList[position]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.background.clipToOutline = true
}
if (element.thumbnail != null) {
holder.imageView.setImageBitmap(element.thumbnail)
holder.imageView.visibility = View.VISIBLE
} else {
holder.imageView.visibility = View.GONE
}
holder.date.text = SimpleDateFormat("dd. MMMM yyyy").format(element.date)
holder.title.text = element.title
holder.content.text = element.content
}
override fun getItemCount(): Int {
return elementList.size
}
}
Having a layout with android:layout_height="match_parent" directly inside an element with android:layout_height="wrap_content" seems to cause this problem.
Why this doesn't create a build error, throws a RuntimeException during inflation or at least shows a Lint warning is a mystery to me.
I have an issue with my custom adapter (I think) I'm getting my data using retrofit, that comes just fine, once I get the data I call another function to populate my recycle view, as follows.
I really appreciate if some one could help me on this...
private fun createMyOrdersTable(myOrders: List<OrderAssigned>){
val ordersCount = myOrders.size
val rv = myorder_rv
rv.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
val ordersList = ArrayList<OrderAssigned>()
if (ordersCount > 0){
myOrders.forEach {
ordersList.add(it)
}
// order.add(OrderAssigned("123","123213","123123","1231231","123123","123123","123123","123123"))
// order.add(OrderAssigned("123","123213","123123","1231231","123123","123123","123123","123123"))
println(ordersList)
val adapter = CustomAdapterMyOrders(ordersList)
rv.adapter = adapter
}else{
Toast.makeText(context, "You don't have any assigned order", Toast.LENGTH_LONG).show()
}
}
And this is my adapter:
package com.davesm.swiftdemexico
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.davesm.swiftdemexico.Model.OrderAssigned
import kotlinx.android.synthetic.main.myorders_layout.view.*
class CustomAdapterMyOrders(private val orders: ArrayList<OrderAssigned>): RecyclerView.Adapter<CustomAdapterMyOrders.ViewHolder>() {
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val orderID = itemView.orderID!!
val clientName = itemView.clientName!!
val no_rem = itemView.orderRem!!
val orderDate = itemView.orderDate!!
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
//
val v = LayoutInflater.from(parent?.context).inflate(R.layout.myorders_layout, parent, false)
return ViewHolder(v);
}
override fun getItemCount(): Int {
//
return orders.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val model = orders[position]
holder.orderID.text = "ID: "+model.id
holder.clientName.text = model.nom_cte
holder.no_rem.text = "RemisiĆ³n"+model.no_rem
holder.orderDate.text = model.falta_rem
}
}
When I execute my app it shows only one "row" which is a card view even when I add more than one item in the foreach in the "createMyOrdersTable" I had tried to add it manually as in the commented code but still not working, I send the data as an ArrayList.
Here is the xml files for the views:
myorder_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/myorder_rv"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is my items layout.
myorders_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.cardview.widget.CardView
android:id="#+id/cardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="10dp"
app:cardCornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:padding="10dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/rounder_button_primary_color"
tools:ignore="MissingConstraints">
<TextView
android:id="#+id/orderID"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Order ID"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Large" />
<TextView
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:text="Client Name"
android:id="#+id/clientName"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/orderRem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RemisiĆ³n" />
<TextView
android:id="#+id/orderDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Date" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
It is not creating 1 row, it is creating many, but they are all as tall as the screen.
Change your item layout to use wrap_content for the height
<?xml version="1.0" encoding="utf-8"?>
<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">
I have a grid supported by recyclerview inside a ConstraintLayout inside a ScrollView.
Although 20 items are inserted in setList() (I debugged it), only 9 items are displayed when using ScrollView
When I switch to NestedScrollView all 20 items are displayed, but the items in the middle are streched. Not the images, but it seems that there is a background behind streched 3 times the actual size of the item/image.
I'm using androidx libraries.
Fragment layout
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimaryDark"
tools:context=".ui.details.DetailsFragment">
<ImageView
android:id="#+id/detail_backdrop"
android:layout_width="match_parent"
android:layout_height="220dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:scaleType="centerCrop"
android:src="#drawable/clapperboard"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/play_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#+id/detail_backdrop"
app:layout_constraintEnd_toEndOf="#+id/detail_backdrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/detail_backdrop"
app:srcCompat="#drawable/ic_play_circle_outline_white_96dp" />
<ProgressBar
android:id="#+id/details_progress_bar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Some other views...
<TextView
android:id="#+id/tv_my_list_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/my_list_at_details"
app:layout_constraintEnd_toEndOf="#+id/wish_list_btn"
app:layout_constraintStart_toStartOf="#+id/wish_list_btn"
app:layout_constraintTop_toBottomOf="#id/wish_list_btn" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_recommended"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_my_list_details"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
List item layout
<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:id="#+id/movie_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/movie_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/iv_poster"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/clapperboard" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Adapter
package com.lacourt.myapplication.ui.details
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Point
import android.graphics.drawable.Drawable
import android.util.DisplayMetrics
import android.util.Log
import android.view.Display
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.lacourt.myapplication.AppConstants
import com.lacourt.myapplication.R
import com.lacourt.myapplication.dto.DbMovieDTO
import com.lacourt.myapplication.ui.OnItemClick
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.movie_list_item.view.*
class RecommendedAdapter(
private val context: Context?,
private val onItemClick: OnItemClick,
private var list: ArrayList<DbMovieDTO>
) : RecyclerView.Adapter<RecommendedHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecommendedHolder {
val view =
LayoutInflater.from(context).inflate(R.layout.list_item_recommended, parent, false)
return RecommendedHolder(view)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: RecommendedHolder, position: Int) {
Log.d("grid-log", "onBindViewHolder() called, position = $position, list.size = ${list.size}")
// get device dimensions
val displayMetrics = DisplayMetrics()
(context as Activity).windowManager.defaultDisplay.getMetrics(displayMetrics)
val width = displayMetrics.widthPixels
val maxHeight= width.div(3) * 1.5
holder.poster.minimumHeight = maxHeight.toInt()
holder.apply {
Picasso.get()
.load("${AppConstants.TMDB_IMAGE_BASE_URL_W185}${list[position].poster_path}")
.placeholder(R.drawable.clapperboard)
.into(poster)
cardView.setOnClickListener {
val id = list[position].id
if (id != null)
onItemClick.onItemClick(id)
else
Toast.makeText(
context,
"Sorry. Can not load this movie. :/",
Toast.LENGTH_SHORT
).show()
}
}
}
fun setList(list: List<DbMovieDTO>) {
Log.d("grid-log", "setList() called")
this.list.clear()
this.list.addAll(list)
notifyDataSetChanged()
}
}
class RecommendedHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var poster = itemView.iv_poster
var cardView = itemView.movie_card_view
}
Any solutions for this strange behavior?
Since it may help someone in the future, I found a solution:
I just added holder.cardView.layoutParams.height = maxHeight.toInt() to onBindViewHolder of my adapter class and now every item layout is in the correct size.
Since you are using a constraint layout, you should let the constraints set the size, in general.
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_recommended"
android:layout_width="0dp"
android:layout_height="dp"
...
0dp in this case means let the constraints set the value.
I got an error when I scroll down the list view. When scroll reached to bottom of activity, the error occurred. And one strange thing is here. On kotlin code, there is "DataController.getDataList()" function. This function get 10 data list as ArrayList, but I got only 9 data in my emulator. What's wrong with my code?
activity_spiral_test_list.xml
<?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=".spiralTestListActivity"
android:background="#color/Background">
<ListView
android:id="#+id/patientList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ViewStub
android:id="#+id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout="#layout/empty"/>
<android.support.design.widget.FloatingActionButton
android:layout_width="80dp"
android:layout_height="80dp"
android:src="#drawable/add"
android:layout_margin="40dp"
android:scaleType="center"
android:tint="#android:color/white"
android:backgroundTint="#color/Primary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:borderWidth="0dp"/>
</android.support.constraint.ConstraintLayout>
patient_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="30dp"
android:orientation="vertical">
<TextView
android:id="#+id/patientName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Patient"
android:textSize="40sp"
android:textColor="#android:color/black"
android:textStyle="bold"/>
<TextView
android:id="#+id/patientDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Explanation"
android:textSize="25sp"/>
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:layout_marginEnd="40dp"
android:orientation="vertical">
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:src="#drawable/assignment"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
android:textSize="20sp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
spiralTestListActivity.kt
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
import myPackage.DataController
import myPackage.PatientData
import kotlinx.android.synthetic.main.activity_spiral_test_list.*
class spiralTestListActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_spiral_test_list)
patientList.adapter = patientAdapter(this, DataController.getDataList())
patientList.emptyView = empty
}
private inner class ViewHolder {
lateinit var name: TextView
lateinit var description: TextView
}
inner class patientAdapter(context: Context, val listItem: ArrayList<PatientData>) : BaseAdapter() {
private val mInflator: LayoutInflater = LayoutInflater.from(context)
override fun getCount(): Int {
return this.listItem.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Any {
return this.listItem[position]
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view: View
val holder: ViewHolder
if (convertView == null) {
view = mInflator.inflate(R.layout.patient_list_item, parent, false)
holder = ViewHolder()
holder.name = view.findViewById(R.id.patientName) as TextView
holder.description = view.findViewById(R.id.patientDescription) as TextView
}
else {
view = convertView
holder = convertView.tag as ViewHolder
}
val patient = getItem(position) as PatientData
val name = holder.name
val description = holder.description
name.text = patient.name
description.text = patient.description
return view
}
}
}
I solve this problem. This problem is occurred because of thread. Surely, controller of data is adapter. But, I add data in my dialog class.(There are some different part of code above. I changed it..) So, when thread ask to get data from adapter, the data is different with ListView's data. It occurred an error.
I fix the code in my adapter class and dialog class. In the adapter class, I add a function named add.
fun add(data: PatientData) {
DataController.addData(data)
}
Also, there is one more thing. In SpiralTestListActivity.ky, I don't add
convertView.tag = holder
above the else part in Adapter class..!!
These parts make my app work correctly..!