I have an activity that has a NavHostFragment
. This NavHostFragment
will host three fragments, two of which are FragmentA
and FragmentB
. Inside FragmentB
, I have a ViewPager2
which has two pages: PageA
and PageB
, both are actually constructed from one fragment, FragmentC
. Inside each PageA
and PageB
, I have one RecyclerView
.
Here's the layout XML for FragmentB
.
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/keyline_4"
android:clipChildren="false"
android:clipToPadding="false"
tools:context=".ui.NavigationActivity">
...
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/frag_course_view_pager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="@dimen/keyline_4"
android:clipChildren="false"
... />
<com.google.android.material.tabs.TabLayout
android:id="@+id/frag_course_tablayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/keyline_4"
... />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
As you can see, I've set the fragment's root layout's clipChildren
to false
. I've also set the ViewPager2
's clipChildren
to false
. Here's the layout XML for PageA
and PageB
(i.e. FragmentC
).
<?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.mobile.tugasakhir.viewmodels.course.CourseTabViewModel" />
</data>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/frag_course_tab_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/offset_bottom_nav_bar_padding"
android:clipChildren="false"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</layout>
As you can see, it only has RecyclerView
and I've set clipChildren
to false
. The inflated XML layout for the ViewHolder of the RV is the following.
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
...
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/component_course_container"
android:layout_width="match_parent"
android:layout_height="@dimen/course_card_height"
android:background="@drawable/drawable_rounded_rect"
android:backgroundTint="?attr/colorSurface"
android:elevation="@dimen/elevation_0">
...
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The clipped portion is the shadow from the elevation
of the above ViewHolder
's XML layout. As I've set all the clipChildren
attributes from all parents to false
, the shadow shouldn't have been clipped, yet it still is. Why is this happening? How can I prevent it from being clipped without changing the padding/margin?
Note: I also have a RecyclerView
inside FragmentA
, but the difference is that the RecyclerView
inside FragmentA
is not nested within a ViewPager2
. Following the methods (setting all the parents' clipChildren
to false
) on FragmentA
allows the RecyclerView
's items to show their shadows.
Here's the image of the problem.
Update
Using the Layout Inspector, it seems like inside ViewPager2
, there are more ViewGroups (marked with the red rectangle). My RecyclerView
with its items clipped is marked with the green rectangle. Here's what the Layout Inspector shows.
As can be seen, inside ViewPager2
, there is a ViewPager2$RecyclerViewImpl
and inside it, there's a FrameLayout
(I did not create these ViewGroups). It turns out that these two have clipChildren
set to true
even when the ViewPager2
's clipChildren
is set to false. I can target the ViewPager2$RecyclerViewImpl
inside my FragmentB
like so.
(viewPager.getChildAt(0) as ViewGroup).clipChildren = false
I then tried targetting the FrameLayout
using a similar method.
((viewPager.getChildAt(0) as ViewGroup).getChildAt(0) as ViewGroup).clipChildren = false
However, I got an error saying that the second getChildAt(0)
returns null
. In my Layout Inspector, it clearly shows that there's a FrameLayout before my RecyclerView. This FrameLayout
has its clipChildren
set to true. I'm pretty sure that I have to set the FrameLayout
's clipChildren
to false
in order for shadows to not be clipped, but I may be wrong.
Here are screenshots showing that I managed to set the clipChildren
of RecyclerViewImpl
to false
and failed to set the clipChildren
of FrameLayout
to false
respectively.
Or is there a better way to unclip the shadows?
I obscured the layout preview for private reason; this causes the layout preview to be a white box.
Update 2
For those who would like to view the problem directly, simply run the app that I provided in this Github link. Use the Layout Inspector to see what I'm seeing.