i have custom-view like this,
public class RoundedCornerLayout extends FrameLayout
{
private final static float CORNER_RADIUS = 100.0f;
private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float cornerRadius;
public RoundedCornerLayout(Context context)
{
super(context);
init(context, null, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
init(context, attrs, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle)
{
p = new Paint();
p.setFlags(Paint.ANTI_ALIAS_FLAG);
p.setColor(Color.WHITE);
p.setStyle(android.graphics.Paint.Style.STROKE);
p.setStrokeWidth(6);
pp = new Paint();
pp.setColor(Color.parseColor("#686868"));
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setWillNotDraw(false);
}
Paint p;
Paint pp;
#Override
public void draw(Canvas canvas)
{
android.util.Log.e("MAYUR", "draw");
canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, canvas.getWidth() / 2, pp);
Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);
super.draw(offscreenCanvas);
if (maskBitmap == null)
{
maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
}
offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, (canvas.getWidth() - 6) / 2, p);
}
private Bitmap createMask(int width, int height)
{
Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas(mask);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, width, height, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);
return mask;
}
}
and i am taking screenshot like this,
View v1 = ll_contain;
v1.setDrawingCacheEnabled(true);
v1.buildDrawingCache(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
and saving bitmap to sdcard, but saving result is different than showing in screen. why? where i am going to wrong?
please give me direction to solve this problem, i tried to search problem but i didn't find this type of such problem to anyone.
show of view in screen is like,
while taking screenshot, it save like,
I was having a similar problem (for a Drawable), and the problem was essentially in using canvas.getHeight() and canvas.getWidth() methods for the position and size while making the drawCircle call. While actually drawing the view, these methods return the same values as the view dimensions, and everything went well. While drawing the screenshot, these would return the height and width of the whole screenshot instead of the the dimensions of the view.
The solution is to compute variables canvasHeight and canvasWidth as
follows:
For drawable: canvasWidth = getBounds().width();
For view: canvasWidth = getRight() - getLeft();
I tested your code and I'm not experiencing any issue/artifact when saving the drawing cache to the sdcard, as you can see in the screenshot below:
How are you saving the bitmap to the sdcard? I'm using the following method, invoked when the layout is ready:
private void saveScreenShot(){
View v1 = findViewById(R.id.container);
v1.setDrawingCacheEnabled(true);
v1.buildDrawingCache(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
FileOutputStream out = null;
try {
out = new FileOutputStream("/sdcard/test.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
You can try to force the layer type of the view to SOFTWARE in your init() method and see if something changes:
private void init(Context context, AttributeSet attrs, int defStyle){
setLayerType(LAYER_TYPE_SOFTWARE, null);
//...
}
Related
I'm using a custom class (extension of ImageView) to have an XML round image view. The problem is when I call .setColorFilter() it doesn't adhere to the same circular/round bounds.
How can I make the color filter only affect the image and not the entire rectangle of the view?
Here is my custom class for reference:
public class RoundedCornerImageFilterView extends ImageFilterView {
public RoundedCornerImageFilterView(Context context) {
super(context);
}
public RoundedCornerImageFilterView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoundedCornerImageFilterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setImageFilter(int color) {
this.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth();
int h = getHeight();
Bitmap roundedCornerBitmap = getRoundedCornerBitmap(bitmap, h, w);
canvas.drawBitmap(roundedCornerBitmap, 0, 0, null);
}
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int height, int width) {
Bitmap sbmp;
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0,
(width), (height));
final RectF rectF = new RectF(rect);
final float roundPx = 28;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
}
My xml implementation:
<MY_PATH.RoundedCornerImageFilterView
android:id="#+id/MY_IMAGE_VIEW"
android:layout_width="match_parent"
android:layout_height="150dp"
/>
Me trying to set the color filter:
MY_IMAGE_VIEW.setColorFilter(Color.parseColor(color), PorterDuff.Mode.OVERLAY)
Before the filter (looking like it's supposed to):
After setting the filter (you can see the square edges now):
Although the image (bitmap) has been given rounded corners, the canvas that it is written to has not. Since the color filter is being applied to the canvas, the tint spills out into the corners.
I suggest that you apply a rounded rectangle to a path then clip the path to the canvas. Something like this:
public class RoundedImageView extends AppCompatImageView {
private final Path mPath = new Path();
public RoundedImageView(Context context) {
super(context);
init();
}
public RoundedImageView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedImageView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setColorFilter(Color.RED, PorterDuff.Mode.OVERLAY);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mPath.reset();
mPath.addRoundRect(new RectF(0, 0, w, h), 128, 128, Path.Direction.CW);
}
#Override
public void draw(Canvas canvas) {
canvas.save();
canvas.clipPath(mPath);
super.draw(canvas);
canvas.restore();
}
}
I am using ImageView here, but the concept remains the same.
If you do this type of clipping, then rounding the bitmap becomes superfluous since it will also be clipped to the path.
I am trying to get rounded border for an imageview. Here is the code for it:
http://stackoverflow.com/a/3292810/4224275
My problem is for a normal imageview declared as follows, how do I use the class object to make the image rounded. Here is my code which didn't work.
private ImageView imageView;
imageView = (ImageView) findViewById(R.id.imageView1);
imageView.buildDrawingCache();
Bitmap bmap = imageView.getDrawingCache();
ImageHelper imh = new ImageHelper();
imh.getRoundedCornerBitmap(bmap, 10);
It doesn't work for me. I don't know what to do.
Here is the logcat output:
Take a look in my example:
public class RoundedNetworkImageView extends NetworkImageView {
public RoundedNetworkImageView(Context context) {
super(context);
}
public RoundedNetworkImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoundedNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable _drawable = getDrawable();
if (_drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap _bitmap = ((BitmapDrawable)_drawable)
.getBitmap().copy(Bitmap.Config.ARGB_8888, true);
canvas.drawBitmap(getCroppedBitmap(_bitmap, (int) (getWidth() / 1.2f)), 0,0, null);
}
public static Bitmap getCroppedBitmap(Bitmap bitmap, int radius) {
Bitmap _newBitmap;
if(bitmap.getWidth() != radius || bitmap.getHeight() != radius) {
_newBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius, false);
}
else{
_newBitmap = bitmap;
}
Bitmap _outBitmap = Bitmap.createBitmap(_newBitmap.getWidth(),
_newBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas _canvas = new Canvas(_outBitmap);
Paint _paint = new Paint();
Rect _rect = new Rect(0, 0, _newBitmap.getWidth(), _newBitmap.getHeight());
_paint.setAntiAlias(true);
_paint.setFilterBitmap(true);
_paint.setDither(true);
_canvas.drawARGB(0, 0, 0, 0);
_paint.setColor(Color.parseColor("#BAB399"));
_canvas.drawCircle(_newBitmap.getWidth() / 2, _newBitmap.getHeight() / 2,
_newBitmap.getWidth() / 2.5f, _paint);
_paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
_canvas.drawBitmap(_newBitmap, _rect, _rect, _paint);
return _outBitmap;
}
}
In the xml:
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/imgShot_shotDetail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
In the activity:
NetworkImageView imgShot = headerView.findViewById(R.id.imgShot_shotDetail);
imgShot.setImageUrl(url, AppControllerImage.getInstance().getImageLoader());
imgShot.setDefaultImageResId(R.drawable.notfound);
imgShot.setErrorImageResId(R.drawable.notfound);
In this case, I've used NetworkImageView from Volley library, but you can use a ImageView instead. You just have to adapt the code.
I am in the process of creating an app which requires irregular shaped buttons. I know that i can use image buttons and have the irregular shapes set as the images but no matter what is the shape of the image, it always occupies a rectangular area on the screen.
Is it possible to have the button occupy the exact shape of the image alone?
Do i need to create a custom control or layout for doing this or is there any other valid approach?
If i need to create a custom layout then how do i ensure that the space enclosed by all the buttons that i have placed on the layout is always circular or elliptic?
You have to override onDraw method in any view you need to shape, see this code to round ImageView
public class RoundedImageView extends ImageView {
public RoundedImageView(Context context) {
super(context);
init(context, null, 0);
}
public RoundedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
#SuppressLint("DrawAllocation") #Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = null;
int w = getWidth(), h = getHeight();
if (drawable instanceof BitmapDrawable) {
b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);
}
if (drawable instanceof LayerDrawable) {
b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
((LayerDrawable) drawable).setBounds(0, 0, w, h);
((LayerDrawable) drawable).draw( new Canvas(b));
}
}
public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
Bitmap sbmp;
if (bmp.getWidth() != radius || bmp.getHeight() != radius)
sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
else
sbmp = bmp;
Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),
Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xffa19774;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f,
sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sbmp, rect, rect, paint);
return output;
}
}
I have onDraw method where I want to cut a small piece of large bitmap. This will be a circle (position X and Y). Then I want to draw it by canvas.
I rewrite method from this answer for that reason, but always got grey circle instead circle piece of large Bitmap.
private Bitmap cutCircleBitmap() {
Bitmap output = Bitmap.createBitmap(2 * RADIUS, 2 * RADIUS, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(bitmapX - RADIUS, bitmapY - RADIUS, 2 * RADIUS, 2 * RADIUS);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(RADIUS, RADIUS, RADIUS, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
Use Canvas.drawRoundRect() and BitmapShader to do it :
public class CropView extends View {
public CropView(Context context) {
this(context, null);
}
public CropView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setFilterBitmap(true);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(radius * 2, radius * 2);
}
private Paint mPaint;
private int radius = 100;
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK); // draw background help us see the result
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sample);
canvas.drawBitmap(cropCircleBitmap(srcBitmap, 200, 60), 0, 0, mPaint);
}
private Bitmap cropCircleBitmap(Bitmap srcBitmap, float left, float top) {
Bitmap dstBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(dstBitmap);
canvas.drawBitmap(srcBitmap, -left, -top, mPaint);
mPaint.setShader(new BitmapShader(dstBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
dstBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(dstBitmap);
canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), radius, radius, mPaint);
return dstBitmap;
}
}
I'm trying to do the following you can see in the picture, but instead of that black square, I'd like to have a white square:
This is my code so far:
public class SmallWhiteThing extends View {
Context context;
Paint paint = new Paint();
// CONSTRUCTOR
public SmallWhiteThing(Context context) {
super(context);
setFocusable(true);
}
public SmallWhiteThing(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context = context;
}
public SmallWhiteThing(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap b = Bitmap.createBitmap(120, 120, Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(b);
c.drawColor(Color.WHITE);
paint.setStrokeWidth(0);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setTextSize(40);
paint.setAntiAlias(true);
c.drawText("Hello", 30, 30, paint);
canvas.drawBitmap(b, 140, 270, paint);
}
}
I tried as you can see this:
c.drawColor(Color.WHITE);
But without any luck.
Tips are really appreciated.
I'm trying somethin else, and I'm getting this:
Code:
Bitmap b = Bitmap.createBitmap(120, 120, Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(b);
c.drawColor(Color.WHITE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(0f);
c.drawRect(0, 0, 150, 150, paint);
canvas.drawBitmap(b, 100, 100, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
paint.setTextSize(40);
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
canvas.drawText("Helloo", 100, 200, paint);
For whoever needs it. This is working:
Current usage (fills a imageview in screen):
//Params: Text, textSize
createBlabla("Text to show", 35);
public void createBlabla(String text, int fontSize){
int paddingRight = 10;
int paddingLeft = 5;
int paddingBottom = 5;
//Paint config
Paint paint = new Paint();
paint.setTextSize(fontSize);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
paint.setAntiAlias(true);
Bitmap largeWhiteBitmap = Bitmap.createBitmap((int) paint.measureText(text) + paddingRight, fontSize + paddingRight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(largeWhiteBitmap);
canvas.drawColor(Color.WHITE);
canvas.drawText(text, paddingLeft, fontSize, paint);
ImageView imv = (ImageView)MainActivity.this.findViewById(R.id.imageView1);
imv.setImageBitmap(largeWhiteBitmap);
}
Note that what you see in the screen is a whole relative layout with an imageView in the middle. This imageview gets a Bitmap as Image with the previous code.
The relativeLayout has green background.