I have a class that draws a circle at the point where the user touches. However, the circle disappears whenever a new point on the same surface is touched. I would like to keep the circle and draw a new one instead. Here is my current code.
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import java.util.Random;
public class ArtSurface extends SurfaceView implements Runnable, View.OnTouchListener {
private SurfaceHolder aHolder;
private Thread aThread;
private boolean aFlag=false;
private float aX;
private float aY;
private Paint aPaint;
private Random cRandom;
public int randomColor(){
if (cRandom==null){
cRandom=new Random();
}
int randomCol=0xff000000+256*256*cRandom.nextInt(256)+256*cRandom.nextInt(256)+cRandom.nextInt(256);
return randomCol;
}
public ArtSurface(Context context, AttributeSet attrs) {
super(context, attrs);
aHolder=getHolder();
aX=-100;
aY=-100;
aPaint=new Paint();
aPaint.setColor(randomColor());
}
public void resume(){
aThread= new Thread(this);
aFlag=true;
aThread.start();
}
public void pause(){
aFlag=false;
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch(motionEvent.getAction()){
case MotionEvent.ACTION_DOWN:
aX= motionEvent.getX();
aY=motionEvent.getY();
break;
case MotionEvent.ACTION_UP:
//Leave art where it is
break;
}
return true;
}
#Override
public void run() {
while(aFlag){
if(!aHolder.getSurface().isValid())
continue;
Canvas canvas=aHolder.lockCanvas();
canvas.drawARGB(255,255,255,255);
canvas.drawCircle(aX,aY,50,aPaint);
aHolder.unlockCanvasAndPost(canvas);
}
}
}```
The way the code is currently, every new touch event causes a new circle to be drawn at the new point of touch. The previous circle is removed and I can only draw one circle at a time. My main aim is to have a new circle with a random color whenever the user touches a new point on the screen. All the other previous circles should remain where they were initially rendered. Thank you.
The line
canvas.drawARGB(255,255,255,255);
keeps drawing over the rendered circle. Removing it means that each new circle is visible on the canvas.
Related
I want to write a program which creates a button, whenever I'm touching the screen, the button should be created on the place where the screen was touched.
I wrote a program which creates circles, whenever and where the screen is touched, can anybody explain me how to make buttons instead of circles?
Thx.
Main Activity
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View.OnTouchListener;
public class SingleTouchActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SingleTouchEventView(this, null));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.single_touch, menu);
return true;
}
}
Touch Activity
import java.util.ArrayList; //not all imports are necessary
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.view.View.OnClickListener;
public class SingleTouchEventView extends RelativeLayout {
private Paint paint = new Paint();
List<Point> points = new ArrayList<Point>();
public SingleTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: // a pointer was moved
case MotionEvent.ACTION_UP:
Point p = new Point();
p.x = (int)event.getX();
p.y = (int)event.getY();
points.add(p);
Button button = new Button(getContext());
int buttonHeight = 50;
int buttonWidth = 50;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(buttonWidth, buttonHeight);
params.leftMargin = p.x;
params.topMargin = p.y;
addView(button, params);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
//DO SOMETHING! {RUN SOME FUNCTION ... DO CHECKS... ETC}
}
});
case MotionEvent.ACTION_CANCEL: {
break;
}
}
invalidate();
return true;
}
// Do something
}
First make your class extends a ViewGroup like RelativeLayout and FrameLayout in your case.
Then, on the touch event, create a Button (or a ImageView and setOnClickListener()), adjust the position of the button with margins on the view LayoutParams and add the button to the layout via addView().
Edit: The button creation will be like this on onTouchEvent():
Point p = new Point();
p.x = (int)event.getX();
p.y = (int)event.getY();
Button button = new Button(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(buttonWidth, buttonHeight);
params.leftMargin = p.x;
params.topMargin = p.y;
addView(button, params);
Also change this to be inside ACTION_UP to prevent creating multiple buttons on long pressing.
This is not possible. You can draw a circle because that is a graphic. If you were to make button appear then you would need to add it to XML. I assume you are making a game that requires elements to randomly appear. I suggest if this is the case to use and engine a spawn random circles and when touched do what you need. Hope this helps
I'm learning Android programming.
So I managed to implement a simple app that rolls a ball over the screen if you tilt yout phone. But right now it is as simple as:
if roll > 0 then xpos++ else xpos-- end and the same for ypos.
So I want to calculate a more exact direction and also I would like the ball to roll faster the more the phone is tilting.
So if I know the tilt in the roll direction and the pitch direction, how do I calculate the direction and speed of the ball?
Here is how:
package benyamephrem.tiltball;
import android.graphics.Point;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Handler;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.FrameLayout;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.SensorEventListener;
import android.widget.Toast;
public class TiltBall extends ActionBarActivity {
BallView mBallView = null;
Handler RedrawHandler = new Handler(); //so redraw occurs in main thread
Timer mTmr = null;
TimerTask mTsk = null;
int mScrWidth, mScrHeight;
android.graphics.PointF mBallPos, mBallSpd;
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE); //hide title bar
//set app to full screen and keep screen on
getWindow().setFlags(0xFFFFFFFF, LayoutParams.FLAG_FULLSCREEN | LayoutParams.FLAG_KEEP_SCREEN_ON);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tilt_ball);
//create pointer to main screen
final FrameLayout mainView = (android.widget.FrameLayout) findViewById(R.id.main_view);
//get screen dimensions
Display display = getWindowManager().getDefaultDisplay();
mScrWidth = display.getWidth();
mScrHeight = display.getHeight();
mBallPos = new android.graphics.PointF();
mBallSpd = new android.graphics.PointF();
//create variables for ball position and speed
mBallPos.x = mScrWidth / 2;
mBallPos.y = mScrHeight / 5;
mBallSpd.x = 0;
mBallSpd.y = 0;
//create initial ball
mBallView = new BallView(this, mBallPos.x, mBallPos.y, 75);
mainView.addView(mBallView); //add ball to main screen
mBallView.invalidate(); //call onDraw in BallView
//listener for accelerometer, use anonymous class for simplicity
((SensorManager) getSystemService(Context.SENSOR_SERVICE)).registerListener(
new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
//set ball speed based on phone tilt (ignore Z axis)
//***Change speed here by multiplying event values by bigger numbers***
mBallSpd.x = -event.values[0] * (30/10);
mBallSpd.y = event.values[1] * (30/10);
//timer event will redraw ball
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
} //ignore
},
((SensorManager) getSystemService(Context.SENSOR_SERVICE))
.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0),
SensorManager.SENSOR_DELAY_NORMAL);
//listener for touch event
mainView.setOnTouchListener(new android.view.View.OnTouchListener() {
public boolean onTouch(android.view.View v, android.view.MotionEvent e) {
//set ball position based on screen touch
mBallPos.x = e.getX();
mBallPos.y = e.getY();
//timer event will redraw ball
return true;
}
});
} //OnCreate
//listener for menu button on phone
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add("Exit"); //only one menu item
return super.onCreateOptionsMenu(menu);
}
//listener for menu item clicked
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
if (item.getTitle() == "Exit") //user clicked Exit
finish(); //will call onPause
return super.onOptionsItemSelected(item);
}
//For state flow see http://developer.android.com/reference/android/app/Activity.html
#Override
public void onPause() //app moved to background, stop background threads
{
mTmr.cancel(); //kill\release timer (our only background thread)
mTmr = null;
mTsk = null;
super.onPause();
}
#Override
public void onResume() //app moved to foreground (also occurs at app startup)
{
//create timer to move ball to new position
mTmr = new Timer();
mTsk = new TimerTask() {
public void run() {
//if debugging with external device,
// a log cat viewer will be needed on the device
Log.d("TiltBall", "Timer Hit - " + mBallPos.x + ":" + mBallPos.y);
//move ball based on current speed
mBallPos.x += mBallSpd.x;
mBallPos.y += mBallSpd.y;
//if ball goes off screen, reposition to opposite side of screen
if (mBallPos.x > mScrWidth) mBallPos.x = 0;
if (mBallPos.y > mScrHeight) mBallPos.y = 0;
if (mBallPos.x < 0) mBallPos.x = mScrWidth;
if (mBallPos.y < 0) mBallPos.y = mScrHeight;
//update ball class instance
mBallView.x = mBallPos.x;
mBallView.y = mBallPos.y;
//redraw ball. Must run in background thread to prevent thread lock.
RedrawHandler.post(new Runnable() {
public void run() {
mBallView.invalidate();
}
});
}
}; // TimerTask
mTmr.schedule(mTsk, 10, 10); //start timer
super.onResume();
} // onResume
#Override
public void onDestroy() //main thread stopped
{
super.onDestroy();
//wait for threads to exit before clearing app
System.runFinalizersOnExit(true);
//remove app from memory
android.os.Process.killProcess(android.os.Process.myPid());
}
//listener for config change.
//This is called when user tilts phone enough to trigger landscape view
// we want our app to stay in portrait view, so bypass event
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
}
} //TiltBallActivity
Here is the BallView class;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class BallView extends View {
public float x;
public float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//construct new ball object
public BallView(Context context, float x, float y, int r) {
super(context);
//color hex is [transparncy][red][green][blue]
mPaint.setColor(0xFF1325E0); //not transparent. color is blue
this.x = x;
this.y = y;
this.r = r; //radius
}
//qcalled by invalidate()
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, r, mPaint);
}
public int getRadius(){
return r;
}
}
This is not my code but I forgot its source so credits to whoever made it. I am using it for a current project I'm working on.
I am looking for an easy way to animate custom views in Android. I am trying to avoid using the animator object but want to work with raw threads. What I have done is created a custom view by creating a class that extends android.view.View. I then override the onDraw method and use the canvas to draw a rect. What I would like is the rect to shrink, so I keep a variable that represents the x value of the right hand side of the rectangle. I would then like the the rectangle's right edge shrink in over time. What I would have liked to do is create a new thread, start it and have it change the value of the rectangle. That all works except the view doesn't get updated until you call View.invalidate. The problem is that I can't call that from the thread that I spawned because it is not the UI thread. I read solutions on using Handlers... but I am still unsure if that is the correct solution and then how to use them.
package com.example.practicum;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
public class TimerControl extends View implements Runnable, Handler.Callback
{
private Paint paint;
private Rect rect;
private Thread t;
private Handler h;
public TimerControl(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
paint = new Paint();
paint.setColor(Color.BLUE);
rect = new Rect(0,0,60,60);
t = new Thread(this);
t.start();
h = new Handler(this);
//h.post(this);
}
#Override
public void onDraw(Canvas canvas)
{
canvas.drawRect(rect, paint);
}
#Override
public void run()
{
rect.right = rect.right-1;
while(true)
{
rect.right = rect.right-1;
this.invalidate();
try
{
Thread.sleep(5000);
h.sendEmptyMessage(0);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public boolean handleMessage(Message msg)
{
return false;
}
}
you can define a global Handler (in the UI thread):
Handler mHandler = new Handler();
then, from your thread, call:
mHandler.post(new Runnable() {
public void run() {
// call some method on the UI thread
}
});
I want to draw a line between two views how it could possible using canvas
Its simple Take one linearLayout for it between two views
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#285A8C" > //Give Color As u want
</LinearLayout>
Thanks every one i got the following solution for this I am using three layouts the middle layout i used for canvas and draw points in that canvas on button on click event
DrawView.java
package demo.example;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class DrawView extends View {
Paint paint = new Paint();
float [][] points;
public DrawView(Context context, float[][] points2, int k) {
super(context);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
this.points=points2;
}
#Override
public void onDraw(Canvas canvas) {
for(int i=0;i<points.length;i++)
{
canvas.drawLine(points[i][0],points[i][1],points[i][2],points[i][3], paint);
}
}
}
get points using following click listener
public class listener implements OnClickListener
{
int i;
listener(int k)
{
this.i=k;
}
public void onClick(View v)
{
for(int k=0;k<match1.length;k++)
{
if(match1[k].isClickable()==false)
{
if(match1[k].getId()==match2[i].getId())
{
points[k][0]=match1[k].getLeft();
points[k]1]=match1[k].getTop()+30+linearLayout2.getTop(); points[k][2]=200;
points[k][3]=match2[i].getTop()+30+linearLayout2.getTop();
match1[k].setCompoundDrawablesWithIntrinsicBounds(null, null,null,null);
match2[i].setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.bubble), null,null, null);
Toast.makeText(getBaseContext(),points[0]+"-"+points[1]+"-"+points[2]+"-"+points[3],Toast.LENGTH_SHORT).show();
ViewGroup.LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
drawView = new DrawView(getBaseContext(),points,k);
linearLayout2.addView(drawView);
}
}
}
}
}
I have to achieve that the Touch Scroll on the ViewFlipper. For Example. I have two Images. At First, ViewFlipper shows an First Image. Now I Flung the view from right to left. The First Image view Slide out left and the Second Slide in from Left. I can achieve it By this Post. But I want to Scroll the image. That is, on the Action_Move Event I want to do Touch Scroll. For Example, when I move the touch from right to left it will flung how much the touch moves. on that time the output should show both images partly.
How to do that? What I have to measure the Screen levels(height & width). Example codes are more helpful.
If you need to detect scroll on only viewflipper which is not occupying entire screen, then try the below
gestureDetector = new GestureDetector(new MyGestureDetector());
viewFlipper.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return false;
}
return true;
}
});
and MyGestureDetector will be same as in http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/
package com.appaapps.flipper;
import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ViewFlipper;
//------------------------------------------------------------------------------
// Flipper - Philip R Brenan at gmail.com
//------------------------------------------------------------------------------
public class FlipperActivity extends Activity {
ViewFlipper f;
DrawView a, b, c;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
f = new ViewFlipper(this);
a = new DrawView(this, "aaaaa");
b = new DrawView(this, "BBBBB");
c = new DrawView(this, "ccccc");
f.addView(a);
f.addView(b);
f.addView(c);
setContentView(f);
}
//------------------------------------------------------------------------------
// Draw
//------------------------------------------------------------------------------
class DrawView extends View implements View.OnTouchListener {
final String text;
DrawView(Context Context, String Text) {
super(Context);
text = Text;
setOnTouchListener(this);
}
public void onDraw(Canvas Canvas) {
super.onDraw(Canvas);
Paint p = new Paint();
p.setColor(0xffffffff);
p.setTextSize(20);
Canvas.drawText(text, 0, 20, p);
}
public boolean onTouch(View v, MotionEvent event) {
final int a = event.getAction();
if (a == MotionEvent.ACTION_DOWN) {
final int i = f.getDisplayedChild(), n = f.getChildCount();
f.setDisplayedChild((i + 1) % n);
}
return true;
}
}
}