This is my RecyclerView Adaper
class RecyclerAdapter(private val recyclerList: List): RecyclerView.Adapter(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): mainRecyclerViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.quiz_item_recycler_view,
parent, false)
return mainRecyclerViewHolder(itemView)
}
override fun getItemCount() = recyclerList.size
override fun onBindViewHolder(holder: mainRecyclerViewHolder, position: Int) {
val currentItem = recyclerList[position]
holder.imageView.setImageResource(currentItem.imageResource)
holder.textView.text = currentItem.recyclerCardText
}
class mainRecyclerViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val imageView: ImageView = itemView.rec_image
val textView: TextView = itemView.text_view_1
}
}
And this is my data class
data class RecyclerItemMain(val imageResource: Int, val recyclerCardText: String, val button: Button)
Like this:
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
holder.yourButton.setOnClickListener { v ->
// Here your start your other activity or navigate to another fragment
}
}
Remember that if you intent to send the user to diferent activities depending on the button, you have to create a when expression what will send the user to an activity depending on another value in the recyclerItem, for example the text of the item, in your case currentItem.recyclerCardText
Here is your full adapter, re-organized:
class RecyclerAdapter(recyclerList: List<CategorySectionIcon>) :
RecyclerView.Adapter<YourAdapter.CustomViewHolder>() {
private var recyclerList: List<CategorySectionIcon>? = recyclerList
inner class CustomViewHolder(
//Get a reference to the Views in our layout//
val myView: View
) : RecyclerView.ViewHolder(myView) {
var textView: TextView = myView.findViewById(R.id.your_text)
var imageView: ImageView = myView.findViewById(R.id.your_image)
var yourButton: Button = myView.findViewById(R.id.iv_category_imagen_icon)
}
override//Construct a RecyclerView.ViewHolder//
fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val itemView =
layoutInflater.inflate(R.layout.quiz_item_recycler_view, parent, false)
return CustomViewHolder(itemView)
}
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
holder.textView.text = recyclerList!![position].recyclerCardText
holder.imageView.setImageResource(recyclerList!![position].image)
holder.yourButton.setOnClickListener { v ->
// Here your start your other activity or navigate to another fragment
}
}
//Calculate the item count for the RecylerView//
override fun getItemCount(): Int {
return recyclerList!!.size
}
}
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
}
}
}
}
After seen all the similiar questions, I don't find a solution of my problem, which the description as follows:
In my android app, I use Kotlin as language. In my app, I have a lot of category and each category have a list of products. In my home activity, I create a vertical RecyclerView named "productListOfCategory". In the "productListOfCategory" adapter,a textView to display a category name and a recyclerView to display all related product list. The following code is the description of "ProductListOfProductTypeAdapter" adapter : (ProductType = category)
class ProductListOfProductTypeAdapter(private val context: Context, private val ProductTypeIDWithProduct: Map<String, Array<ProductData>>, private val productTypeDetail: Array<ProductTypeData>)
: RecyclerView.Adapter<ProductListOfProductTypeAdapter.ViewHolder>(),ProductOfProductTypeAdapter.OnItemClickListener{
override fun onItemClick(view: View, viewModel: ProductData) {
val intent = Intent(context,ProductDetail::class.java)
context.startActivity(intent)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_list_product_product_type, parent, false)
return ViewHolder(view)
}
override fun getItemCount() = ProductTypeIDWithProduct.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val itemType = ProductTypeIDWithProduct.keys.elementAt(position)
holder.productTypeName.text = getName(itemType)
val arrayProductOfProductType = ProductTypeIDWithProduct[itemType] as ArrayList<ProductData>
holder.productListOfProductType.apply {
holder.productListOfProductType.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
holder.productListOfProductType.adapter = ProductOfProductTypeAdapter(arrayProductOfProductType,context,this#ProductListOfProductTypeAdapter)
}
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val productTypeName: TextView = itemView.textViewProductTypeName
val productListOfProductType: RecyclerView = itemView.recyclerViewProductOfProductType
}
"ProductOfProductTypeAdapter" is the second adapter which the code as the following :
class ProductOfProductTypeAdapter(private val products: ArrayList<ProductData>, private val context: Context,private val mListener: OnItemClickListener)
: RecyclerView.Adapter<ProductOfProductTypeAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_product_featured, parent, false)
return ViewHolder(view)
}
override fun getItemCount() = products.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val productItem = products[position] as Map<String, Map<String, String>>
holder.productName.text = productItem["name"]?.get("En").toString()
holder.productWeight.text = productItem["weight"].toString().plus(context.resources.getString(R.string.ml))
holder.productPrice.text = "$".plus(productItem["price"].toString()).plus("/")
holder.productRating.text = productItem["reviewsValue"].toString()
holder.itemView.setOnClickListener {
mListener.onItemClick(holder.itemView, products[position])
notifyDataSetChanged()
}
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val productName: TextView = itemView.itemProdFeaturedName
val productPrice: TextView = itemView.itemProdFeaturedPrice
val productImage: ImageView = itemView.itemProdFeaturedImage
val productWeight: TextView = itemView.txtViewWeight
val productRating: TextView = itemView.itemProdFeaturedRate
}
interface OnItemClickListener {
fun onItemClick(view: View,viewModel: Map<String, Map<String, String>>)
}
My problem is How to click on product and dispaly the product detail activity.I try as the following but still not get what I want.
Shouldn't your OnItemClickListener be like the following?
interface OnItemClickListener {
fun onItemClick(view: View, product: ProductData)
}
And you need to change the way you start your ProductDetail activity, and put your product ID or something to identify the product selected in the extra data of the intent. For example:
val intent = Intent(context,ProductDetail::class.java)
intent.putExtra("PRODUCT_ID", product.id)
context.startActivity(intent)
I'm Using GSON to parse my JSON. I have an object that has 2 array object. I'm having a problem on getting the TransactionDetails position.
I have a recyclerView that populates the "Transactions" and then when I tap on that it should open the "TransactionDetails". But I'm having trouble on getting the position on TransactionDetails what array to read.
As you can see on the code I need to put a position on [0] because it only loads the 1st array on transaction details.
JSON Url
DetailedTransactionAdapter
class DetailedTransactionAdapter(val transactionFeed: TransactionFeed) : RecyclerView.Adapter<DetailCustomViewHolder>() {
override fun onBindViewHolder(holder: DetailCustomViewHolder, position: Int) {
val tr = transactionFeed.Transactions[1].TransactionDetails[position]
holder.view.txt_programType.text = transactionDetail.ProgramType
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DetailCustomViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(R.layout.list_detailed_transaction, parent, false)
return DetailCustomViewHolder(cellForRow)
}
override fun getItemCount(): Int {
return transactionFeed.Transactions[0].TransactionDetails.count()
}
}
class DetailCustomViewHolder(val view: View): RecyclerView.ViewHolder(view) {
init{
}
}
class TransactionFeed(val Transactions: List<Transactions>)
class Transactions(val TransactionCode: String,
val ProgramID: Int,
val ProgramName: String,
val ProgramType: String,
val ProgramDescription: String,
val TransactionID: Int,
val UserID: String,
val TransactionAmount: Int,
val TransactionDate: String,
val TransactionDetails: List<TransactionDetails>)
class TransactionDetails(val Clamied: Boolean,
val NextToClaim: Boolean,
val ProgramDetailID: Int,
val TransactionDetailID: Int,
val ProgramDetails: String,
val ProgramType: String,
val TransactionDetailAmount: Int,
val TransactionDetailMonth: String)
TransactionsAdapter
lass TransactionsAdapter(val transactionFeed: TransactionFeed) : RecyclerView.Adapter<CustomViewHolder>() {
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
val tr = transactionFeed.Transactions.get(position)
holder.view.txt_transaction_id.text = tr.TransactionID.toString()
holder.view.txt_transaction_date.text = tr.TransactionDate
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(R.layout.list_transaction, parent, false)
return CustomViewHolder(cellForRow)
}
override fun getItemCount(): Int {
return transactionFeed.Transactions.count()
}
}
class CustomViewHolder(val view: View):RecyclerView.ViewHolder(view) {
init{
view.setOnClickListener {
val intent = Intent(view.context, DetailedTransactionActivity::class.java)
view.context.startActivity(intent)
}
}
}
You'll have to set appropriate position in getItemCount() and onBindViewHolder() of DetailedTransactionAdapter. Here is how you can go about doing it:
First pass selected transaction position in TransactionsAdapter (when user clicks on any transaction) via intent to DetailedTransactionActivity.
class CustomViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
init {
view.setOnClickListener {
val intent = Intent(view.context, DetailedTransactionActivity::class.java)
intent.putExtra("selectedTransaction", adapterPosition)
view.context.startActivity(intent)
}
}
}
Then get that position in DetailedTransactionActivity and pass it to DetailedTransactionAdapter.
val transactionPos = intent.getIntExtra("selectedTransaction", -1)
detailedTransactionAdapter = DetailedTransactionAdapter(transactionFeed, transactionPos)
You'll have to change your DetailedTransactionAdapter to also have selectedTransaction as a field. This will help in dynamically populating adapter and binding appropriate data to view. Change adapter impl to this:
class DetailedTransactionAdapter(val transactionFeed: TransactionFeed, val selectedTransaction:Int) : RecyclerView.Adapter<DetailCustomViewHolder>() {
override fun onBindViewHolder(holder: DetailCustomViewHolder, position: Int) {
if(selectedTransaction == -1){
return
}
val tr = transactionFeed.Transactions[selectedTransaction].TransactionDetails[position]
holder.view.txt_programType.text = transactionDetail.ProgramType
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DetailCustomViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(R.layout.list_detailed_transaction, parent, false)
return DetailCustomViewHolder(cellForRow)
}
override fun getItemCount(): Int {
return transactionFeed.Transactions[selectedTransaction].TransactionDetails.count()
}
}
This is where magic happens. You are returning appropriate transaction details count
return transactionFeed.Transactions[selectedTransaction].TransactionDetails.count()
and binding data.
val tr = transactionFeed.Transactions[selectedTransaction].TransactionDetails[position]
So when you have selected first transaction, this will return count of transaction details of transaction[0] which is first transaction. And when any other transaction is selected, this will return its transaction details and populate adapter with its data.
Getting a large number of exceptions which I cannot reproduce like these:-
Fatal Exception: java.lang.IllegalArgumentException: view is not a
child, cannot hide androidx.cardview.widget.CardView{5dd439c V.E...C..
......I. 20,-228-680,-78}
at androidx.recyclerview.widget.b.e(ChildHelper.java:352)
at androidx.recyclerview.widget.RecyclerView$p.b(RecyclerView.java:6393)
There is no link from my source. But using Crashlytics log I think I know the approximate area of problem. The recycler adapter row is a very simple layout with a cardview at the root and a relative layout as the child. What could be the cause of this exception ?
Edit: My adapter
internal class AnalyzerAdapter(private val fragment: AnalyzerFragment,
private val context: Context) : RecyclerView.Adapter<AnalyzerAdapter.Companion.ViewHolder>() {
private val entries = ArrayList<AnalyzerData>()
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val parent = LayoutInflater.from(context).inflate(R.layout.analyzer_row, viewGroup, false)
return ViewHolder(parent)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val entry = entries[position]
holder.tvSize.text = "title"
holder.tvDetails.text = "details"
val type = getItemViewType(position)
holder.itemView.setOnClickListener {
fragment.onListClick(type)
}
when (type) {
...
}
}
override fun getItemViewType(position: Int): Int {
return entries[position].dataType
}
override fun getItemCount(): Int {
return entries.size
}
fun addEntry(entry: AnalyzerData) {
entries.add(entry)
notifyItemInserted(entries.size - 1)
}
fun editEntry(entry: AnalyzerData, position: Int) {
entries[position] = entry
notifyItemChanged(position)
}
fun initEntries(list: List<AnalyzerData>) {
entries.clear()
entries.addAll(list)
notifyDataSetChanged()
}
companion object {
internal class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) {
var ivIcon: ImageView = parent.findViewById(R.id.analyzer_icon)
var tvTitle: TextView = parent.findViewById(R.id.analyzer_title)
var tvDetails: TextView = parent.findViewById(R.id.analyzer_details)
var tvSize: TextView = parent.findViewById(R.id.analyzer_size)
}
}
}
I am using recyclerview to display images in cardview. When I load images from the url. It loads well from first time but when It loads for second time it is not displayed properly.
How to fix it? Here is the code
override fun getItemCount(): Int {
dataList = FlickrDBOperation.dataArray
if (dataList!!.isEmpty())
return 0
Log.e("count",dataList!!.size.toString())
return dataList!!.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
var itemView: View = LayoutInflater.from(parent.context).inflate(R.layout.imagelist_row,parent,false)
var viewHolder: FlickrAdapter.Holder = FlickrAdapter.Holder(itemView)
return viewHolder
}
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.image_name.text = dataList!!.get(position).name
Picasso.with(context).load(dataList!!.get(position).preUrl).into(holder.row_image)
}
class Holder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
val row_image: ImageView
val image_name: TextView
init {
row_image = itemView!!.findViewById<ImageView>(R.id.row_image)
image_name = itemView!!.findViewById<TextView>(R.id.image_name)
}
}