Draw a shape over existing view - android

I have a view and I want to draw a shape on it (circle for example) after click.
I've tried to do this but there are two problems -
onDraw is never called.
Not sure the setLayoutParams(v.getLayoutParams) will give me the result I want.
#Override
public void onClick(View v) {
CircleView circle = new CircleView(GameXoActivity.this, v.getWidth(), v.getHeight());
circle.setLayoutParams(v.getLayoutParams());
circle.startDrawing();
}
CircleView:
public CircleView(Context context, int width, int height) {
super(context);
this.width = width;
this.height = height;
}
protected void startDrawing() {
this.postInvalidate();
}
#Override
protected void onDraw(Canvas canvas) {
Log.d("TAG", "onDraw");
// draw circle
}
}
}
UPDATE:
The shape is not an image and I want to draw it with animation (I didn't write the entire code).
Also, the shape is not always a circle, so using a drawable-state is not an option.
Because there is not just one view, but 9, I don't think the making 9 more on top of them would be right.

As I'm sure you'll need to customize this quite a bit, I've left things rather generic. The following example will animate a blue circle being drawn clockwise, starting from the east (0 degrees), on top of the View's content when the View is clicked.
public class CircleView extends View
{
private static final int MARGIN = 50;
Handler handler = new Handler();
Paint paint = new Paint();
RectF rect = new RectF();
boolean drawing = false;
float sweep = 0;
public CircleView(Context context)
{
this(context, null);
}
public CircleView(Context context, AttributeSet attrs)
{
super(context, attrs);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(15);
paint.setColor(Color.BLUE);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawArc(rect, 0, sweep, false, paint);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
rect.set(MARGIN, MARGIN, w - MARGIN, h - MARGIN);
}
public void startAnimation()
{
drawing = true;
handler.post(runnable);
}
Runnable runnable = new Runnable()
{
#Override
public void run()
{
sweep += 10;
if (!(sweep > 360))
{
invalidate();
handler.postDelayed(this, 20);
}
else
{
drawing = false;
sweep = 0;
}
}
};
}
In this Activity example, I used an image that most developers would already have in their project, but it can obviously be changed to your custom image. Also, for the sake of simplicity and brevity, the CircleView is set as the entire content of the Activity, but it can easily be listed in an xml layout, as well.
public class MainActivity extends Activity
{
CircleView circle;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
circle = new CircleView(this);
circle.setBackgroundResource(R.drawable.ic_launcher);
circle.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
circle.startAnimation();
}
}
);
setContentView(circle);
}
}

I suggest, create two imageView with same dimensions, set the image you want to display on image view and then make the second image invisible .
For example :
circleimage.setVisibility(View.INVISIBLE);//now its hidden(do it OnCreate)
and then show 2ndimage when 1stimage is clicked(do it in onclick of 1st image)
circleimage.setVisibility(View.VISIBLE);

If you want to mess with drawing of the object you should overridepublic void draw(Canvas canvas) and not protected void onDraw(Canvas canvas)
EDIT:Please read comments, this first statement of my answer is probably wrong
but I would use a FrameLayout or a RelativeLayout and put the images one on top of another.
Then you can play with the visibility of the overlaying image in order to hide/show it.
EDIT:
In case your circle is not an image and needs to be drawn, make your own circle class extending View and use it as a component in the FrameLayout or RelativeLayout as you would do if it were an image

Related

How to make Circular Mask and Clip GLSurfaceView?

I work with an SDK that provides a rectangular GLSurfaceView through a callback.
I want to be able to render this view in a circular layout. (i.e.) I would like to display the view on a circular view
It's showing Circle shape when I overlay GLSurfaceView over ImageView
GLSurfaceView over ImageView
It's showing Square shape when I overlay GLSurfaceView over VideoView.
GLSurfaceView over VideoView
I have tried below code for making circle GLSurfaceView
public class SampleGLView extends GLSurfaceView implements View.OnTouchListener {
private Path clippingPath;
public SampleGLView(Context context) {
this(context, null);
}
public SampleGLView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnTouchListener(this);
}
private TouchListener touchListener;
#Override
public boolean onTouch(View v, MotionEvent event) {
final int actionMasked = event.getActionMasked();
if (actionMasked != MotionEvent.ACTION_DOWN) {
return false;
}
if (touchListener != null) {
touchListener.onTouch(event, v.getWidth(), v.getHeight());
}
return false;
}
public interface TouchListener {
void onTouch(MotionEvent event, int width, int height);
}
public void setTouchListener(TouchListener touchListener) {
this.touchListener = touchListener;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
int radius = Math.min(w, h)/2;
clippingPath = new Path();
clippingPath.addCircle(w/2, h/2, radius, Path.Direction.CW);
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();
canvas.clipPath(clippingPath);
super.dispatchDraw(canvas);
canvas.restoreToCount(count);
}
}
Question:
How do I go about clipping and rendering this as a circle?
(The background is constantly changing, so i cant overlay a transparent view on top of this video view. The aim is to have a rectangular glsurface view on top of which there is a circular glsurface view)
Is any one have idea how to solve please comment. Thanks in advance.

How to make Circular Mask and Clip GLSurfaceView in android?

I work with an SDK that provides a rectangular GLSurfaceView through a callback.
I want to be able to render this view in a circular layout. (i.e.) I would like to display the view on a circular view
It's showing Circle shape when I overlay GLSurfaceView over ImageView
GLSurfaceView over ImageView
It's showing Square shape when I overlay GLSurfaceView over VideoView.
GLSurfaceView over VideoView
I have tried below code for making circle GLSurfaceView
public class SampleGLView extends GLSurfaceView implements View.OnTouchListener {
private Path clippingPath;
public SampleGLView(Context context) {
this(context, null);
}
public SampleGLView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnTouchListener(this);
}
private TouchListener touchListener;
#Override
public boolean onTouch(View v, MotionEvent event) {
final int actionMasked = event.getActionMasked();
if (actionMasked != MotionEvent.ACTION_DOWN) {
return false;
}
if (touchListener != null) {
touchListener.onTouch(event, v.getWidth(), v.getHeight());
}
return false;
}
public interface TouchListener {
void onTouch(MotionEvent event, int width, int height);
}
public void setTouchListener(TouchListener touchListener) {
this.touchListener = touchListener;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
int radius = Math.min(w, h)/2;
clippingPath = new Path();
clippingPath.addCircle(w/2, h/2, radius, Path.Direction.CW);
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();
canvas.clipPath(clippingPath);
super.dispatchDraw(canvas);
canvas.restoreToCount(count);
}
}
Question:
How do I go about clipping and rendering this as a circle?
(The background is constantly changing, so i cant overlay a transparent view on top of this video view. The aim is to have a rectangular glsurface view on top of which there is a circular glsurface view)
Is any one have idea how to solve please comment. Thanks in advance.

How to set android xml layout to custom view and be able to draw on it

I want to add xml layout to custom view. It is done in commented section of code. But I am not able to draw after doing that. This Code paint red circle in center of screen. After uncommenting commented lines circle is not painted.
public class Main extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
}
public class MyView extends View {
Paint paint;
public MyView(Context context) {
super(context);
// View view = inflate(context, R.layout.activity_main_zadanie, null);
// view.setFocusable(true);
// addView(view);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
int radius;
radius = 100;
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawCircle(x / 2, y / 2, radius, paint);
}
}
}
Your new view is probably covering the canvas on your custom view. Try setting the background to translucent in R.layout.activity_main_zadanie.

Arc or circle not perfectly round after drawing on screen

I want to show the progress of a file upload by filling an arc untill it hits 100% (a circle). This is quite easy to do. I only needed it to rotate animated as well. When I did that I came to the conclusion that the circle is not perfectly round cause it was bouncing a bit.
Below you'll see the arc when it is at 100%.
And here a green overlay added with Photoshop which displays the imperfection of the circle.
Why is the arc/circle not round? Is this anti-aliasing? Beside that when I'm just redraw the arc on different places at the frame rate it still shows the bouncing effect.
The "debugging" code I use:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path path = new Path();
RectF drawBounds = new RectF(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
if(mProgress != 100) {
path.arcTo(drawBounds, mStartDegree, mProgress * 3.6f, true);
canvas.drawPath(path, mLoaderPaint);
}
if (mStartDegree >= 359)
mStartDegree = 0;
else
mStartDegree ++;
invalidate();
}
seems that arc drawing routine is somewhat broken, run my code and wait till angle is < 270 degs or less:
class V extends View implements Runnable {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mRect = new RectF();
private float mStartAngle;
private float mAngle;
private Xfermode mClearMmode = new PorterDuffXfermode(Mode.CLEAR);
public V(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mRect.set(0, 0, w, w);
getHandler().post(this);
}
#Override
protected void onDetachedFromWindow() {
Log.d(TAG, "onDetachedFromWindow ");
super.onDetachedFromWindow();
getHandler().removeCallbacks(this);
}
#Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(0xff00aa00);
mPaint.setXfermode(null);
canvas.drawOval(mRect, mPaint);
mPaint.setXfermode(mClearMmode);
canvas.drawArc(mRect, mStartAngle, mAngle, true, mPaint);
}
#Override
public void run() {
mStartAngle += 3.65;
mAngle += 0.2f;
invalidate();
getHandler().postDelayed(this, 20);
}
}
the good news is that you will easily find out how to use this code to get what you want

Setting image background in SurfaceView, getting black screen

Okay so Im trying to set the background of a SurfaceView to a JPG file. But it doesn't seem to want to draw the image, and all I get is a black screen.
Here:s my code:
public class FloorplanActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MapView mapView = new MapView(getApplicationContext());
setContentView(mapView);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.floorplan, menu);
return true;
}
class MapView extends SurfaceView{
Rect testRectangle1 = new Rect(0, 0, 50, 50);
Bitmap scaled;
int x;
int y;
public MapView(Context context) {
super(context);
}
public void surfaceCreated(SurfaceHolder arg0){
Bitmap background = BitmapFactory.decodeResource(getResources(), R.drawable.floorplan);
float scale = (float)background.getHeight()/(float)getHeight();
int newWidth = Math.round(background.getWidth()/scale);
int newHeight = Math.round(background.getHeight()/scale);
scaled = Bitmap.createScaledBitmap(background, newWidth, newHeight, true);
}
public void onDraw(Canvas canvas) {
canvas.drawBitmap(scaled, 0, 0, null); // draw the background
}
Not sure why it won't draw the "floorplan" image I have saved in the drawable-mdpi folder.
Anyone got any suggestions?
Thanks.
EDIT: After doing some debugging with breakpoints, it seems like the "scaled" variable becomes "Infinity" for some reason and as such the newWidth and newHeight variables become less than 0 and the application crashes.
This is only if I move the entire surfaceCreated into the contstructor, if I leave the code as is here then it doesn't do anything beyind displaying a black screen.
No idea what's causing it to do that though...
First, you should implement SurfaceHolder.Callback interface with your MapView class and set it as a callback for its SurfaceHolder to make the app call your onSurfaceCreated() metod.
Second, if you want your onDraw() method to be called, then call setWillNotDraw(false) in your MapView's constructor.
I've done that as following:
public class MapView extends SurfaceView implements SurfaceHolder.Callback {
private Bitmap scaled;
public MapView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
getHolder().addCallback(this);
}
public void onDraw(Canvas canvas) {
canvas.drawBitmap(scaled, 0, 0, null); // draw the background
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
Bitmap background = BitmapFactory.decodeResource(getResources(), R.drawable.dr);
float scale = (float) background.getHeight() / (float) getHeight();
int newWidth = Math.round(background.getWidth() / scale);
int newHeight = Math.round(background.getHeight() / scale);
scaled = Bitmap.createScaledBitmap(background, newWidth, newHeight, true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Callback method contents
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Callback method contents
}
}
And it works well.
NOTE: Moved MapView class to a separate *.java file.
Update Watch Duplicate Copy Move

Categories

Resources