I'm working on a project that requires me to draw a circle at a random location on the screen when the user touches the screen. When the touch event occurs it also needs to remove the last circle I drew, so that there can only be one circle on the screen at one time.
I have a class Circle, that I use to create a circle:
public class Circle extends View {
private final float x;
private final float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public Circle(Context context, float x, float y, int r) {
super(context);
mPaint.setColor(0x000000);
this.x = x;
this.y = y;
this.r = r;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
}
This is the activity from which a new Circle is created. It will also monitor touch events. Right now it is drawing a circle in the upper left hand corner of the screen, but that code will need to be moved into the onTouch method. I will likely calculate the random number using Random.
public class FingerTappingActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_finger_tapping);
LinearLayout circle = (LinearLayout) findViewById(R.id.lt);
View circleView = new Circle(this, 300, 300, 150);
circleView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
circle.addView(circleView);
circle.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
}
I have never worked with touch events before such as these and have no idea how to go about this. Some tips would be greatly appreciated.
Do some thing like this ,
public class DrawCircles extends View {
private float x = 100;
private float y = 100;
private int r = 50;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
public DrawCircles(Context context) {
super(context);
init();
}
public DrawCircles(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawCircles(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
void init() {
mPaint.setColor(0x000000);
// logic for random call here;
}
Random random = new Random();
void generateRandom() {
int minRadius = 100;
int w = getWidth();
int h = getHeight();
this.x = random.nextInt(w);
this.y = random.nextInt(h);
this.r = minRadius + random.nextInt(100);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
generateRandom();
invalidate();
return super.onTouchEvent(event);
}
}
This view will draw random circles inside the view . make some adjustments for generating x & y coordinates . add this view to xml then it will work.
Related
I'm developing a game which shows shapes randomly, I got the class but I got no idea how to call the custom view from my GameFragment. I was wondering if anyone can help me to achieve it.
CustomView.java
public class CustomViews extends View {
private final int SQUARE_SIZE = 500;
private RectF rectF;
private Paint paint;
private boolean CIRCLE = false;
private boolean RECTANGLE = false;
public CustomViews(Context context) {
super(context);
init(null);
}
public CustomViews(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CustomViews(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
public CustomViews(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
private void init(#Nullable AttributeSet set) {
rectF = new RectF();
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
randomColorGenerator();
}
public void rect(Canvas canvas) {
int height = canvas.getHeight() / 2;
int width = canvas.getWidth() / 2;
rectF.set(width - 200, height - 200, width + 200, height + 200);
}
private void circle(Canvas canvas) {
float cx;
float cy;
float radius = 200;
cx = canvas.getWidth() / 2;
cy = canvas.getWidth() / 2;
canvas.drawCircle(cx, cy, radius, paint);
}
private void randomColorGenerator() {
Random random = new Random();
int choices = 3;
switch (random.nextInt(choices)) {
case 0:
paint.setColor(Color.GREEN);
break;
case 1:
paint.setColor(Color.RED);
break;
case 2:
paint.setColor(Color.BLACK);
break;
}
}
public void randomShapeGenerator(Canvas canvas) {
Random random = new Random();
int numberOfMethods = 2;
switch (random.nextInt(numberOfMethods)) {
case 0:
rect(canvas);
rectSelected();
break;
case 1:
circle(canvas);
circleSelected();
break;
}
}
public boolean circleSelected(){
RECTANGLE = false;
return CIRCLE = true;
}
public boolean rectSelected( ) {
CIRCLE = false;
return RECTANGLE = true;
}
#Override
public void onDraw(Canvas canvas) {
randomShapeGenerator(canvas);
canvas.drawRect(rectF, paint);
}
}
Now I need to call it from my GameFragment where there are some buttons and whenever you click on them a new random shape must be generate. Is anyone got any idea?
Assuming your fragment has a LinearLayout with id main_content then this might help you to add your custom view programmatically:
Button btn = findViewById(R.id.yourbutton);
btn.setOnClickListener(v -> {
LinearLayout main_layout = findViewById(R.id.main_content);
CustomViews customView = new CustomViews(this);
customView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
main_layout.addView(customView);
});
layoutParams might be also tuned according your needs.
You have to take into account where you want to display the customViews and also their sizes. For instance, if you have a linear layout with vertical orientation, you can add views in the following way:
main_layout.addView(customView, 400, 400);
This will display multiple customViews one below the other (until the screen's height is reached).
Indeed, CustomViews has to be modified a bit (here are two methods to be changed):
public void rect(Canvas canvas) {
int height = canvas.getHeight() / 2;
int width = canvas.getWidth() / 2;
rectF.set(width - 200, height - 200, width + 200, height + 200);
canvas.drawRect(rectF, paint);
}
#Override
public void onDraw(Canvas canvas) {
randomShapeGenerator(canvas);
}
I am writing a program that draws a circle at a random location on the phone screen. What it is supposed to do is when the circle is touched, it removes that circle and moves it to another random location.
Currently, when the screen is tapped the old circle is removed, and redrawn at another random location on the screen. It is very close, but I was wondering how I get over this hurdle.
public class Circle extends View {
private float x = 300;
private float y = 300;
private int r = 150;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Random random = new Random();
// draws circle
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
// constructors
public Circle(Context context) {
super(context);
init();
}
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Circle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
void init() {
// might be used later for some data collection
}
// gets random number,,
void generateRandom() {
int w = getWidth() - r - 50;
int h = getHeight()- r - 50;
int border = r + 50;
this.x = border + random.nextInt(w-border);
this.y = border + random.nextInt(h-border);
}
// when screen is tapped, old circle removed, new circle drawn
#Override
public boolean onTouchEvent(MotionEvent event) {
generateRandom();
invalidate();
return super.onTouchEvent(event);
}
}
Change the code like this ,
#Override
public boolean onTouchEvent(MotionEvent event) {
if (isInsideCircle(event.getX(), event.getY())) {
generateRandom();
invalidate();
}
return super.onTouchEvent(event);
}
boolean isInsideCircle(float xPoint, float yPoint) {
float dx = (x - xPoint);
float dxPow = (float) Math.pow(dx, 2);
float dy = (y - yPoint);
float dyPow = (float) Math.pow(dy, 2);
float radPow = (float) Math.pow(r, 2);
return (dxPow + dyPow) < radPow || (dxPow + dyPow == radPow);
}
I am new to programing. I am trying to move a circle by using the OnTouchListener, but I don't know how to call it within the onTouch event as I have a Class for Circle with x and y and a class called Drawing (d) which draws it on the canvas. I have highlighted bellow the lines which I find problematic. Thank you.
``
public class FirstPicture extends Activity implements OnTouchListener {
Drawing d;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
d=new Drawing(this);
setContentView(d);
d.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
**d.c1.getX() = event.getX();
d.c1.getY()= event.getY();**
d.invalidate();
return true;
}
}
public class Drawing extends View{
Context ctx;
Circle c1;
public Drawing(Context context) {
super(context);
this.ctx = context;
c1 = new Circle (165, 350, 33);
}
protected void onDraw (android.graphics.Canvas canvas){
Paint p = new Paint();
Paint p1 = new Paint ();
Paint p2 = new Paint ();
Paint p3= new Paint();
Paint p4 = new Paint();
p2.setColor(Color.WHITE);
p.setColor(Color.GREEN);
p3.setColor(Color.RED);
p1.setColor(Color.BLACK);
p4.setColor(Color.BLUE);
p1.setStyle(Style.FILL);
p1.setStyle(Style.FILL_AND_STROKE);
p1.setTextSize(19);
canvas.drawCircle(c1.getX(), c1.getY(), c1.getR(), p4);
canvas.drawText("100", c1.getX()-15, c1.getY()+5, p1);
}
}
public class Circle {
private float x;
private float y;
private float r;
public Circle(float x, float y, float r) {
super();
this.x = x;
this.y = y;
this.r = r;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public float getR() {
return r;
}
public void setR(float r) {
this.r = r;
}
}
You're trying to assign to a getter:
d.c1.getX() = event.getX()
How about exposing an update method on your Drawing view.
private int circleCenterX;
private int circleCenterY;
public void update(int x, int y) {
this.circleCenterX = x;
this.circleCenterY = y;
}
#Override
protected void draw(Canvas canvas) {
canvas.drawCircle(circleCenterX, circleCenterY, c1.getR(), p4);
canvas.drawText("100", c1.getX() - 15, c1.getY() + 5, p1);
}
Then your onTouch becomes:
#Override
public boolean onTouch(View v, MotionEvent event) {
d.update(event.getX(), event.getY());
return true;
}
Instantiate all your Paint objects outside of the draw method - perhaps in your constructor where you instantiate the circle. Instantiating objects is a relatively heavy operation and you don't want to do it while draw() is happening, especially as it happens 60x a second.
I'm semi-sure the draw() method on the view will automatically be called so there's no need to invalidate the view (but even if you do, it won't redraw the view until the next frame anyway - take this bullet point and this bit inside parentheses with a pinch of salt!)
I am trying to redraw the custom view in onCreate() method
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
circleView = (CircleView)findViewById(R.id.circleView);
circleView.setCircle(100, 100, 25);
circleView.wrapView();
}
and custom view is :
public class CircleView extends View
{
private Paint paint = null;
private int x = 50;
private int y = 50;
private int radius = 50;
public CircleView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public CircleView(Context context)
{
super(context);
init();
}
private void init()
{
paint = new Paint();
}
public void setCircle(int x, int y, int radius)
{
this.x = x;
this.y = y;
this.radius = radius;
init();
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
paint.setColor(Color.WHITE);
canvas.drawCircle(x, y, radius, paint);
Log.e("", "radius : " + radius);
}
public void setColor(int color)
{
paint.setColor(color);
}
public void wrapView()
{
this.setLayoutParams(new RelativeLayout.LayoutParams(radius*2, radius*2));
this.invalidate();
}
}
and xml is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/layoutMain"
>
<com.pep1439.view.CircleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/circleView" />
</RelativeLayout>
i just want to resize the circle, but failed. Help me to draw circle with any radius. How to do this. Its working fine if i use default values. It draws the circle when i remove the line circleView.setCircle(100, 100, 25);. I want to adjust circle at run time.
thanks.
You set x and y to 100 and radius to 25. Then you resize your view to radius*2, which is 50, so in the end you're drawing a circle of radius 25 at position 100,100 on a view that is only 50x50 in size. In other words: You draw your circle outside the area of your view.
I have problem with refreching canvas in my widget. I create custom widget and I want to repaint first cell on click.
There ins activity
public class TestView extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ElementView ev = (ElementView)findViewById(R.id.surface2);
ev.setOnClickListener(evOnClick);
}
public OnClickListener evOnClick = new OnClickListener() {
#Override
public void onClick(View v) {
ElementView temp=(ElementView)v;
temp.paint.setColor(Color.RED);
temp.canvas.drawRect(new Rect(0,0,90,90),temp.paint);
temp.postInvalidate();
}
};
}
and there is ElementView ( widget which I want to repaint )
public class ElementView extends View {
private final int width=100;
private final int height=100;
public Paint paint=null;
public Canvas canvas=null;
public ElementView(Context context) {
super(context);
paint = new Paint();
}
public ElementView(Context context, AttributeSet attr) {
super(context, attr);
paint = new Paint();
}
public ElementView(Context context, AttributeSet attr, int defaultStyles) {
super(context, attr, defaultStyles);
paint = new Paint();
}
#Override
protected void onMeasure(int widthSpec, int heightSpec) {
int measuredWidth = MeasureSpec.getSize(widthSpec);
int measuredHeight = MeasureSpec.getSize(heightSpec);
setMeasuredDimension(this.width,this.height);
}
#Override
protected void onDraw(Canvas canvas) {
this.canvas=canvas;
// get the size of your control based on last call to onMeasure
int height = getMeasuredHeight();
int width = getMeasuredWidth();
// Now create a paint brush to draw your widget
paint.setColor(Color.GREEN);
//define border
this.canvas.drawLine(0, 0, 0, 99, paint);
this.canvas.drawLine(0, 0, 99,0, paint);
this.canvas.drawLine(99, 0, 99, 99, paint);
this.canvas.drawLine(0, 99, 99,99, paint);
//define cells
this.canvas.drawLine(0,50,99,50,paint);
this.canvas.drawLine(30,0,30,50,paint);
//draw green rectangle
this.canvas.drawRect(new Rect(0,0,50,50),paint);
//draw some text
paint.setTextSize(8);
paint.setColor(Color.RED);
String displayText = "test";
Float textWidth = paint.measureText(displayText);
int px = width / 2;
int py = height / 2;
this.canvas.drawText(displayText, px - textWidth / 2, py, paint);
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
paint.setColor(Color.RED);
//change color of first cell
canvas.drawRect(new Rect(0,0,50,50),paint);
return super.dispatchTouchEvent(event);
}
}
When I click on ElementView it enter in Activity in onClick and pass through code without mistake or exception , but doesn't change view . Can anybody tell me where is mistake ?
I don't think writing to the Canvas outside of the onDraw method will have any effect on the screen.
Try setting a flag in your onClick method that you read in onDraw which will trigger your drawing routine.