I have a simple bitmap that I draw within a canvas & that I rotate using a matrix.
The problem I bump into is that using hardware acceleration the edges are not
private void fixAntiAlias(View viewFromThe80s) {
if (Build.VERSION.SDK_INT > 10) {
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
viewFromThe80s.setLayerType(View.LAYER_TYPE_SOFTWARE, p);
((View) viewFromThe80s.getParent()).setLayerType(View.LAYER_TYPE_SOFTWARE, p);
}
}
My textview used a 9-patch as a background so I couldn't add a transparent 1px border without impacting the 9-patch pixels. So, instead, I was able to get this working by disabling hardware acceleration for the given view and its parent:
I'm calling this right after view inflation. Specifically in onCreateViewHolder
in my case (in the viewholder constructor to be exact). This fixes my rotated TextView which uses a NinePatchDrawable background, similar to the following:
<TextView
android:id="@+id/text_new_feature"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:rotation="-30"
android:background="@drawable/background_new_feature"/>
Setting the antialias flag on the paint would not help anyway. To get antialiased borders on bitmap when rotating them you should add a 1px transparent border around them.
Adding this 1px transparent border is not as easy as I thought. Adding it at runtime is really messy. My app loads a lot of bitmap and to add this border I need to allocate even more bitmap to redraw them. This really bust the heap but as I took good care with avoiding any memory leak, it´s working as intended. What’s really killing me is the “lags” that this has introduced. I tracked down this fluidity lost to the GC. This last one seems to be slowing down the UI Thread when he claim back the recycled bitmaps. Using a cache is not the solution either. This is the best way towards performance but storing 500x500 PNGs (alpha obliged) is way out of proportion. So, here I am, hitting the wall. I haven’t yet tried a “draw time” way but my guess is that drawing to an off-screen bitmap buffer that I don’t think will be HW acc. (correct me if I’m wrong) won’t help my cause.
The Idea of having an “AA shader” is really seducing and I see here several advantage. It’s well supported by the hardware acceleration, will of course be a marvel for the memory (no more savage bitmap allocation) and could be totally independent from the bitmap scaling. I made a quick test and this is by far the best AA (and here I mean in quality) I ever manage to get and … it’s fast… This quick wrap-up do an upper edge AA using shaders.
BitmapShader bitmapShader = new BitmapShader(mBitmap,
TileMode.CLAMP, TileMode.CLAMP);
Matrix m = new Matrix();
m.postTranslate(0, 1);
bitmapShader.setLocalMatrix(m);
final LinearGradient AAshader = new LinearGradient(0, 0, 0, 1, 0x00000000, 0xffffffff, TileMode.CLAMP);
ComposeShader compositor = new ComposeShader(bitmapShader,
AAshader, PorterDuff.Mode.DST_IN);
mPaint.setShader(compositor);
canvas.drawRect(this.getBounds(), mPaint);
Now the big drawback ! How to get a 4 edge AA :) ??? We can probably manage an upper/lower edge AA using a multi steps Gradient but this is still dirty. A nice way will be to combine the source bitmap with some kind of 9-patch to get the transparent border, but we cannot compose 2 bitmapShader… So, here I am once again. How to get this mask Shader! Damn wall ;)