On Click implementation not working in Kotlin - android

I am implementing on Click listener in Kotlin and it is not working. When i click on button nothing happens. Below is the code:
class MainActivity : AppCompatActivity(), View.OnClickListener{
var area: MaterialButton? = null; var length: MaterialButton? = null
var time: MaterialButton? = null;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
area = findViewById(R.id.button_area)
length = findViewById(R.id.button_length)
time = findViewById(R.id.button_time)
setClickListeners()
}
private fun setClickListeners() {
area?.setOnClickListener(this)
length?.setOnClickListener(this)
time?.setOnClickListener(this)
}
fun toggleDrawer(view: View) {
showToast("Drawer")
}
fun openSettings(view: View) {}
override fun onClick(v: View) {
when (v.id) {
R.id.button_area, R.id.button_length,
R.id.button_time -> showToast("Click")
else ->{
showToast("Drawer")
}
}
}
private fun showToast(str: String){
Toast.makeText(this,str,Toast.LENGTH_LONG).show()
}
}
XML onClick attribute is not working.
<include
layout="#layout/toolbar_content"/>
I have included layout with include property, in main activity(xml). Included view onClick methods are:
fun toggleDrawer(view: View) {
showToast("Drawer")
}
fun openSettings(view: View) {}
They are not working. Infact i am getting error. Could not find a method toggleDrawer(View) in the activity class android.view.ContextThemeWrapper for onClick handler on view class com.google.android.material.button.MaterialButton with id 'drawer_icon'. I have declared these methods in MaterialButton tag. The layout of this button is toolbar_content.
How to resolve all these issues.

If You want to set onClick to specific View in the included layout use this in onCreate:
// Apply click listener to one view in the included layout
val includedLayoutButton: View = findViewById<View>(R.id.includedLayout).findViewById(R.id.butInIncludedLayout)
includedLayoutButton.setOnClickListener {
Log.d("in", "on click")
}
main.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/includedLayout"
layout="#layout/layout_test" />
</androidx.constraintlayout.widget.ConstraintLayout>
layout_test.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/butInIncludedLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</FrameLayout>

Related

How to pass multiple views as parameters in BindingAdapter in Data binding android?

I have one relative layout and one ImageView. I want to set visibility based on Image loading like if image loads successfully then imageview is visible and if some error occurs relative layout is visible. How can I manage this scenario in data binding using BindingAdapter ?
Your question is not clear so I don't know if it will help you.
These are steps to implement
1: Create parameters in BindingAdapter.kt
#BindingAdapter("showLoading")
fun View.showLoading(loading: Boolean) {
if (loading) {
visible()
} else {
gone()
}
}
#BindingAdapter("showError")
fun View.showError(error: Boolean) {
if (error) {
visible()
} else {
gone()
}
}
fun View.gone() {
this.visibility = View.GONE
}
fun View.visible() {
this.visibility = View.VISIBLE
}
2: Use parameters [app:showLoading="#{viewModel.showLoading}"] and [app:showError="#{viewModel.showError}"] created in file XML
<?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="viewModel"
type="com.xxx.xxx.MainViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EAEAE2"
android:orientation="vertical">
<Button
android:id="#+id/btnAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ShowLoading" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:showLoading="#{viewModel.showLoading}" />
<RelativeLayout
android:id="#+id/viewError"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#color/colorPrimary"
app:showError="#{viewModel.showError}" />
</LinearLayout>
</layout>
3: Create showError and showLoading variables in Viewmodel.
And assign the viewModel variable to the binding.
class MainViewModel: ViewModel() {
val showError: MutableLiveData<Boolean> = MutableLiveData()
val showLoading: MutableLiveData<Boolean> = MutableLiveData()
init {
showError.postValue(false)
showLoading.postValue(true)
}
}
class MainActivity : AppCompatActivity() {
private val viewModel = MainViewModel()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.lifecycleOwner = this
binding.viewModel = viewModel
initViews()
}
private fun initViews() {
binding.btnAdd.setOnClickListener {
viewModel.showError.postValue(true)
viewModel.showLoading.postValue(false)
}
}
}

Data not displayed on recycler view

I have a recycler view issue where the data is not being displayed. onCreateViewHolder and onBindViewHolder are not being called. When I call notifyDataSetChanged(), notifyChanged() is called but mObservers is empty, so it won't update my list.
public void notifyChanged() {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
here's my adapter code:
class ReleasesAdapter : RecyclerView.Adapter<ReleasesAdapter.ReleasesViewHolder>() {
private val data = mutableListOf<Album>(Album())
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReleasesViewHolder {
return ReleasesViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.song_item, parent, false)
)
}
override fun onBindViewHolder(holder: ReleasesViewHolder, position: Int) {
holder.bindView(data[position])
}
override fun getItemCount(): Int {
return data.size
}
fun setItems(items: List<Album>) {
data.addAll(items)
notifyDataSetChanged()
}
inner class ReleasesViewHolder(
override val containerView: View
) : RecyclerView.ViewHolder(containerView), LayoutContainer {
fun bindView(item: Album) {
containerView.nameTv.text = item.name
}
}
}
And here's my activity code:
#AndroidEntryPoint
class MainActivity : AppCompatActivity(), Contract.View {
#Inject
lateinit var presenter: Contract.Presenter
private val releasesAdapter = ReleasesAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
resultsRv.run {
adapter = releasesAdapter
layoutManager = LinearLayoutManager(this#MainActivity)
}
presenter.loadNewReleases()
}
override fun showReleases(data: List<Album>) {
releasesAdapter.setItems(data)
}
override fun showErrorMessage(message: String) {
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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:orientation="vertical"
tools:context=".presentation.MainActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/resultsRv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="#layout/song_item" />
</androidx.appcompat.widget.LinearLayoutCompat>
song_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.textview.MaterialTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/nameTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/song_item_margin"
android:textColor="#color/black" />
Please send help :(
Edit: Added Xml code
I believe you are using the scope functions wrong especially run in this case. Use run() function if you need to compute some value or want to limit the scope of multiple local variables.
So while your other code seems okay, I believe your Adapter and LayoutManager is not being assigned. I would suggest you replace the run with apply and try again.
resultsRv.apply {
adapter = releasesAdapter
layoutManager = LinearLayoutManager(this#MainActivity)
}

All child recyclerView's items changed when one child recyclerview's item is changed while click the item

I am working with nested recyclerView. According to business logic, first I have to call an API that fetched the list of item that is shown in the Parent recycler view. After that, if a user clicks any of the items of the parent recycler view, another API is called which fetches a list of sub-items, and I have to show the item list in the inner recycler view of that clicked-positioned parent recycler view.
I successfully implemented showing items in the parent recycler view and sub-items in the clicked-position nested recycler view.
But the problem I am facing is when I clicked any specific item of the parent recycler view, all the other nested recycler view's item get changed with the newly populated sub-items value.
How can I solve this issue?. Here is the sample code
main_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
style="#style/CardViewStyle"
android:id="#+id/chapter_layout"
android:layout_width="match_parent">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/chapter_name_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<com.google.android.material.textview.MaterialTextView
android:id="#+id/header_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
</com.google.android.material.card.MaterialCardView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/chapter_topic_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="#layout/item_main" />
</androidx.appcompat.widget.LinearLayoutCompat>
MainItemViewHolder.kt
class MainItemViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun bind(item: SpecificChapter, onClick: (SpecificChapter, Int) -> Unit) {
with(view) {
chapter_name_text_view.text = "Chapter "+ item.no
header_text_view.text = item.name
chapter_layout.setOnClickListener { onClick(item, bindingAdapterPosition) }
}
}
}
MainItemAdapter.kt
class MainItemAdapter(
val onClick: (SpecificChapter, Int) -> Unit
) : ListAdapter<SpecificChapter, MainItemViewHolder>(DIFF_CALLBACK) {
companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<SpecificChapter>() {
override fun areItemsTheSame(old: SpecificChapter, aNew: SpecificChapter) = (old.id == aNew.id)
override fun areContentsTheSame(old: SpecificChapter, aNew: SpecificChapter) = (old == aNew)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainItemViewHolder {
return MainItemViewHolder(parent.inflate(R.layout.main_item))
}
override fun onBindViewHolder(holder: MainItemViewHolder, position: Int) {
holder.bind(getItem(position)!!, onClick)
}
}
sub_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView
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">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/chapter_topic_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</com.google.android.material.card.MaterialCardView>
SubItemViewHolder.kt
class SubItemViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun bind(item: SpecificTopic, onClick: (SpecificTopic) -> Unit) {
with(view) {
chapter_topic_text_view.text = item.name
chapter_topic_layout.setOnClickListener { onClick(item) }
}
}
}
SubItemAdapter.kt
class SubItemAdapter(
val onClick: (SpecificTopic) -> Unit
) : ListAdapter<SpecificTopic, SubItemViewHolder>(DIFF_CALLBACK) {
companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<SpecificTopic>() {
override fun areItemsTheSame(old: SpecificTopic, aNew: SpecificTopic) = (old.id == aNew.id)
override fun areContentsTheSame(old: SpecificTopic, aNew: SpecificTopic) = (old == aNew)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubItemViewHolder {
return SubItemViewHolder(parent.inflate(R.layout.sub_item))
}
override fun onBindViewHolder(holder: SpecificTopicViewHolder, position: Int) {
holder.bind(getItem(position)!!, onClick)
}
}
activity_chapter.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/chapter_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/main_item"/>
</androidx.appcompat.widget.LinearLayoutCompat>
ChapterActivity.kt
class ChapterActivity : BaseActivity<ChapterViewModel>() {
var chapterPosition = 0
private val mainItemAdapter: MainItemAdapter by lazy {
MainItemAdapter { specificChapter, position ->
// sub item Api call when clicked specific item. response is viewmodel.allTopics
chapterPosition = position
specificChapter.id?.let { viewModel.getChapterWiseTopics(it) }
}
}
private val subItemAdapter: SubItemAdapter by lazy {
SubItemAdapter {
}
}
override fun onResume() {
super.onResume()
// Main item Api call. response is viewmodel.allChapters
viewModel.getChapters("subject_code")
}
override fun observeLiveData() {
// showing Main item in parent recyclerView
observe(viewModel.allChapters) {
val chapterList = ArrayList<SpecificChapter>()
chapterList.add(SpecificChapter(...))
chapter_recycler_view.adapter = mainItemAdapter
mainItemAdapter.submitList(chapterList)
chapter_recycler_view.setItemViewCacheSize(chapterList.size)
}
// showing sub item in nested recyclerView
observe(viewModel.allTopics) {
val topicList = ArrayList<SpecificTopic>()
topicList.add(SpecificTopic(...))
with((chapter_recycler_view.findViewHolderForAdapterPosition(chapterPosition) as MainItemViewHolder).itemView) {
this.chapter_topic_recycler_view.adapter = subItemAdapter
subItemAdapter.submitList(topicList)
}
}
}
}

Viewpager must not be null (Viewpager2)

I'm trying to implement viewpager when press of a button on secondary activity for that I created a PageAdaper class which extends Recycler view.Adapter .I got viewpager must not be null error on runtime .
PageAdaper.kt
open class PageAdapter(context: Context, arrayList: ArrayList<Uri>) : RecyclerView.Adapter<PageAdapter.MyViewHolder>() {
private var mContext: Context? =null
private var galleryUri= arrayListOf<Uri>()
private var layoutInflater: LayoutInflater? =null
init {
this.mContext=context
this.galleryUri=arrayList
this.layoutInflater=context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
}
private fun onBindViewHolderr(holder: MyViewHolder, position: Int) {
holder.iView.setImageURI(galleryUri[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view=LayoutInflater.from(mContext).inflate(R.layout.image_container,parent,false)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return galleryUri.size
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val iView: ImageView
init {
super.itemView
iView=itemView.findViewById(R.id.imageContainer)
}
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
onBindViewHolderr(holder, position)
}
}
Image_container.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/imageContainer"
android:contentDescription="#string/gallery" />
</LinearLayout>
Activity_gallery.xml
<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="match_parent">
<ImageButton
android:id="#+id/galleryBack"
android:layout_width="59dp"
android:layout_height="56dp"
android:background="#android:color/transparent"
android:contentDescription="#string/back_button"
android:src="#drawable/ic_baseline_arrow_back_24"
style="#style/Widget.AppCompat.Button.Colored"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintVertical_bias="0.05"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/viewPager"
android:layout_width="409dp"
android:layout_height="729dp"
android:background="#android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.viewpager2.widget.ViewPager2>
</androidx.constraintlayout.widget.ConstraintLayout>
Creation on viewpager on button click from activity_main
gallery.setOnClickListener { // gallery button reference
if (lastImageUri!=null){
val intent= Intent(this,GalleryActivity::class.java)
startActivity(intent) // inflates activity_gallery.xml
val iAdapter=PageAdapter(this,galleryUri) // creating object with params
viewPager.adapter=iAdapter // here comes the error
}
}
Update
GalleryActivity.kt
It contains only setContentview to activity_gallery.xml
Do I need to add anything.
class GalleryActivity : AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_gallery)
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
galleryBack.setOnClickListener {
finish()
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
}
}
}
Explain me about this as I'm new to android. Thank you!
So, startActivity will go to the GalleryActivity class. You need to put the lines after that into the GalleryActivity.
Okay, now that you've added your GalleryActivity.kt. You need to make 2 changes. First, in your activity_main:
gallery.setOnClickListener { // gallery button reference
if (lastImageUri!=null){
val intent= Intent(this,GalleryActivity::class.java)
intent.putExtra("IMAGE_URI", galleryUri)
startActivity(intent) // inflates activity_gallery.xml
}
}
Then, in your GalleryActivity.kt
class GalleryActivity : AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_gallery)
val galleryUri = getIntent().getStringExtra("GALLERY_URI")
val iAdapter=PageAdapter(this,galleryUri) // creating object with params
viewPager.adapter=iAdapter
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
galleryBack.setOnClickListener {
finish()
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right)
}
}
}
Try that.

Android - Cannot move progressBar into centre

While working with Kotlin, in my BaseActivity I want to implement showProgressBar i.e,
abstract class BaseActivity : AppCompatActivity() {
var progressBar: ProgressBar? = null
fun showProgressBar() {
progressBar = ProgressBar(this, null, android.R.attr.progressBarStyleSmall)
val params = RelativeLayout.LayoutParams(120, 120)
params.addRule(RelativeLayout.CENTER_IN_PARENT)
val layout = this.findViewById<ViewGroup>(android.R.id.content)
layout.addView(progressBar, params)
}
fun hideProgressBar() {
progressBar?.visibility = GONE
}
}
MainActivity layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity">
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_centerInParent="true" />
</RelativeLayout>
I am calling from MainActivity like,
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.i(TAG, "calling showProgressBar")
showProgressBar()
Handler(Looper.getMainLooper()).postDelayed(Runnable {
Log.i(TAG, "calling hideProgressBar")
hideProgressBar()
}, 5000)
}
}
But params.addRule(RelativeLayout.CENTER_IN_PARENT) seem does not work. Output is in below screenshot. How can I move the progressBar in centre of the screen?

Categories

Resources