Rishabh876 Rishabh876 - 4 months ago 8
Java Question

Custom ImageView loses transparency as soon as it goes out of screen in recycleView

I have a custom ImageView that overrides onDraw method to crop corners using Path to give rounded corner of given radius. I have a RecyclerView where I have these custom ImageView in all of the 4 items. Now the problem is this custom ImageView renders fine for the first time it shows up in the list. Only 2 accommodate in the screen at a time. As I scroll down everything is fine in all views. I can see rounded corner in all of them. But when I scroll up to previous item. Now these corner lose their transparency in corners and become black in all but third item in the list. Canvas in onDraw also has

isOpaque = true
. I have tried many things but nothing seem to be working. Here is the code

public class RoundedImageView extends ImageView
{
private Paint mPaint;
private int mCornerRadius = 0;
private boolean mRoundedTopLeft = true, mRoundedBottomLeft = true, mRoundedTopRight = true, mRoundedBottomRight = true;

public void setCornerRadius(int mCornerRadius)
{
this.mCornerRadius = mCornerRadius;
}

public void RoundCorners(boolean isRoundedTopLeft, boolean isRoundedTopRight, boolean isRoundedBottomLeft, boolean isRoundedBottomRight)
{
mRoundedTopLeft = isRoundedTopLeft;
mRoundedBottomLeft = isRoundedBottomLeft;
mRoundedBottomRight = isRoundedBottomRight;
mRoundedTopRight = isRoundedTopRight;
}

public RoundedImageView(Context context)
{
super(context);
if (Build.VERSION.SDK_INT >= 11)
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
setupPaint();
}

public RoundedImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
if (Build.VERSION.SDK_INT >= 11)
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
setupPaint();
}

public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
if (Build.VERSION.SDK_INT >= 11)
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
setupPaint();
}

@TargetApi(21)
public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
if (Build.VERSION.SDK_INT >= 11)
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
setupPaint();

}

private Paint setupPaint()
{
mPaint = new Paint();
mPaint.setColor(Color.TRANSPARENT);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStrokeWidth(1);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
return mPaint;
}

@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);

Path path = RoundedRect(0, 0, getWidth(), getHeight(), mCornerRadius, mCornerRadius,
mRoundedTopLeft, mRoundedTopRight, mRoundedBottomRight, mRoundedBottomLeft);
canvas.drawPath(path, mPaint);
}

public static Path RoundedRect(
float left, float top, float right, float bottom, float rx, float ry,
boolean tl, boolean tr, boolean br, boolean bl)
{
Path path = new Path();
if (rx < 0) rx = 0;
if (ry < 0) ry = 0;
float width = right - left;
float height = bottom - top;
if (rx > width / 2) rx = width / 2;
if (ry > height / 2) ry = height / 2;
float widthMinusCorners = (width - (2 * rx));
float heightMinusCorners = (height - (2 * ry));

path.moveTo(right, top + ry);
if (tr)
path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
else
{
path.rLineTo(0, -ry);
path.rLineTo(-rx, 0);
}
path.rLineTo(-widthMinusCorners, 0);
if (tl)
path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
else
{
path.rLineTo(-rx, 0);
path.rLineTo(0, ry);
}
path.rLineTo(0, heightMinusCorners);

if (bl)
path.rQuadTo(0, ry, rx, ry);//bottom-left corner
else
{
path.rLineTo(0, ry);
path.rLineTo(rx, 0);
}

path.rLineTo(widthMinusCorners, 0);
if (br)
path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
else
{
path.rLineTo(rx, 0);
path.rLineTo(0, -ry);
}

path.rLineTo(0, -heightMinusCorners);

path.close();//Given close, last lineto can be removed.

path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
return path;
}
}


What I have already tried:
- setting isRecyclable false in ViewHolder


  • setting different PorterDuff mode in paint

  • LAYER_TYPE_HARDWARE (hardware acceleration) for this view

  • setDrawingCacheBackgroundColor(0x00000000);
    in constructor

  • setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
    passing paint in this function

  • tried making canvas transparent before
    super.onDraw()



UPDATE:

After a lot of fiddling around I have concluded that whenever my viewHolder's view goes out of screen. All it's alpha channel become black. I have a feeling it has to do something with the
setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Answer

Worked by making the parent software accelerated.

I solved it by putting

if (Build.VERSION.SDK_INT >= 11)
                view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

in constructor of my ViewHolder. It worked even if I enabled software acceleration for any parent container view.

Now I don't know why this worked.

Comments