The addOnScrollListener for my RecyclerView not working as expected - kotlin

I want to know when I am at the bottom of my recycler view but I can't get why the recyclerView.canScrollVertically(1) is always returning true even if I am at the bottom of the Recycler View.
The recycler view is inside a CoordinatorLayout with an AppBarLayout.
You have the Kotlin code and the XML code for the bigger picture
Thank you.
getDataBinding().shipmentRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
Log.e(TAG,
"onScrollStateChanged 1: This is the bottom shipmentRecyclerView $newState <> ${RecyclerView.SCROLL_STATE_IDLE} ${
recyclerView.canScrollVertically(1)
}")
if (!getDataBinding().shipmentRecyclerView.canScrollVertically(1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
Log.e(TAG, "onScrollStateChanged 2: This is the bottom shipmentRecyclerView")
if (viewModel.currentPage.get()!! < viewModel.totalPages.get()!!) {
viewModel.getShipmentByPage(
viewModel.currentPage.get()!! + 1,
viewModel.request.get()
)
}
}
}
})
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<layout 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">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.technifyit.jibheli.presentation.main.fragment.search.SearchViewModel" />
</data>
<com.sothree.slidinguppanel.SlidingUpPanelLayout
android:id="#+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
app:umanoPanelHeight="0dp"
app:umanoShadowHeight="#dimen/margin_4dp"
tools:context=".presentation.main.fragment.search.SearchFragment">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/shipment_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="#dimen/margin_12dp"
android:clipToPadding="true"
android:fastScrollEnabled="true"
app:layout_anchor="#id/app_bar_layout"
app:layout_anchorGravity="bottom"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:shipment_adapter="#{viewModel}" />
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/dark_color_purple"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
...........
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/dark_color_purple"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:visibility="gone"
app:contentInsetStart="0dp"
app:layout_anchor="#id/app_bar_layout"
app:layout_anchorGravity="bottom"
app:layout_collapseMode="pin"
app:theme="#style/ThemeOverlay.AppCompat.Dark"
app:title="">
.........
</androidx.appcompat.widget.Toolbar>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/custom_web_page_browser"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/margin_40dp"
android:background="#drawable/background_rounded_top"
android:backgroundTint="#color/grey_clair">
<com.technifyit.jibheli.presentation.customView.MontserratBoldTextView
android:id="#+id/url_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_20dp"
android:layout_marginEnd="#dimen/margin_6dp"
android:text="#string/activity_item_details_send_request_button_text"
android:textColor="#color/dark_color_purple"
android:textSize="#dimen/title_size_sign_up"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="#id/close"
app:layout_constraintEnd_toStartOf="#id/use_link_image_view"
app:layout_constraintStart_toEndOf="#id/close"
app:layout_constraintTop_toTopOf="#id/close" />
<ImageView
android:id="#+id/close"
android:layout_width="#dimen/icon_24dp"
android:layout_height="#dimen/icon_24dp"
android:layout_margin="#dimen/margin_6dp"
android:background="#drawable/ic_close_gold"
android:backgroundTint="#color/dark_color_purple"
android:padding="#dimen/margin_4dp"
android:src="#drawable/ic_close_native"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="#color/white" />
<com.technifyit.jibheli.presentation.customView.MontserratBoldTextView
android:id="#+id/use_link_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin_6dp"
android:background="#drawable/button_rounded_left_only_no_icon"
android:backgroundTint="#color/dark_color_purple"
android:drawableEnd="#drawable/ic_check_native"
android:drawablePadding="#dimen/margin_6dp"
android:gravity="center"
android:paddingStart="#dimen/margin_8dp"
android:paddingEnd="#dimen/margin_8dp"
android:text="#string/select"
android:textAllCaps="false"
android:textColor="#color/white"
app:drawableTint="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="#dimen/margin_4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/close">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/no_item_found_suggested_layout"
layout="#layout/no_item_found_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/requested_shipments_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin_6dp"
android:fastScrollEnabled="true"
app:layout_constraintTop_toTopOf="parent"
app:requested_shipment_adapter="#{viewModel}" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/requested_trip_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin_6dp"
android:fastScrollEnabled="true"
app:layout_constraintTop_toTopOf="parent"
app:requested_trip_adapter="#{viewModel}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
</layout>

Thank you for your response, i did find a solution by adding to my recycler view in xml
addOnScrolledToBottomListener="#{viewModel}" and then in the bindingAdapter
#BindingAdapter("addOnScrolledToBottomListener")
fun addOnScrolledToBottomListener(recyclerView: RecyclerView, viewModel: SearchViewModel) {
recyclerView.addOnScrollListener(object :
RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (recyclerView.canScrollVertically(1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
if (viewModel.currentPage.get()!! < viewModel.totalPages.get()!!) {
viewModel.getShipmentByPage(
viewModel.currentPage.get()!! + 1,
viewModel.request.get()
)
}
}
}
})
}`
and like that it worked like a charm, Thank you #xinaiz for your help

Related

Viewpager 2 conflict with SwipeRefreshLayout

Im trying to use SwipeRefreshLayout to load data whenever user swipe down. It works correctly in Viewpager but when I user Viewpager2 it causes :
2022-03-08 09:12:39.733 6489-6489/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 6489
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.get(ArrayList.java:437)
at androidx.recyclerview.widget.StaggeredGridLayoutManager$Span.calculateCachedStart(StaggeredGridLayoutManager.java:2531)
at androidx.recyclerview.widget.StaggeredGridLayoutManager$Span.getStartLine(StaggeredGridLayoutManager.java:2548)
at androidx.recyclerview.widget.StaggeredGridLayoutManager.checkSpanForGap(StaggeredGridLayoutManager.java:410)
at androidx.recyclerview.widget.StaggeredGridLayoutManager.hasGapsToFix(StaggeredGridLayoutManager.java:359)
at androidx.recyclerview.widget.StaggeredGridLayoutManager.checkForGaps(StaggeredGridLayoutManager.java:282)
at androidx.recyclerview.widget.StaggeredGridLayoutManager.onScrollStateChanged(StaggeredGridLayoutManager.java:317)
at androidx.recyclerview.widget.RecyclerView.dispatchOnScrollStateChanged(RecyclerView.java:5197)
at androidx.recyclerview.widget.RecyclerView.setScrollState(RecyclerView.java:1550)
at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5397)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)>
It happen when I change to the second page and return to the first page and swipe down to refresh. Below is my layout of the first page.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.example.myapplication.viewmodel.FirstViewModel"/>
</data>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
app:onRefreshListener="#{() -> viewModel.onRefresh()}"
app:refreshing="#{viewModel.spinner}"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
>
<TextView
android:id="#+id/tvContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="News"
android:textAllCaps="true"
android:textSize="30sp"
android:textStyle="bold"
android:gravity="center"
android:onClick="#{() -> viewModel.nextFragment()}"
android:textColor="#color/red"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/csArticles"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#+id/tvContent"
>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvNews"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="50dp"
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
tools:listitem="#layout/item_news" />
<ProgressBar
android:id="#+id/spinner"
android:layout_width="0dp"
android:visibility="gone"
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" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/csNoArticles"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#+id/tvContent"
app:layout_constraintBottom_toBottomOf="parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No articles"
android:textSize="25sp"
android:textColor="#color/navy"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</layout>
And the last is the function which I use to init Viewpager2Adapter.
fun ViewPager2.initFragment(
fragment: Fragment,
fragments: MutableList<Fragment>
): ViewPager2 {
adapter = object : FragmentStateAdapter(fragment) {
override fun createFragment(position: Int) = fragments[position]
override fun getItemCount() = fragments.size
}
return this
}
Thank for reading.

Hopefully a simple Kotlin regarding looping through a recycler

I have a recycler in my activity for acrostic poetry. The recycler displays an image of the letters of the word (Stone Age, in this case) and an EditText to enter the acrostic words. What I want to do is read the words that have been entered, so for "Stone Age" I'm creating 8 items in the recycler.
In order to get the words, I have tried to replicate the steps in this question How to iterate over RecyclerView items. I think I'm close, but I can't quite get over the line.
I have this function where I am trying to read the values (at this stage just into the logcat)
I figured that getChildCount returned the items, but this is logging 2 (or sometimes, oddly, 3) rather than the 8 I would expect, so I'm struggling to understand what I am looping.
private fun saveTask() {
var p: String = ""
Log.d(HWG.TAG, "Children: ${acrosticRecycler.getChildCount().toString()}")
for (i in 0 until acrosticRecycler.getChildCount()) {
var holder: AcrosticAdapter.ViewHolder
if(acrosticRecycler.findViewHolderForAdapterPosition(i) != null) {
holder = acrosticRecycler.findViewHolderForAdapterPosition(i) as AcrosticAdapter.ViewHolder
p = holder.txtWord.text.toString()
Log.d(HWG.TAG, "Word: ${p}")
}
}
}
This is the layout of the recycler
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp"
app:cardCornerRadius="4dp"
app:cardElevation="6dp">
<LinearLayout
android:id="#+id/llTaskList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<ImageView
android:id="#+id/imgLetter"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:adjustViewBounds="true"
android:cropToPadding="true"
android:scaleType="centerCrop"
app:srcCompat="#drawable/icons8_s" />
<EditText
android:id="#+id/txtWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:hint="Stone Age"
android:textAllCaps="true"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
This is the activity in which the recycler sits
<?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:background="#color/background"
tools:context=".TextualTask">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:background="#color/background"
app:cardCornerRadius="4dp"
app:cardElevation="6dp"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<ImageView
android:id="#+id/subjectImage"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center_horizontal"
android:adjustViewBounds="true"
android:cropToPadding="true"
android:scaleType="centerCrop"
app:srcCompat="#drawable/icons8_knowledge_sharing_80" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="#+id/txtTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_marginLeft="15dp"
android:text="Acrostic Poem"
android:textAllCaps="true"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_margin="6dp"
android:background="?android:attr/listDivider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:id="#+id/txtPreamble"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginLeft="15dp"
android:text="Preamble text"
android:textAlignment="center"
android:textSize="14sp"
android:textStyle="bold|italic" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<androidx.cardview.widget.CardView
android:id="#+id/crdWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="24dp"
app:cardBackgroundColor="#color/cardback"
app:cardCornerRadius="4dp"
app:cardElevation="6dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<Button
android:id="#+id/btnSubmit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:backgroundTint="#color/start"
android:text="Submit" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/acrosticRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemCount="5"
tools:listitem="#layout/acrostic_task" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
Oddly enough, sometime the for loop gets the values from items 0-2, but sometimes it doesn't. The call to saveTask is made from btnSubmit as I don't need to get the values at the point the user enters them, just when they're happy to submit.
Could someone point me in the right direction please?
You can't get the correct count from acrosticRecycler.getChildCount().
because acrosticRecycler.getChildCount() will return the count of currently showed item in the RecyclerView. So even if your data is 8, but the showed data in the screen is only 3 items. So you will always get 3 not 8.
It's not good practice to get the data from the ViewHolder in recycler view directly. You should get the data from the list you have inserted to recycler view adapter.
for example, you can create adapter like this :
class AcrosticAdapter(var listData: ArrayList<AcrosticPoetry>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int = listData.size
}
//assuming this is your model class
class AcrosticPoetry() {
var textWord = ""
}
and you can change your code to
private fun saveTask() {
val adapter = acrosticRecycler.adapter as AcrosticAdapter
val data = adapter.listData
for (i in 0 until data.size) {
val word = data[i].txtWord
Log.d(HWG.TAG, "Word: ${word}")
}
}

MaterialCardView not showing when added programmatically

I am not able to see MaterialViewCard at my Activity when adding programmatically. If I add directly on XML, it shows. But When adding via Kotling, it doesn't.
XML sample:
<?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=".SecondFragment">
<LinearLayout
android:id="#+id/layout_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:id="#+id/layout_first_block"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#color/surface"
android:layout_margin="2dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00"
android:textColor="#color/on_surface"/>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#color/surface"
android:layout_margin="2dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="01"
android:textColor="#color/on_surface"/>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#color/surface"
android:layout_margin="2dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="03"
android:textColor="#color/on_surface"/>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_weight="1">
<Button
android:id="#+id/button_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/previous"/>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Result:
Cards added via XML
But when I try this (below) won't work.
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=".SecondFragment">
<LinearLayout
android:id="#+id/layout_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:id="#+id/layout_first_block"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1">
<!-- Will add here-->
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_weight="1">
<Button
android:id="#+id/button_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/previous"/>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Kotlin:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button_second).setOnClickListener {
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}
val layoutFirstBlock: LinearLayout = view.findViewById<LinearLayout>(R.id.layout_first_block)
for (r in 1..10){
val row: LinearLayout = LinearLayout(context)
row.orientation = LinearLayout.HORIZONTAL
row.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
for(c in 1..10){
val card: MaterialCardView = MaterialCardView(context)
val marginParams: ViewGroup.MarginLayoutParams = ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
marginParams.setMargins(R.dimen.small_padding, R.dimen.small_padding, R.dimen.small_padding, R.dimen.small_padding)
card.layoutParams = marginParams
card.setBackgroundColor(resources.getColor(R.color.surface, context?.theme))
val num: TextView = TextView(context)
num.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val value = ((r-1)*10 + c).toString()
num.text = value
num.setTextColor(resources.getColor(R.color.on_surface, context?.theme))
Log.d("i", "i$r$c = $value")
card.addView(num)
row.addView(card)
}
layoutFirstBlock.addView(row, 0)
}
}
Result: Cards missing when added by Kotlin
Any ideas?
Thanks!
In my case the issue was i have a component above the cardview and i have set its height to match_parent,when i gave the height to wrap_content the issue has been solved.
If it doesn't work also check in build gradle for below line.
implementation 'com.google.android.material:material:1.0.0'
Firstly,
You need to generate id's of each view as well.
val card: MaterialCardView = MaterialCardView(context)
card.id = View.generateViewId()
and
val num: TextView = TextView(context)
num.id = View.generateViewId()
Secondly,
I think, you should need to update index of
layoutFirstBlock.addView(row, 0)
to
layoutFirstBlock.addView(row, r)

GridView cannot be cast to ViewPager in Kotlin Custom Calendar

Working on the custom calendar in Kotlin.
On tapping the DateText, this custom calendar widget will be opened in a new fragment.
I used Grid Views to display the dates and I'm getting ClassCastException on navigating to the Calendar Screen(GridView cannot be cast to ViewPager).
Error:
Caused by: java.lang.ClassCastException: com.daimler.myfinance.payment.paymentdate.extensions.CalendarGridView cannot be cast to com.daimler.myfinance.payment.paymentdate.extensions.CalendarViewPager
at com.payment.paymentdate.CalendarView.initUiElements(CalendarView.kt)
CalendarView.kt
open class CalendarView : LinearLayout {
private var mViewPager: CalendarViewPager? = null
private fun initUiElements() {
mViewPager = findViewById<ViewPager>(R.id.calendarViewPager) as CalendarViewPager
}
}
CalendarViewPager.kt
class CalendarViewPager : ViewPager {
constructor(context: Context?) : super(context!!) {
}
constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var heightMeasureSpec = heightMeasureSpec
var height = 0
for (i in 0 until getChildCount()) {
val child: View = getChildAt(i)
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
val h = child.measuredHeight
if (h > height) {
height = h
}
}
if (height != 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}
calendar_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:background="#android:color/white"
android:orientation="vertical">
<!-- date toolbar -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/calendarHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#color/jumio_white"
app:layout_constraintBottom_toTopOf="#+id/abbreviationsBar">
<ImageButton
android:id="#+id/previousButton"
style="#style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="30dp"
android:layout_height="match_parent"
android:src="#drawable/ic_chevron_left"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.uikit.widgets.textviews.MBBody2TextView
android:id="#+id/currentDateLabel"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:gravity="center"
android:textColor="#color/jumio_black"
android:textSize="18sp"
app:layout_constraintLeft_toRightOf="#id/previousButton"
app:layout_constraintRight_toLeftOf="#id/forwardButton"
app:layout_constraintTop_toTopOf="parent"
android:text="April 2020" />
<ImageButton
android:id="#+id/forwardButton"
style="#style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="30dp"
android:layout_height="match_parent"
android:src="#drawable/ic_chevron_right"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- eventDays header -->
<LinearLayout
android:id="#+id/abbreviationsBar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="#+id/calendarHeader">
<com.\uikit.widgets.textviews.MBBody2TextView
android:id="#+id/mondayLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/material_calendar_monday"
android:textColor="#color/jumio_black" />
<com.uikit.widgets.textviews.MBBody2TextView
android:id="#+id/tuesdayLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/material_calendar_tuesday"
android:textColor="#color/jumio_black" />
<com.uikit.widgets.textviews.MBBody2TextView
android:id="#+id/wednesdayLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/material_calendar_wednesday"
android:textColor="#color/jumio_black" />
<com.uikit.widgets.textviews.MBBody2TextView
android:id="#+id/thursdayLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/material_calendar_thursday"
android:textColor="#color/jumio_black" />
<com.uikit.widgets.textviews.MBBody2TextView
android:id="#+id/fridayLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/material_calendar_friday"
android:textColor="#color/jumio_black" />
<com.uikit.widgets.textviews.MBBody2TextView
android:id="#+id/saturdayLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/material_calendar_saturday"
android:textColor="#color/jumio_black" />
<com.uikit.widgets.textviews.MBBody2TextView
android:id="#+id/sundayLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/material_calendar_sunday"
android:textColor="#color/jumio_black" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/gridScroll"
app:layout_constraintTop_toBottomOf="#+id/abbreviationsBar">
<com.payment.paymentdate.extensions.CalendarGridView
android:id="#+id/calendarViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
Because in your xml you have defined com.payment.paymentdate.extensions.CalendarGridView which is subclassof GridView and you are assigning it to ViewPager wich is type of ViewPager
<com.payment.paymentdate.extensions.CalendarViewPager
android:id="#+id/calendarViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

why my submodel cannot be cast to java.util.ArrayList

I'm making a recyclerview with multilevel data, and there is a problem when entering data into the sub-adapter. appear error like this "model cannot be cast to java.util.ArrayList android"
my json
[{
"header" : "buah air",
"sub" : {
"warna" : "merah",
"jenis" : "air"
}
},{
"header" : "buah serat",
"sub" : {
"warna" : "hijau",
"jenis" : "serat"
}
}]
my model
data class mTOP (
val header : String,
#SerializedName("sub") val sub : mSubTOP
)
data class mSubTOP(
val warna : String,
val jenis : String
)
my MainActivity
val adapter = adapter_top(response!!.body() as ArrayList<mTOP>)
rv.adapter = adapter
my adapter_top (here an error occurs)
override fun onBindViewHolder(holder: adapter_top.ViewHolder, position: Int) {
holder.tvHeader?.text = Datane[position].header
holder.rvList?.layoutManager = LinearLayoutManager(holder.rvList.context, LinearLayout.VERTICAL, false)
var adapterSub = adapter_sub(Datane[position].sub as ArrayList<mSubTOP>)
holder.rvList?.adapter = adapterSub
}
my adapter_sub
class adapter_sub(val Datane: ArrayList<mSubTOP>): RecyclerView.Adapter<adapter_sub.ViewHolder>() {
}
Because it's not ArrayList at all :) You have to create a list with one element:
adapter_sub(arrayListOf(Datane[position].sub))
this complete my adapter_sub
class adapter_sub(val Datane: ArrayList<mSubTOP>): RecyclerView.Adapter<adapter_sub.ViewHolder>() {
override fun onBindViewHolder(holder: adapter_sub.ViewHolder, position: Int) {
val location = Datane[position]
holder.tvName?.text = location.warna
holder.tvHobi?.text = location.jenis
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): adapter_sub.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.layout_sub, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return Datane.size
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val tvName = itemView.findViewById<TextView>(R.id.tvJenis)
val tvHobi = itemView.findViewById<TextView>(R.id.tvWarna)
}
}
layout activity_main.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/RvMain"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp" >
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
layout layout_top.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:gravity="center_vertical"
android:text="Date"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Large"
android:textColor="#009688"
android:textSize="18sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
layout layout_sub.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="#+id/locationBadge"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#drawable/circle_badge"
android:gravity="center_vertical|center_horizontal"
android:text="✓"
android:textColor="#fff"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/tvWarna"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="Name"
android:textSize="18sp" />
<TextView
android:id="#+id/tvJenis"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="Address"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
this my stack trace
10-20 06:24:08.445 11624-11624/br.com.mirabilis.jambu_air E/AndroidRuntime: FATAL EXCEPTION: main
Process: br.com.mirabilis.jambu_air, PID: 11624
android.view.InflateException: Binary XML file line #14: Binary XML file line #14: Error inflating class TextView
at android.view.LayoutInflater.inflate(LayoutInflater.java:543)
at android.view.LayoutInflater.inflate(LayoutInflater.java:427)
at br.com.mirabilis.jambu_air.adapter.adapter_sub.onCreateViewHolder(adapter_sub.kt:23)
at br.com.mirabilis.jambu_air.adapter.adapter_sub.onCreateViewHolder(adapter_sub.kt:13)
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6794)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5975)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3336)
at android.view.View.measure(View.java:18811)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18811)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at androidx.cardview.widget.CardView.onMeasure(CardView.java:260)
at android.view.View.measure(View.java:18811)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18811)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.measureChildWithMargins(RecyclerView.java:9119)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1583)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3641)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4194)
at android.view.View.layout(View.java:16653)
at android.view.ViewGroup.layout(ViewGroup.java:5438)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:16653)
at android.view.ViewGroup.layout(ViewGroup.java:5438)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at android.view.View.layout(View.java:16653)
at android.view.ViewGroup.layout(ViewGroup.java:5438)
at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:444)
at android.view.View.layout(View.java:16653)
at android.view.ViewGroup.layout(ViewGroup.java:5438)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at android.view.View.layout(View.java:16653)
at android.view.ViewGroup.layout(ViewGroup.java:5438)
at android.widget.LinearLayout.setCh
10-20 06:24:08.448 11624-11624/br.com.mirabilis.jambu_air E/MQSEventManagerDelegate: failed to get MQSService.
10-20 06:24:08.473 11624-11624/br.com.mirabilis.jambu_air I/Process: Sending signal. PID: 11624 SIG: 9