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.

Norik
  • 161
  • 1
  • 9
  • Maybe if you set `mViewPager.setOffscreenPageLimit(4);` to 1 ( 4->1), and page will be recreated each time, shadows won't render wrong? –  Ekalips Jan 20 '17 at 12:41
  • 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. – Norik Jan 20 '17 at 12:46
  • 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). –  Ekalips Jan 20 '17 at 12:50
  • 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. – Norik Jan 20 '17 at 13:12
  • 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..). –  Ekalips Jan 20 '17 at 13:20
  • 2
    did you manage to solve this after all ? – Ovidiu Latcu Aug 29 '17 at 08:37
  • @OvidiuLatcu Sadly no. We went with a design change that didn't include elevation, so our design team sort of solved our problem :/ – Norik Sep 16 '17 at 18:21

1 Answers1

-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.

Muhammad Ahmed AbuTalib
  • 4,080
  • 4
  • 36
  • 59