Вопрос

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?

Это было полезно?

Решение 2

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);

Другие советы

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

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);

Try this work around: Don't need to extend ImageView

imageView.scrollTo();
imageView.setHorizontalFadingEdgeEnabled(true);
imageView.setFadingEdgeLength(40);

Just merge your drawable with your edge color in custom drawable like this... fade_image_background.xml

<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/abc" />
<item>
    <shape android:shape="rectangle">
        <gradient
            android:angle="270"
            android:endColor="#000000"
            android:startColor="#00000000"
            android:type="linear" />
    </shape>
</item>

and use this custom drawable like this..

android:background="@drawable/fade_image_background"
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top