I'm new to Kotlin and am trying to make phone call from a recycler view that has the button for the phone number, I want when i click on the button it should open up my phone dialer with the number automatically however when i click on the button, nothing happens.
here is what i've done:
I gave the permission for making a call in the manifest file
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:allowBackup="true"
android:dataExtractionRules="#xml/data_extraction_rules"
my recyclerview has the image, name, contact, the expertise and the button for calling the contact
here is my code snippet for the adapter that is supposed to carry out the activity. Im not sure, but maybe there could be a problem with my method.
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
class ConsultantAdapter(private val modelList: List<ConsultantModel>) :
RecyclerView.Adapter<ConsultantAdapter.ViewHolder>() {
private lateinit var callBtnListener: View.OnClickListener
classConsultantAdapter(valmodelList:List<ConsultantModel>,callBtnListener:View.OnClickListener) {}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val cImage: ImageView = itemView.findViewById(R.id.profile_image)
private val cName: TextView = itemView.findViewById(R.id.consultant_name)
private val cContact: TextView = itemView.findViewById(R.id.consultant_contact)
private val cExpertise: TextView = itemView.findViewById(R.id.consultant_expertise)
val callBtn: ImageView = itemView.findViewById(R.id.call_consultant_button)
fun setEvents(resource: String, name: String, contact: String, expertise: String) {
Glide.with(itemView.context).load(resource).into(cImage)
cName.text = name
cContact.text = contact
cExpertise.text = expertise
itemView.setOnClickListener{
val intent: Intent = Uri.parse(contact).let { number ->
Intent(Intent.ACTION_DIAL, number)
}
itemView.context.startActivity(intent)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val galleryView =
LayoutInflater.from(parent.context).inflate(R.layout.consultants_item, parent, false)
return ViewHolder(galleryView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val resource = modelList[position].image
val name = modelList[position].name
val contact = modelList[position].contact
val expertise = modelList[position].expertise
holder.setEvents(resource, name, contact, expertise)
}
override fun getItemCount(): Int {
return modelList.size
}
}
Just add
setOnClickListener
to either your callBtn, or make a reference to your parent view like Relative Layout or whatever you have used to wrap all children views.
The ItemView here, is perhaps a root view for the layout, row or cell and you can bind it to any view using
as
Related
I am relativley new to Android Studio and I have tried making a RecyclerView for my Application. I have ran into an issue where I cannot update the ViewHolder unless it's inside the ViewHolder itself.
Here is my RecyclerViewAdapter
package com.example.testactivity
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView
class RecyclerViewAdapter() : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var name : TextView
var description : TextView
var listCard : CardView
init {
name = itemView.findViewById(R.id.projname)
description = itemView.findViewById(R.id.desc)
listCard = itemView.findViewById(R.id.listCard)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: RecyclerViewAdapter.ViewHolder, position: Int) {
holder.name.text = ideaList[position].name
holder.description.text = ideaList[position].description
holder.listCard.setCardBackgroundColor(Color.parseColor(ideaList[position].color))
holder.itemView.findViewById<LinearLayout>(R.id.linLayout).setOnClickListener(View.OnClickListener {
ideaList.remove(ideaList[position])
println(position.toString())
notifyItemChanged(ideaList.size)
})
}
override fun getItemCount(): Int {
return ideaList.size
}
fun addItem(name: String, desc: String, color: String) {
val idea = Idea(
name,
desc,
color
)
ideaList.add(idea)
notifyItemInserted(ideaList.size-1)
println((ideaList.size-1).toString())
}
}
And this is my MainActivity
class MainActivity : AppCompatActivity() {
//private var layoutManager: LayoutManager? = null
//private var adapter: RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>? = null
override fun onCreate(savedInstanceState: Bundle?) {
lateinit var layoutManager : LayoutManager
lateinit var adapter : RecyclerViewAdapter
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Switch Activity
val accbtn = findViewById<ImageButton>(R.id.accInf)
accbtn.setOnClickListener {
val i = Intent(this, SecondActivity::class.java)
//i.putExtra("", value) **IMPORT THE ACCOUNT INFORMATION ONTO THIS PAGE
this.startActivity(i)
this.overridePendingTransition(0, 0);
}
// Add Item
val addbtn = findViewById<ImageButton>(R.id.addBtn)
val bottomSheet = BottomSheetFragment()
// Use the add button to open a modal to add an item to a grid
addbtn.setOnClickListener {
//Open bottom sheet modal to add item
bottomSheet.show(supportFragmentManager, "BottomSheetDialog")
}
// Add Item to Recycler view
val recycleView = findViewById<RecyclerView>(R.id.recyclerview)
layoutManager = LinearLayoutManager(this)
adapter = RecyclerViewAdapter()
recycleView.layoutManager = layoutManager
recycleView.adapter = adapter
}
I have tried using it in the MainActivity and inside of the ViewAdapter, aswell when I did "notifyItemChanged(ideaList.size)" inside of the ViewHolder it worked, but it doesn't work with any of the notify functions outside of this.
Not only does notifyOnItemChanged work anywhere, but the onBindViewHolder is the one place you should probably never call it- the point of that function is to bind a view, preferably without side effects. Luckily you aren't doing that, you're doing it in a callback set in that function which is totally different.
THe reason your call doesn't work is the call is wrong. Your code is:
ideaList.remove(ideaList[position])
println(position.toString())
notifyItemChanged(ideaList.size)
Let's say the size of the list is 10, and the position is 4 at the beginning of this function. First off, you didn't change anything- you removed something. Changed would be if you swapped the value at position X with a different value, but kept the size and placement unchanged. So it should be notifyItemRemoved, not notifyItemChanged. Secondly, the index you send is wrong- you'd be sending 9 in my example above. You should be sending 4, the index of the item removed. So you want notifyItemRemoved(position)
I can't manage to uset setImageResource on my holder (which is a part of a CardView).
I've already tried to add a image asset but it didn't seem to work.
I would like to know how can I change an image properly in this case.
This is the code of the entire page:
package com.example.revenuer.adapter
import android.R
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.revenuer.entity.Operation
import com.example.revenuer.listener.OperationListener
class HistoryAdapter(val list: List<Operation>): RecyclerView.Adapter<HistoryAdapter.OperationViewHolder>() {
private var listener: OperationListener? = null
fun setOnOperationListener(listener: OperationListener){
this.listener = listener;
}
class OperationViewHolder(view: View, private val listener: OperationListener?): RecyclerView.ViewHolder(view){
val nameView: TextView
val valueView: TextView
val dateView: TextView
val imageView: ImageView
init {
view.setOnClickListener{
listener?.onListItemClick(view, adapterPosition)
}
nameView = view.findViewById(com.example.revenuer.R.id.item_cardview_name)
valueView = view.findViewById(com.example.revenuer.R.id.item_cardview_value)
dateView = view.findViewById(com.example.revenuer.R.id.item_cardview_date)
imageView = view.findViewById(com.example.revenuer.R.id.operation_image)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OperationViewHolder{
val view = LayoutInflater.from(parent.context).inflate(com.example.revenuer.R.layout.operation_item, parent,false)
return OperationViewHolder(view, listener)
}
override fun onBindViewHolder(holder: OperationViewHolder, position: Int) {
val operation = list[position]
holder.nameView.text = operation.name
holder.valueView.text = operation.value
holder.dateView.text = operation.date
if (operation.type) {
holder.imageView.setImageResource(R.drawable.custom_arrow_up)
}
}
override fun getItemCount(): Int {
return list.size
}
}
You have import android.R, so in the rest of your code you need to write com.example.revenuer.R to refer to your own package's R, just like you did elsewhere.
Solution:
Replace import android.R with import com.example.revenuer.R and you can replace all com.example.revenuer.R with R. Explicitly write android.R when you need to.
MyAdapter.kt
im a beginner in this and how to open another activity when i click the cardview..previously it worked fine,but when i click the card nothing happens and only toast show up
I want the user to be able to click on a card and go to a different activity. If you click on card 1 you must go to the activity1. If you click on card 2 you must go to the activity2. Etc...
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.viewpager.widget.PagerAdapter
import kotlinx.android.synthetic.main.card_item.view.*
class MyAdapter(private val context: Context, private val myModelArrayList: ArrayList<MyModel>) : PagerAdapter(){
override fun getCount(): Int {
return myModelArrayList.size //return list of records/items
}
override fun isViewFromObject(view: View, `object`: Any): Boolean {
return view == `object`
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
//inflate layout card_item.xml
val view = LayoutInflater.from(context).inflate(R.layout.card_item, container, false)
//get data
val model = myModelArrayList.get(position)
val title = model.title
val description = model.description
val date = model.date
val image = model.image
//set data to ui views
view.bannerIv.setImageResource(image)
view.titleTv.text = title
view.descriptionTv.text = description
view.dateTv.text = date
view.setOnClickListener {
val intent = Intent(context, SecondActivity::class.java)
context.startActivity(intent)
// finish();
}
//handle item/card click
view.setOnClickListener{
Toast.makeText(context,"$title \n $description \n $date", Toast.LENGTH_SHORT).show()
}
//add view to container
container.addView(view, position)
return view
}
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
container.removeView(`object` as View)
}
}
```
just simply remove your second view.setOnClickListener and move your toast to first view.setOnClickListener. As others mentioned second listener will be overridden.
Here is my code :-
Favourite Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.security.AccessController.getContext
//this is my calling activity
class FavouriteActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.favourite_activity)
val mToolbar: Toolbar = findViewById(R.id.toolbar_favourite)
setSupportActionBar(mToolbar)
getSupportActionBar()?.setDisplayHomeAsUpEnabled(true);
getSupportActionBar()?.setDisplayShowHomeEnabled(true);
setTitle("Favourite Activity");
//getting recyclerview from xml
val recyclerView = findViewById(R.id.recyclerView) as RecyclerView
//adding a layoutmanager
recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
//it can be staggered and grid
//creating our adapter
val adapter = CustomAdapter(star) //here I am calling the adapter activity
//now adding the adapter to recyclerview
recyclerView.adapter = adapter
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
}
CustomAdapter class
class CustomAdapter(val userList: ArrayList<User>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
//this method is returning the view for each item in the list
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_layout_favourite, parent, false)
return ViewHolder(v)
}
//this method is binding the data on the list
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.bindItems(userList[position])
holder.imgCopy.setOnClickListener(View.OnClickListener {
holder.shareString(userList[position])
Toast.makeText(holder.itemView.getContext(),"Copy Button Clicked", Toast.LENGTH_SHORT).show()
})
}
//this method is giving the size of the list
override fun getItemCount(): Int {
return userList.size
}
//the class is holding the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imgCopy: ImageView = itemView.findViewById(R.id.img_copy) as ImageView
val textViewName = itemView.findViewById(R.id.tvTitle) as TextView
fun bindItems(user: User) {
textViewName.text = user.name
}
fun shareString(user: User)
{
val message : String = user.name
val intent = Intent()
intent.action = Intent.ACTION_SEND
intent.putExtra(Intent.EXTRA_TEXT,message)
intent.type = "text/plain"
startActivity(Intent.createChooser(intent,"Share to :")) ///Issue occur right here
}}}
Getting error : Required context , found Intent.
it is working fine in other FragmentActivity.
I have tried various methods to called the context. but anything is not working.
I have also passed the context from Fragment activity, but that also not worked.
Please let me know is there any way to start Intent.
As I am always getting error and stuck due to this.
The startActivity available in the ViewHolder class is different from the one available in activites. So in this method (available in viewholder), the first parameter should be a context. So pass the context as follows:
startActivity(itemView.context, Intent.createChooser(intent,"Share to :"))
I'm developing an android app in kotlin, and I want to have a button in every recyclerView element, which will launch an intent - the same in whole recycle view, but with different parameters(for now it's just position for testing, in final form that will be some value from database).
I write the following code for that(inside my adapter class):
override fun onBindViewHolder(holder: ProjectViewHolder, position: Int) {
val Edit: Button = holder.view.EditButton
Edit.setOnClickListener()
{
var projekt: Intent = Intent(applicationContext, Project::class.java)
projekt.putExtra("id", position)
startActivity(projekt)
}
But I get "unresolved refference" error for applicationContext. I used buttons with intent like that before and that worked perfectly fine, though this is the first time I'm trying to do it inside recyclerView element.
How to make it work? Maybe I just take the wrong approach and it should be done in different way?
Edit: Complete adapter class file:
package com.example.legoapp127260
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.project_item_layout.view.*
class ProjectAdapter : RecyclerView.Adapter<ProjectViewHolder>()
{
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ProjectViewHolder {
val layoutInflater = LayoutInflater.from(viewGroup.context)
val projectRow = layoutInflater.inflate(R.layout.project_item_layout, viewGroup, false)
return ProjectViewHolder(projectRow)
}
override fun getItemCount(): Int {
return 2;
}
override fun onBindViewHolder(holder: ProjectViewHolder, position: Int) {
val projectName: TextView = holder.view.projectName
val projectNames: Array<String> = arrayOf("Set 1", "Set 2")
val Edit: Button = holder.view.EditButton
projectName.setText(projectNames[position])
Edit.setOnClickListener()
{
var projekt: Intent = Intent(Edit.context, Project::class.java)
projekt.putExtra("id", position)
Edit.context.startActivity(projekt)
}
}
}
class ProjectViewHolder(val view: View) : RecyclerView.ViewHolder(view)
{
}
You can get context from your button:
var projekt: Intent = Intent(Edit.context, Project::class.java)
projekt.putExtra("id", position)
Edit.context.startActivity(projekt)