Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply fading edges to ImageView

Is there any way to apply vertical/horizontal fading edges to an ImageView component?

I already tried android:fadingEdge but unfortunately this attribute is deprecated and will be ignored as of API level 14, Any ideas?

like image 824
NullPointer Avatar asked Feb 19 '14 18:02

NullPointer


3 Answers

I have found a neat workaround that worked perfectly for me. I needed to fade out the top and the bottom of the imageView (this approach works for any side though, simply create a different gradient). I wrapped the ImageView inside of a FrameLayout and put 2 Views to the top and bottom, after that, I created the xml's with gradients for the background of these and simply put them as backgrounds. Here's how it looks:

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="centerCrop"
            android:adjustViewBounds="true" />
        <View
            android:layout_width="match_parent"
            android:layout_height="@dimen/fade_effect_heigth"
            android:layout_gravity="bottom"
            android:background="@drawable/custom_gradient_bottom"/>
        <View
            android:layout_width="match_parent"
            android:layout_height="@dimen/fade_effect_heigth"
            android:layout_gravity="top"
            android:background="@drawable/custom_gradient_top"/>
</FrameLayout>

Now the 2 Views are on top of the image view, and their gradient xml background files look like this (this is the top gradient, bottom is the same just flip the start/end color):

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<gradient
    android:angle="90"
    android:startColor="#00000000" <- black with 0 alpha, so transparent
    android:endColor="#000000" <- black color
    android:type="linear" />

You can choose the height of the fade that works for you, I chose 120dp and it served my needs well. Here's a screenshot from my emulator of the ImageView only:

enter image description here

like image 159
Vucko Avatar answered Oct 09 '22 16:10

Vucko


I create the following extend of ImageView to incorporate it with horizontal fading, you can easily change this class and add vertical fading. (Tested with the latest android version 4.4.2)

Base class:

public class FadingImageView extends ImageView {
    private FadeSide mFadeSide;

    private Context c;

    public enum FadeSide {
        RIGHT_SIDE, LEFT_SIDE
    }

    public FadingImageView(Context c, AttributeSet attrs, int defStyle) {
        super(c, attrs, defStyle);

        this.c = c;

        init();
    }

    public FadingImageView(Context c, AttributeSet attrs) {
        super(c, attrs);

        this.c = c;

        init();
    }

    public FadingImageView(Context c) {
        super(c);

        this.c = c;

        init();
    }

    private void init() {
        // Enable horizontal fading
        this.setHorizontalFadingEdgeEnabled(true);
        // Apply default fading length
        this.setEdgeLength(14);
        // Apply default side
        this.setFadeDirection(FadeSide.RIGHT_SIDE);
    }

    public void setFadeDirection(FadeSide side) {
        this.mFadeSide = side;
    }

    public void setEdgeLength(int length) {
        this.setFadingEdgeLength(getPixels(length));
    }

    @Override
    protected float getLeftFadingEdgeStrength() {
        return mFadeSide.equals(FadeSide.LEFT_SIDE) ? 1.0f : 0.0f;
    }

    @Override
    protected float getRightFadingEdgeStrength() {
        return mFadeSide.equals(FadeSide.RIGHT_SIDE) ? 1.0f : 0.0f;
    }

    @Override
    public boolean hasOverlappingRendering() {
        return true;
    }

    @Override
    public boolean onSetAlpha(int alpha) {
        return false;
    }

    private int getPixels(int dipValue) {
        Resources r = c.getResources();

        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dipValue, r.getDisplayMetrics());
    }
}

Usage:

- Create the following object in your XML:

<com.your.package.FadingImageView
    android:id="@+id/fade_image_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/some_drawable" />

- Then apply your desired fade side:

    FadingImageView mFadingImageView = (FadingImageView) findViewById(R.id.fade_image_view);

    mFadingImageView.setEdgeLength(28);

    mFadingImageView.setFadeDirection(FadeSide.RIGHT_SIDE);
like image 34
NullPointer Avatar answered Oct 09 '22 17:10

NullPointer


A small addition to Vucko's answer.

This class can add fade to multiple edges at once.

public class FadingImageView extends AppCompatImageView {


    private boolean mFadeRight;
    private boolean mFadeLeft;
    private boolean mFadeTop;
    private boolean mFadeBottom;

    private Context c;



    public FadingImageView(Context c, AttributeSet attrs, int defStyle) {
        super(c, attrs, defStyle);

        this.c = c;

        init();
    }

    public FadingImageView(Context c, AttributeSet attrs) {
        super(c, attrs);

        this.c = c;

        init();
    }

    public FadingImageView(Context c) {
        super(c);

        this.c = c;

        init();
    }

    private void init() {
        // Enable horizontal fading
        this.setHorizontalFadingEdgeEnabled(true);
        this.setVerticalFadingEdgeEnabled(true);
        // Apply default fading length
        this.setEdgeLength(14);
        // Apply default side
        this.setFadeRight(true);
    }




    public void setFadeRight(boolean fadeRight) {
        mFadeRight = fadeRight;
    }



    public void setFadeLeft(boolean fadeLeft) {
        mFadeLeft = fadeLeft;
    }


    public void setFadeTop(boolean fadeTop) {
        mFadeTop = fadeTop;
    }

    public void setFadeBottom(boolean fadeBottom) {
        mFadeBottom = fadeBottom;
    }

    public void setEdgeLength(int length) {
        this.setFadingEdgeLength(getPixels(length));
    }


    @Override
    protected float getTopFadingEdgeStrength() {
        return mFadeTop ? 1.0f : 0.0f;
    }

    @Override
    protected float getBottomFadingEdgeStrength() {
        return mFadeBottom ? 1.0f : 0.0f;
    }

    @Override
    protected float getLeftFadingEdgeStrength() {
        return mFadeLeft ? 1.0f : 0.0f;
    }

    @Override
    protected float getRightFadingEdgeStrength() {
        return mFadeRight ? 1.0f : 0.0f;
    }

    @Override
    public boolean hasOverlappingRendering() {
        return true;
    }

    @Override
    public boolean onSetAlpha(int alpha) {
        return false;
    }

    private int getPixels(int dipValue) {
        Resources r = c.getResources();

        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dipValue, r.getDisplayMetrics());
    }
}

And to add fade to all edges

 mFadingImageView.setFadeTop(true);
 mFadingImageView.setFadeBottom(true);
 mFadingImageView.setFadeLeft(true);
 mFadingImageView.setFadeRight(true);
like image 38
Abdullah Saleh Avatar answered Oct 09 '22 16:10

Abdullah Saleh