I need to add empty constructor to my Adapter, but i have already primary constructor.
My code:
class RvStatesAdapter(private var stateList: List<State>): RecyclerView.Adapter<RvStatesAdapter.MyViewHolder>() {
inner class MyViewHolder(val binding: RvStateListBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(RvStateListBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return stateList.size
}
I have tried to use costructor(): this() but in this case i dont understand what i need to put in this() brackets
You can make Adapter constructor without params by instead of passing list in primary constructor use function to submit list in adapter.
class RvStatesAdapter(): RecyclerView.Adapter<RvStatesAdapter.MyViewHolder>() {
private val stateList: ArrayList<State> = ArrayList<State>()
/**
* submit list to recycler view adapter for populating items
*/
fun submitList(list: List<State>) {
stateList.addAll(list)
}
inner class MyViewHolder(val binding: RvStateListBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
RvStateListBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return stateList.size
}
}
Submit list using adapter instance
val list = emptyList<State>()
val rvStatesAdapter = RvStatesAdapter()
// init recyclerview properties
rvStatesAdapter.submitList(list)
Related
Where in the code should i be using the following lines to work with my widgets:
binding = WorkoutCardBinding.inflate(layoutInflater)
setContentView(binding.root)
I know it should be used in an activiy's onCreate function but I can't seem to get it to work with the below adapter class
class WorkoutAdaptor (
var workouts: List<Workout>
) : RecyclerView.Adapter<WorkoutAdaptor.WorkoutViewHolder>() {
private lateinit var binding: WorkoutCardBinding
inner class WorkoutViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WorkoutViewHolder {
binding = WorkoutCardBinding.inflate(layoutInflater)
setContentView(binding.root)
val view = LayoutInflater.from(parent.context).inflate(R.layout.workout_card, parent, false)
return WorkoutViewHolder(view)
}
override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
holder.itemView.apply {
binding.tvWorkoutCard.text = workouts[position].
}
}
override fun getItemCount(): Int {
return workouts.size
}
val binding = WorkoutCardBinding.inflate(
LayoutInflater.from(parent.context), parent, false)
return WorkoutViewHolder(binding)
//Change you onCreateViewHolder completely to this code
You don't have to create a binding variable in the adapter class. To use view binding in recyclerView adapter there are a few things that you've to change.
Firstly, change your viewHolder class constructor to accept viewBinding instead of a view
inner class WorkoutViewHolder(private val workoutCardBinding: WorkoutCardBinding) :
RecyclerView.ViewHolder(workoutCardBinding.root) {
fun bind(workout: Workout) {
workoutCardBinding.apply {
// create your view here
}
}
Change onCreateViewHolder, to return a viewHolder object using binding.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WorkoutViewHolder {
val workoutCardBinding=
WorkoutCardBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return WorkoutCardBinding(workoutCardBinding)
}
Your complete adapter class will look like this -
class WorkoutAdaptor (
var workouts: List<Workout>
) : RecyclerView.Adapter<WorkoutAdaptor.WorkoutViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WorkoutViewHolder {
val workoutCardBinding =
WorkoutCardBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return WorkoutCardBinding(workoutCardBinding)
}
override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
holder.bind(workouts[position])
}
override fun getItemCount(): Int {
return workouts.size
}
inner class WorkoutViewHolder(private val workoutCardBinding: WorkoutCardBinding) :
RecyclerView.ViewHolder(workoutCardBinding.root) {
fun bind(workout: Workout) {
workoutCardBinding.apply {
// create your view here
}
}
}
}
TodoAdapter.kt
class TodoAdapter (var todos:List<Todo>) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>(){
inner class TodoViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val view= LayoutInflater.from(parent.context).inflate(R.layout.todo_layout, parent, false)
return TodoViewHolder(view)
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.itemView.apply {
}
}
override fun getItemCount(): Int {
return todos.size
}
}
Above is the Recycler View Adapter Class.
I already have an inner class TodoAdapter. How do I use ViewBinding with this?
The layout file from where I want to access views is todo_layout.xml
I am assuming you are familiar with ViewBinding. Here is how you can use ViewBinding with your RecyclerViewAdapter.
Here will be your TodoAdapter.kt
class TodoAdapter (var todos:List<Todo>) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val binding = TodoLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return TodoViewHolder(binding)
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.bind()
}
override fun getItemCount(): Int {
return todos.size
}
inner class TodoViewHolder(private val binding: TodoLayoutBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(){
binding.apply{
// Assign Values
}
}
}
}
And now inside your TodoViewHolder bind function call, you can access all your views.
It shows like this. DataBindingUtil and getRoot() are shown in red. When I hover over it android studio asks me to create class,enum,interface,etc and for getRoot() it shows to create reference and create an extension function
Primary Constructor Call Expected Error on super(binding.root)
Here's my OnBindViewHolder function code:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val country = countries[position]
var countryInfoCardBinding = DataBindingUtil.setContentView<CountryInfoCardBinding>(context as Activity, R.layout.country_info_card)
countryInfoCardBinding.country = country
}
And here's my XML file:
https://pastebin.com/PySQFLmv
You should inflate your data binding object in onCreateViewHolder, not onBindViewHolder. Now you're inflating an object which has no connection to your view, which is why (I'm assuming) nothing appears
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val country = countries[position]
holder.binding.country = country
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = CountryInfoCardBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return ViewHolder(binding)
}
inner class ViewHolder(val binding: CountryInfoCardBinding) : RecyclerView.Viewholder(binding.root)
I have a problem with:
RecyclerView: No adapter attached; skipping layout
I can't define adapter in OnCreate because the list is not ready.
How I can define adapter in OnCreate? or what is a possible solution for resolve my problem?
In onCreate I did:
adapter = MyAdapter(this#MyActivity)
adapter.data = ArrayList()
Then later I just set adapter.date = xxx
In my adapter I have:
class MyAdapter(val activity: MyActivity) :
RecyclerView.Adapter<MyAdapter.BodyViewHolder>() {
var data: MutableList<MyModel>? = null
set(value) {
field = value
notifyDataSetChanged()
}
override fun getItemCount() = data?.size ?: 0
fun ViewGroup.inflate(#LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View {
return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BodyViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.my_layout, parent, false)
return BodyViewHolder(view)
}
override fun onBindViewHolder(holder: BodyViewHolder, position: Int) {
holder.bindValue(data?.get(position), activity)
}
class BodyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindValue(record: MyModel?, activity: MyActivity) {
record?.let {
itemView.mTextView.text = ....
}
}
}
}
Worth mentioning that the height of my recycler view is wrap_content
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
It's totally ok if you don't have data in onCreate. What you need to do is to define the adapter and bind it with your RecyclerView. Once you have data ready, add data to the list in adapter and notify it. Example as below
class MyAdapter: RecyclerView.Adapter<MyViewHolder>() {
private val data = mutableListOf<MyModel>()
override fun getItemCount() = data.count()
fun addData(data : MyModel) {
// add single data the list or call addAll() to add a group of data.
// just remember not to replace the variable
}
fun clearData() {
}
fun deleteData(id: Int) {
}
}
class adpCoba(val context: Context, val datalist:ArrayList<dataCoba>):RecyclerView.Adapter<adpCoba.MyViewHolder>(){
class MyViewHolder (itemView:View):RecyclerView.ViewHolder(itemView){
val text :TextView=itemView.findViewById(R.id.textcoba)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(context).inflate(R.layout.fetch_coba,parent,false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currntItem = datalist [position]
holder.text.text= currntItem.nama
}
override fun getItemCount(): Int {
return datalist.size
}
}
My recycler view has two types of item view. One type of them has MPAndroidChart in it. I need to do some chart view configuration that cannot be done in XML. How can I do it given that I am using RecyclerView data binding with a single base view holder (as recommended by George Mount) ?
open class BaseViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(obj: Any) {
binding.setVariable(BR.obj, obj)
binding.executePendingBindings()
}
}
abstract class BaseAdapter : RecyclerView.Adapter<BaseViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate<ViewDataBinding>(layoutInflater, viewType, parent, false)
return BaseViewHolder(binding)
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val obj = getObjForPosition(position)
holder.bind(obj)
}
override fun getItemViewType(position: Int): Int {
return getLayoutIdForPosition(position)
}
protected abstract fun getObjForPosition(position: Int): Any
protected abstract fun getLayoutIdForPosition(position: Int): Int
}
You can still access
holder.itemView.myChartViewId.doSomeStuff()
on the onBindViewHolder() call.
You can also implement a function to "initialize" your charts in your view holder like this:
open class BaseViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(obj: Any) {
binding.setVariable(BR.obj, obj)
binding.executePendingBindings()
}
fun initCharts() {
if (itemView.myChartViewId == null) return
itemView.myChartViewId.doSomwStuff()
}
}
and call it whenever you need.