I am trying to draw a bitmap on top right hand corner of the Canvas
So far I have done the following:
//100x40 dimensions for the bitmap
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.backbutton);
Rect source = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
Rect bitmapRect = new Rect(0, 0, canvasWidth -200,50);
canvas.drawBitmap(bitmap, source, bitmapRect, paint);
The problem is that when I run the app, the bitmap doesn't appear on the screen.
Full code:
public class MyView extends View {
Rect bitmapRect;
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); //To change body of overridden methods use File | Settings | File Templates.
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.backbutton);
Rect source = new Rect(0,0,bitmap.getWidth(), bitmap.getHeight());
bitmapRect = new Rect(0,0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, source, bitmapRect, new Paint());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
if(null != bitmapRect && bitmapRect.contains(x,y)){
Toast.makeText(view.getContext(), "this works", Toast.LENGTH_LONG).show();
}
return super.onTouchEvent(event); //To change body of overridden methods use File | Settings | File Templates.
}
Can someone help me here please?
in MyView right under Rect bitmapRect; make the variables
public int width;
public int height;
then in your MyView class put this method in there
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh)
{
width = w;
height = h;
}
now you have the width and height of the canvas that you are using
then in your onDraw() method make the bitmapRect like this
bitmapRect = new Rect(width -200,0, width, 50);
i think the problem is that how you had it you had a negative number in your rect and it was inverting the bitmap, when you use a draw command with Rects, one is the source of what your going to draw and one is the destination of where its going to be drawn
Related
Im trying to draw an arc in android, between two textView using drawArc. My requirement is to achieve an arc as shown in the image which is correct arc shape.
But when i tried ,i'm not getting an perfect arc shape and i got the arc which is of semi ovalshaped.
Here is my code snippet:
public class ArcView extends View {
final RectF oval = new RectF();
Path myPath = new Path();
Paint paint;
float left, top, right, bottom;
public FlightStatusArcView(Context context) {
super(context);
}
public FlightStatusArcView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public FlightStatusArcView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet set) {
if (set == null)
return;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public void setArcProperties(float l, float t, float r, float b) {
left = l;
top = t;
right = r;
bottom = b;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
oval.set(left, top, right, bottom);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5f);
canvas.drawArc(oval, 180f, 180f, false, paint);
drawArrow(canvas);
}
private void drawArrow(Canvas canvas) {
canvas.save();
Paint p = new Paint();
p.setColor(Color.WHITE);
p.setStyle(Paint.Style.FILL);
p.setStrokeWidth(4f);
float startX = oval.left + 20;
float startY = oval.top + (oval.centerY() - oval.top)/ 2;
Path path = new Path();
path.moveTo(startX, startY-20);
path.lineTo(startX + 20, startY + 20);
path.lineTo(startX + 30, startY -17);
path.close();
canvas.drawPath(path, p);
canvas.restore();
}
}
Please help how to achieve the perfect arc shape using the canvas apis.
You could use a Path together with quadTo or cubicTo to draw a curve like this. This will allow you to draw quadratic or cubic bezier curves. For instance, a cubic bezier curve with two identical control points (x2, y2) is constructed like this:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5f);
Path p = new Path();
float x1 = 100;
float y1 = 256;
float x2 = 400;
float y2 = 32;
float x3 = 700;
float y3 = 256;
p.moveTo(x1, y1);
p.cubicTo(x2, y2, x2, y2, x3, y3);
canvas.drawPath(p, paint);
drawArrow(canvas);
}
This is the result:
You can find more information on cubicTo and quadTo in the official documentation
I have a method to Cropped image to circle and work fine but need scale type to center crop or center in image but dont work if I define in XML file.
In xml value= SCALE TYPE= CENTER_CROP OR SCALE_TYPE CENTER
This is my class button:
public class CircleImage extends ImageView {
public CircleImage(Context context) {
super(context);
}
public CircleImage(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImage(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 b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth(), h = getHeight();
Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);
}
public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
Bitmap sbmp;
if (bmp.getWidth() != radius || bmp.getHeight() != radius) {
float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
float factor = smallest / radius;
sbmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / factor), (int)(bmp.getHeight() / factor), false);
} else {
sbmp = bmp;
}
Bitmap output = Bitmap.createBitmap(radius, radius,
Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xffa19774;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, radius, radius);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(radius / 2 + 0.7f,
radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sbmp, rect, rect, paint);
return output;
}
}
Pass a complete and fixed class for circle image and center scale type
public class CircleImage extends ImageView {
public CircleImage(Context context) {
super(context);
}
public CircleImage(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImage(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 b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth(), h = getHeight();
Bitmap bm_scale_center_crop;
if (bitmap.getWidth() >= bitmap.getHeight()){
bm_scale_center_crop = Bitmap.createBitmap(
bitmap,
bitmap.getWidth()/2 - bitmap.getHeight()/2,
0,
bitmap.getHeight(),
bitmap.getHeight()
);
}else{
bm_scale_center_crop = Bitmap.createBitmap(
bitmap,
0,
bitmap.getHeight()/2 - bitmap.getWidth()/2,
bitmap.getWidth(),
bitmap.getWidth()
);
}
Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);
}
I'm trying to get the text view '2' (in black) to appear in the centre of my view but for some reason it won't appear. Does anyone know what's wrong here and how this error can be fixed? Is there way of showing it and changing the colour of it programmatically rather than using XML?
XML
<com.apptacularapps.car.RectangleTextView
android:layout_width="120dp"
android:layout_height="40dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="2"
android:gravity="center"
android:background="#808080"/>
Java
public class RectangleTextView extends View {
Paint paint;
private TextPaint mTextPaint;
public RectangleTextView(Context context) {
super(context);
init();
}
public RectangleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RectangleTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(1); // convert to dp?
paint.setStyle(Paint.Style.STROKE); // delete line for filled rect
mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("2", 0, 0, paint);
paint.setTextSize(20);
int w = canvas.getWidth();
int h = canvas.getHeight();
int rectWidth = w/5;
int space = w/15;
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
for (int i = 0; i < 4; i++) {
int left = i * (rectWidth + space);
int right = left + rectWidth;
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
}
}
You do not have a paint object that defines how your text will be drawn and neither have you called canvas.drawText() in your onDraw() method. Do it this way:
private TextPaint mTextPaint;
private void init() {
mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
// You can tweak the appearance of the textpaint here
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setColor(color);
}
#Override
public void onDraw() {
super.onDraw()
// You can tweak the positioning of the text here
canvas.drawText("2", 25, 25, mTextPaint);
}
I have 2 bitmaps on a canvas. ontouching the top bitmap , the lower bitmap should be visible and the top bitmap should be erased.
I took help from this thread. Make certain area of bitmap transparent on touch. I can see the bottom bitmap through the circle, but the top bitmap is not erasing on touching. How to erase the the bitmap on touching. I know that this question has been asked before, but i am not able to solve the problem.
this is my code:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new Panel(this));
}
class Panel extends View {
Bitmap bmOverlay;
private Paint mPaint;
Bitmap bm2, bm1;
Bitmap bitmap;
Canvas pcanvas;
int x = 0;
int y = 0;
int r = 0;
public Panel(Context context) {
super(context);
setFocusable(true);
setBackgroundColor(Color.TRANSPARENT);
// setting paint
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.TRANSPARENT);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
mPaint.setAntiAlias(true);
bm1 = BitmapFactory.decodeResource(getResources(), R.drawable.aa);
bm2 = BitmapFactory.decodeResource(getResources(), R.drawable.aaa);
bmOverlay = Bitmap.createBitmap(bm1.getWidth(), bm1.getHeight(),
Bitmap.Config.ARGB_8888);
pcanvas = new Canvas(bmOverlay);
}
#Override
protected void onDraw(Canvas canvas) {
// draw a circle that is erasing bitmap
super.onDraw(canvas);
canvas.drawBitmap(bm2, 0, 0, null);
pcanvas.drawBitmap(bm1, 0, 0, null);
pcanvas.drawCircle(x, y, 40, mPaint);
canvas.drawBitmap(bmOverlay, 0, 0, null);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// set parameter to draw circle on touch event
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
x = (int) ev.getX();
y = (int) ev.getY();
invalidate();
break;
}
case MotionEvent.ACTION_MOVE: {
x = (int) ev.getX();
y = (int) ev.getY();
invalidate();
break;
}
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}
}
You need to make two changes to get the top bitmap to erase. First, make it a mutable Bitmap so that you can change the contents as it is erased:
Bitmap temp = BitmapFactory.decodeResource(getResources(), R.drawable.aa);
bm1 = temp.copy(Bitmap.Config.ARGB_8888, true); // mutable = true
Be careful about out of memory errors here.
Secondly, in your onDraw function, update the bitmap contents by writing back to bm1:
#Override
protected void onDraw(Canvas canvas) {
// draw a circle that is erasing bitmap
super.onDraw(canvas);
canvas.drawBitmap(bm2, 0, 0, null);
pcanvas.drawBitmap(bm1, 0, 0, null);
pcanvas.drawCircle(x, y, 40, mPaint);
canvas.drawBitmap(bmOverlay, 0, 0, null);
// erase the top bitmap:
Canvas bitmapCanvas = new Canvas(bm1);
bitmapCanvas.drawBitmap(bm2, 0, 0, null);
bitmapCanvas.drawBitmap(bmOverlay, 0, 0, null);
}
Also, to stop a circle being erased in the top left corner when you start the app, create a boolean with a default value of false and set it inside onTouchEvent when you have valid co-ordinates, and check it before calling drawCircle.
I need to denote progress by the border of view.
E.g. Initially view will not have any border at all, when 50% progress is reached, only 50% of view will get border.Find the attached image.
I did lot of googling but no luck.The view I used is textview.
Edited
The following code, cuts the edges of bitmap.
What I've done in this code is -
1. Bg is set to Black Hexagon
2. And I've taken hollow green bordered hexagon & revealing this hollow hexagon, so that it will look like border is getting accumulated.
public class MyView extends View {
private Bitmap mBitmap;
private Paint mPaint;
private RectF mOval;
private float mAngle = 135;
private Paint mTextPaint;
private Bitmap bgBitmap;
public MyView(Context context) {
super(context);
doInit();
}
/**
* #param context
* #param attrs
* #param defStyleAttr
*/
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
doInit();
}
/**
* #param context
* #param attrs
*/
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
doInit();
}
private void doInit() {
// use your bitmap insted of R.drawable.ic_launcher
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.hexagon_border);
bgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.view_message_small_hexagon);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOval = new RectF();
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(48);
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setColor(0xffffaa00);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Matrix m = new Matrix();
RectF src = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
RectF dst = new RectF(0, 0, w, h);
m.setRectToRect(src, dst, ScaleToFit.CENTER);
Shader shader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
shader.setLocalMatrix(m);
mPaint.setShader(shader);
m.mapRect(mOval, src);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(0xff0000aa);
Matrix matrix = new Matrix();
canvas.drawBitmap(bgBitmap, matrix, null);
canvas.drawArc(mOval, -90, mAngle, true, mPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mAngle = (float) Math.toDegrees(Math.atan2(event.getY() - h2, event.getX() - w2));
mAngle += 90 + 360;
mAngle %= 360;
invalidate();
return true;
}
}
try this SO answer:
public class MyView extends View {
private Bitmap mBitmap;
private Paint mPaint;
private RectF mOval;
private float mAngle = 135;
private Paint mTextPaint;
public MyView(Context context) {
super(context);
// use your bitmap insted of R.drawable.ic_launcher
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOval = new RectF();
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(48);
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setColor(0xffffaa00);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Matrix m = new Matrix();
RectF src = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
RectF dst = new RectF(0, 0, w, h);
m.setRectToRect(src, dst, ScaleToFit.CENTER);
Shader shader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
shader.setLocalMatrix(m);
mPaint.setShader(shader);
m.mapRect(mOval, src);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xff0000aa);
canvas.drawArc(mOval, -90, mAngle, true, mPaint);
canvas.drawText("click me", getWidth() / 2, getHeight() / 2, mTextPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mAngle = (float) Math.toDegrees(Math.atan2(event.getY() - h2, event.getX() - w2));
mAngle += 90 + 360;
mAngle %= 360;
invalidate();
return true;
}
}
Getting a good circular progress spinner is difficult in itself. The ProgressWheel is a good custom View that does this. You should be able to modify the ProgressWheel's onDraw() class to do something very similar to what you want.