Shadows created with Elevation flicker when changing Fragments in a ViewPager
Asked Answered
J

1

7

I have a problem with shadows that are created with Elevation.

My screen consists of a ViewPager with 4 different Fragments and a TabLayout for navigating. The first and last fragment both contain a RecyclerView which is filled with CardView elements. Whenever I switch between pages 1 and 4, the shadows below CardView elements first appear way off their position and snap into their correct place after around half a second has passed.

This only occurs when switching between non-neighbouring fragments in the ViewPager. If I move in order from 1 to 4, this doesn't occur.

Every other element with Elevation set has this issue, not just CardView.

My ViewPager implementation:

mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (NoSwipeViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOffscreenPageLimit(4);
tabLayout.setupWithViewPager(mViewPager);

One of the CardViews used in RecyclerView

<android.support.v7.widget.CardView
        style="@style/Custom.CarView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardUseCompatPadding="true" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/post_image"
            android:layout_width="match_parent"
            android:layout_height="179dp"
            android:layout_gravity="center"
            android:scaleType="centerCrop"
            app:imageUrl="@{photo.avatar_url}"
            tools:background="@color/com_facebook_blue" />

        <Button
            android:id="@+id/edit_item_imageView"
            style="@style/Widget.AppCompat.Button.Borderless"
            android:layout_width="29dp"
            android:layout_height="37dp"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:background="@android:color/transparent" />

        <ImageView
            android:id="@+id/image_edit"
            android:layout_width="12dp"
            android:layout_height="24dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp"
            android:src="@drawable/profile_post_options" />

        <TextView
            android:id="@+id/textview_comment"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/post_image"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp"
            android:text="@{photo.description}"
            android:textColor="@color/v3_primary_gray"
            android:textSize="12sp"
            android:visibility="@{photo.description.length() > 0 ? View.VISIBLE : View.GONE}"
            tools:text="comment"
            android:layout_marginBottom="@dimen/margin_bottom_matches"/>

    </RelativeLayout>
</android.support.v7.widget.CardView>

The style of the CardView only has cardCornerRadius set to 4dp.

How exactly do shadows of Elevation work? Is there any specific attribute I need to set to prevent this? Or could I use a different method to get the same shadows I would with Elevation?

Thanks for your help.

Juli answered 20/1, 2017 at 12:36 Comment(7)
Maybe if you set mViewPager.setOffscreenPageLimit(4); to 1 ( 4->1), and page will be recreated each time, shadows won't render wrong?Embowed
Although that would fix the shadow issue, it's not a solution as the content in the fragments needs to be fetched from a server. That would cause very bad UX as the content would need to load everytime.Juli
Hm. I assume you need to use something like simple View with background (with shadow). You can simply create it with XML (just two shapes with rounded corners).Embowed
Yeah, I tried that one. The problem is, you can't get nearly as nice looking shadows as with Elevation. The two shape shadows look a bit cheap. Also changing to a regular View would cause a lot of layout issues and a lot of work to get the same appearence we currently have. I really appreciate the ideas, thanks.Juli
Involve some designer to create your view that will have right shadows. Then create 9Path image from designer image, so it will be scaled correctly. Also, I mean not really use View, but ViewGroup (RelativeLayout, Frame,Linear..).Embowed
did you manage to solve this after all ?Appreciable
@OvidiuLatcu Sadly no. We went with a design change that didn't include elevation, so our design team sort of solved our problem :/Juli
F
-1

I was struggling with the same issue and got it fixed but I exactly dont know whats up with the shadow rendering.

My problem came up when I was creating the pages in the view pager like this.

private final List<TestItem> challengeItems;
@Override
    public Object instantiateItem(ViewGroup container, int position) {

        View pageView = challengeItems.get(position);

        container.addView(view);
        return view;
    }

TestItem were an implementation of LinearLayout (I was using it as a template)

public class TestItem extends LinearLayout {

int position;


public TestItem(Context context) {
    super(context);
    init();

}

private void init() {
    inflate(getContext(), R.layout.test_card, this);
    ButterKnife.bind(this);
}

public void populateChallenge(Challenge challenge) {

}


public int getPosition() {
    return position;
}

public void setPosition(int position) {
    this.position = position;
}

}

The problem comes when the inflation of the template view is not given the container viewgroup (the viewpager's container). The fix for the shadow flicker would then be

 @Override
    public Object instantiateItem(ViewGroup container, int position) {


        View view = LayoutInflater.from(container.getContext()).inflate(R.layout.test_card, **container**, false);
        container.addView(view);
        return view;
    }

The view we are about to load into the viewpager should be inflated inside its container. Then only the ViewPager transformer would properly animate over the shadows.

Fork answered 14/10, 2017 at 17:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.