I'm trying to make an Activity in which the canvas color changes when you tap the canvas.
With the code I now have, I get this error:
Attempt to invoke virtual method 'void android.graphics.Canvas.drawRect(float, float, float, float, android.graphics.Paint)' on a null object reference
This is a part of my Activity code.
public class ColorActivity extends Activity {
private float x = 0;
private float y = 0;
public Canvas canvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color);
setContentView(new MyView(this));
}
public class MyView extends View {
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
setFocusableInTouchMode(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
Paint paintCanvas = new Paint();
paintCanvas.setStyle(Paint.Style.FILL);
paintCanvas.setColor(Color.WHITE);
paintCanvas.setColor(Color.parseColor("#F44336"));
canvas.drawRect(0, 0, x, y, paintCanvas);
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Paint repaintCanvas = new Paint();
repaintCanvas.setStyle(Paint.Style.FILL);
repaintCanvas.setColor(Color.WHITE);
repaintCanvas.setColor(Color.parseColor("#2196F3"));
canvas.drawRect(0, 0, 100, 100, repaintCanvas);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
Log.d("LOG","Move");
invalidate();
break;
case MotionEvent.ACTION_UP:
Log.d("LOG", "Up");
invalidate();
break;
}
return super.onTouchEvent(event);
}
}
What am I doing wrong?
I think I know what is your problem. Invalidate calls again to the onDraw() method and it overwrites whatever you paint in the onTouchEvent method.
Try the following code:
public class ColorActivity extends Activity {
private float x = 0;
private float y = 0;
public Canvas canvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color);
setContentView(new MyView(this));
}
public class MyView extends View {
Paint paintCanvas;
public MyView(Context context) {
super(context);
paintCanvas = new Paint();
paintCanvas.setStyle(Paint.Style.FILL);
paintCanvas.setColor(Color.WHITE);
paintCanvas.setColor(Color.parseColor("#F44336"));
// TODO Auto-generated constructor stub
setFocusableInTouchMode(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
canvas.drawRect(0, 0, x, y, paintCanvas);
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
paintCanvas.setStyle(Paint.Style.FILL);
paintCanvas.setColor(Color.WHITE);
paintCanvas.setColor(Color.parseColor("#2196F3"));
invalidate();
break;
case MotionEvent.ACTION_MOVE:
Log.d("LOG","Move");
invalidate();
break;
case MotionEvent.ACTION_UP:
Log.d("LOG", "Up");
invalidate();
break;
}
return super.onTouchEvent(event);
}
}
Your Canvas is null. You will only get it inside onDraw(Canvas canvas) which is responsible for drawing on your Canvas. In your onTouchEvent, set some instance variables (such as color, positions etc.) and call invalidate(), then onDraw will be triggered and you can draw your Canvas with desired needs which you will get from the instance values you set in onTouchEvent.
Related
I use Canvas to draw bitmap by touch screen but they don't show bitmap on apps.
public class MainActivity extends Activity {
public LinearLayout screenlayout;
public void draw (int x, int y){
Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.dam);
Canvas canvas=new Canvas(b);
canvas.drawBitmap(b, x, y, null);
}
public void onCreate(Bundle saveInstanceState){
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
final LinearLayout screenlayout= (LinearLayout)findViewById(R.id.screenlayout);
screenlayout.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int x = (int) event.getRawX();
int y = (int) event.getRawY();
draw(x,y);
break;
case MotionEvent.ACTION_MOVE:
break;
default:
break;
}
return true;
}
});
}
}
As Ganpat Kaliya answer, I provide another code to solve this problem. Thanks to Ganpat Kaliya.
public class MainActivity extends Activity {
public static float vtx;
public static float vty;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Test view = new Test(this);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);
addContentView(view, params);
view.setOnTouchListener(new OnTouchListener(){
public boolean onTouch(View v, MotionEvent event) {
float a = event.getX();
float b = event.getY();
vtx=a;
vty=b;
v.invalidate();
return true;
}
});
}
}
And:
public class Test extends View {
public Test(Context context) {
super(context);
}
public void draw(Canvas canvas) {
float x=MainActivity.vtx;
float y=MainActivity.vty;
Paint paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStrokeWidth(6);
canvas.drawLine(10,10,50,50,paint);
paint.setColor(Color.RED);
canvas.drawLine(50, 50, 90, 10, paint);
canvas.drawCircle(50, 50, 3, paint);
canvas.drawCircle(x,y,10,paint);
Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.dam);
canvas.drawBitmap(b, x, y, null);
}
}
I'm trying to draw circle that follow my finger over the screen.
it's done but if I move finger fast, circle move isn't smooth.
customview.java
public customview(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
paint = new Paint();
paint.setAntiAlias(true);
paint.setARGB(255, 255, 255, 255);
}
Context context;
public static float x=100, y=100;
private Paint paint;
public static boolean drew = false;
RadialGradient radialGradient;
#Override
protected void onDraw(Canvas canvas) {
if(drew){
int ringColors[] = { 0xFF15afda, 0x0015afda };
radialGradient = new RadialGradient(x, y,100, ringColors, null,
TileMode.CLAMP);
paint.setShader(radialGradient);
canvas.drawCircle(x, y, 200, paint);
}
}
public static void setDrew(boolean drew){
customview.drew = drew;
}
public static void setXT(float x){
customview.x = x;
}
public static void setYT(float y){
customview.y = y;
}
touch event( in touch event I change x and y that shows the position of finger and set invalidate until view redraw a circle in new position )
#Override
public boolean onTouch(View v, MotionEvent event) {
dispatchGenericMotionEvent(event);
// TODO Auto-generated method stub
MotionEvent ev = event;
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
customview.setXT(ev.getRawX());
customview.setYT(ev.getRawY());
customview.setDrew(true);
(findViewById(R.id.touch)).invalidate();
break;
case MotionEvent.ACTION_UP:
customview.setDrew(false);
(findViewById(R.id.customview)).invalidate();
break;
default:
break;
}
return true;
}
Actually i am doing image editing in android and using canvas ... but i don't know ....
how to work with canvas and UI together..??
how use buttons and other widgets with canvas...??
how to make polygon editable .. so that if i touch any point then it hould highlight and i can resize the polygon.
There is my code:
public class Crop_Image_Activity1 extends Activity implements OnClickListener
{
static int count=0,i=0,j=0;
ImageView img1;
Button bt1,bt2;
Path path=new Path();
Paint mPaint;
float x_current,y_current;
float x0,y0;
float x1,y1;
float pointx[]=new float[20];
float pointy[]=new float[20];
String num;
MyView view1;
ViewGroup.LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crop__image__activity1);
img1=(ImageView)findViewById(R.id.imageView1);
bt1=(Button)findViewById(R.id.button1);
bt2=(Button)findViewById(R.id.button2);
//img1.setImageResource(R.drawable.pic1);
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(1);
view1=new MyView(this);
params =new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
addContentView(view1, params);
// bt1.setOnClickListener(this);
// bt2.setOnClickListener(this);
}
public class MyView extends View implements android.view.GestureDetector.OnGestureListener{
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private GestureDetector gestureScanner;
public MyView(Context c)
{
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
gestureScanner=new GestureDetector(this);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
return gestureScanner.onTouchEvent(event);
}
public boolean onDown(MotionEvent arg0)
{
x1=arg0.getX();
y1=arg0.getY();
if(count==-1)
{
mPath.reset();
mPath.moveTo(pointx[j],pointy[j]);
}
else if(count==0)//// storing initial points
{
mPath.moveTo(x1, y1);
mCanvas.drawCircle(x1,y1,10, mPaint);
x0=x1;
y0=y1;
pointx[i]=x1; /// storing all points in array
pointy[i]=y1;
}
else if(count>0)
{
mPath.moveTo(x_current,y_current);
mCanvas.drawCircle(x_current,y_current,10, mPaint);
}
count++;
invalidate();
return true;
}
#Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,float arg3)
{
x_current=arg1.getX();
y_current=arg1.getY();
i++;
pointx[i]=x_current;
pointy[i]=y_current;
mPath.lineTo(x_current,y_current);
mCanvas.drawPath(mPath, mPaint);
invalidate();
return true;
}
public boolean onSingleTapUp(MotionEvent e)
{
mPath.moveTo(x_current,y_current);
mPath.lineTo(x0,y0);
mCanvas.drawPath(mPath, mPaint);
invalidate();
return true;
}
public boolean onDoubleTapUp(MotionEvent e)
{
return false;
}
public void onLongPress(MotionEvent e)
{
for(j=0;j<=i;j++)
{
if((e.getX()>pointx[j]-20 && e.getX()<pointx[j]+20) && (e.getY()>pointy[j]-20 && e.getY()<pointy[j]+20))
{
mPaint.setColor(Color.BLUE);
mCanvas.drawCircle(pointx[j],pointy[j],20, mPaint);
count=-1;
invalidate();
mPaint.setColor(0xFFFF0000);
break;
}
}
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY)
{
return false;
}
#Override
public void onShowPress(MotionEvent e)
{
}
}
public void onClick(View view)
{
switch(view.getId())
{
case R.id.button1:
break;
case R.id.button2:
// Intent intent1=new Intent();
// startActivity(intent1);
break;
}
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_crop__image__activity1, menu);
return true;
}
}
If you want both your custom view and components from xml layout to appear on the screen, create a RelativeLayout and set it as activity's view. Then add your cutom view to that layout and inflate the view from your .xml file using relative layout as a parent.
Like this:
RelativeLayout relativeLayout = new RelativeLayout(this);
setContentView(relativeLayout);
layout.addView(myView);
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.activity_crop__image__activity1, relativeLayout);
About the last question try sth like this in your onTouch method
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
tx = event.getX(); // get coordinates when you touch the screen
ty = event.getY();
break;
case MotionEvent.ACTION_MOVE:
newX = event.getX(); // get coordinates when you move the finger
newY = event.getY();
for(int i = 0; i < pointx.length; i++){ // iterate over points array
if(((tx - pointx[i])*(tx - pointx[i]) + (ty - pointy[i])*(ty - pointy[i])) < 20){
// if you touched within 20 pixels of the polygon's vertex
// ...
// create Path anew replacing that vertex with coordinates newX and newY
}
}
break;
}
return true;
}
I'm making an app which paints a circle with a Touch event on the screen. The next code works fine:
Class Punto extends view{
Paint paint;
Point point = new Point();
Public Punto(Context contex){
super(context);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
paint.setColor(Color.BLUE);
canvas.drawCircle(point.x,point.y,10,paint);
}
#Override
public boolean onTouchEvent (MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
point.x = event.getX();
point.y = event.getY();
break;
}
return true;
}
class Point{
float x,y;
}
Activity:
public class Pintar extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Punto punto = new Punto(this);
setContentView(punto);
}
However I need that the circle be painted on a picture (in my case is a market's plane) but I don't know how I can do this.
Simply extend an ImageView:
class Punto extends ImageView {
I'm sorry, I assumed that the code you posted compiled...
Try this:
public class TouchImage extends ImageView {
Paint paint = new Paint();
Point point = new Point();
public TouchImage(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setColor(Color.BLUE);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(point.x, point.y, 10, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
point.x = event.getX();
point.y = event.getY();
invalidate();
}
return true;
}
class Point {
float x, y;
}
}
With a layout like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Use your reverse package name, for instance "example.com" is -->
<com.example.TouchImage
android:id="#+id/touchImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/map" />
</LinearLayout>
And an Activity that intercepts the coordinates when the TouchImage is touched:
public class Example extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TouchImage touchImage = (TouchImage) findViewById(R.id.touchImage);
touchImage.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// Call the existing onTouchEvent() in TouchImage,
// if it draws a circle fetch the coordinates
if(v.onTouchEvent(event)) {
// Do something with event.getX(), event.getY()
}
return true;
}
});
}
}
I'm trying to draw multiple rectangles. I want to be able to draw each rectangle by hand though. I can draw one but then once I call invalidate(), of course, the canvas gets cleared.
Is there another way to call the onDraw() so that the canvas doesn't get cleared?
Here's what I have:
I simply have a class which extends a SurfaceView and then
Override the onDraw
#Override
protected void onDraw(Canvas canvas)
{
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawRect(xCoor, yCoor, rectW, rectH, paint);
}
And then I Override an OnTouchEvent
#Override
public boolean onTouchEvent (MotionEvent event)
{
downX = Math.round(event.getX());
downY = Math.round(event.getY());
invalidate(); //clears canvas which I don't want
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
xCoor = downX;
yCoor = downY;
rectH = 0;
rectW = 0;
break;
case MotionEvent.ACTION_MOVE:
rectH = downY;
rectW = downX;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
Am I doing this completely wrong? :)
Any help would be appreciated.
Thanks!
You could add each rectangle to a list and iterate it onDraw like this:
import android.graphics.Rect;
private ArrayList<Rect> rectangles = new ArrayList<Rect>();
#Override
public boolean onTouchEvent (MotionEvent event) {
// ...
case MotionEvent.ACTION_UP:
rectangles.add(new Rect(xCoor, yCoor, rectW, rectH));
break;
// ...
}
#Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
for (Rect rect : rectangles) {
canvas.drawRect(rect, paint);
}
}