android cliprect with negative values does not change parent view rect - android

I have a child view and I want the canvas that to draw a circle that has "pixels" in the negative side of the axis
canvas.drawCircle(0, 0, 50f, paint);
In order to do that i use clipRect, this works fine and i see the full cirlce.
However when I use requestLayout on the parent view and changes the x,y postion of the child view
the negative sids of the circle are not shown
please advise me what to do
here is the code:
package natan.android.TestCanvas;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
public class TestCanvasActivity extends Activity {
View childView;
RelativeLayout parentView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
childView = new View(this)
{
#Override
protected void onDraw(Canvas canvas) {
canvas.clipRect(-50, -50, 50, 50,android.graphics.Region.Op.REPLACE);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
canvas.drawCircle(0, 0, 50f, paint);
super.onDraw(canvas);
}
};
parentView = new RelativeLayout(this);
parentView.addView(childView);
LayoutParams layoutParms = (LayoutParams)(childView.getLayoutParams());
layoutParms.leftMargin=150;
layoutParms.topMargin=150;
setContentView(parentView);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
LayoutParams layoutParms = (LayoutParams)(childView.getLayoutParams());
layoutParms.leftMargin=100;
layoutParms.topMargin=100;
parentView.requestLayout();
return super.onTouchEvent(event);
}
}

I think i figured out a soulation
I took it from here
http://www.devdaily.com/java/jwarehouse/android/core/java/android/view/ViewGroup.java.shtml
using this line of codes fixed the problem
parentView.setClipChildren(false);
and
parentView.requestLayout();
parentView.invalidate();
Hopes this helps someone else and If someone has more insight on this problem please add it
here is the full code:
public class TestCanvasActivity extends Activity {
View childView;
RelativeLayout parentView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
childView = new View(this)
{
#Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
canvas.drawCircle(0, 0, 50f, paint);
super.onDraw(canvas);
}
};
parentView = new RelativeLayout(this)
{
#Override
protected void onLayout(boolean changed, int l, int t,
int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
}
};
parentView.setClipChildren(false);
parentView.addView(childView);
parentView.setClipChildren(false);
LayoutParams layoutParms = (LayoutParams)(childView.getLayoutParams());
layoutParms.leftMargin=150;
layoutParms.topMargin=150;
setContentView(parentView);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
LayoutParams layoutParms = (LayoutParams)(childView.getLayoutParams());
layoutParms.leftMargin=100;
layoutParms.topMargin=100;
parentView.requestLayout();
parentView.invalidate();
return super.onTouchEvent(event);
}
}

Related

How to clear canvas in android on button click

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class SingleTouchEventView extends View {
private Paint paint = new Paint();
private Path path = new Path();
public boolean cc = false;
public SingleTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(18f);
paint.setColor(Color.LTGRAY);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
}
#Override
protected void onDraw(Canvas canvas) {
if(cc)
{
Bitmap back = BitmapFactory.decodeResource(getResources(), R.drawable.black_square);
Bitmap cb = Bitmap.createScaledBitmap(back, 0, 0, false);
canvas.drawBitmap(cb,0,0,null);
cc = false;
}
canvas.drawPath(path, paint);
}
public void clearCanvas()
{
cc =true;
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}
}
The above file is my SingleTouchEventView.Java
Here is my MainActivity.java
public class MainActivity extends Activity {
Button reset;;
LinearLayout canvasAlphabets;
SingleTouchEventView myView;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
reset = (Button)findViewById(R.id.reset_canvas);
myView = new SingleTouchEventView(this, null);
canvasAlphabets = (LinearLayout)findViewById(R.id.canvas_Alphabets);
canvasAlphabets.addView(myView);
reset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
}
}
My question is what code should I use in reset button to delete all contents of canvas.
Please help me
I have tried implementing myView.clearCanvas() but that doesn't help. If I add this code to reset buutons on Click it causes FC
Thanks
path = new Path();
Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, 0, 0, clearPaint);
cc = false;
I got it fixed with above code
Maybe I do not understand what you want to draw, but have you tried this:
protected void onDraw(Canvas canvas)
{
if (cc)
{
Bitmap back = BitmapFactory.decodeResource(getResources(), R.drawable.black_square);
Bitmap cb = Bitmap.createScaledBitmap(back, 0, 0, false);
canvas.drawBitmap(cb,0,0,null);
cc = false;
}
else
canvas.drawPath(path, paint);
}
}
Otherwise, if you want to erase all, you can use this new paint:
Paint transparent = new Paint();
transparent.setAlpha(0);
You can panit everything with a transparent color, to clear everything.

Android - Draw a rect using canvas which should raise from bottom

I want to draw a stack which should raise from the bottom. For example the stack height is 400, from the height 10 it should grow till it reaches 400.
I want to do this using paint and canvas.
I don't want to do it with image view/bitmap and scale animation.
Is it possible to do this with canvas and paint? if so how to achieve it?
Thanks in advance.
You could try using something like this (have not tested myself):
Paint paint = new Paint();
paint.setColor(Color.BLACK);
for(int i = 10; i < 400; i = i + 10)
{
try
{
// To slow the for loop down, can change 100 accordingly or remove altogther
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
canvas.drawRect(0, i, 10, 0, paint); // this will make 10 x 10 square starting from bottom
invalidate();
}
What ever you do with canvas, even if you try for loop or invalidate, sleep, after all its drawing the shape in single stretch. I found the result in following way. May be it would be helpful for someone else, so adding the code here.
import android.os.Bundle;
import android.os.CountDownTimer;
import android.app.Activity;
import android.graphics.Color;
import android.util.Log;
import android.view.Menu;
public class AndroidDraw extends Activity {
private DrawView drawView;
private int height = 300;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_draw);
CountDownTimer timer = new CountDownTimer(2000, 50) {
#Override
public void onTick(long millisUntilFinished) {
height = height - 10;
drawView = new DrawView(AndroidDraw.this, height);
drawView.setBackgroundColor(Color.WHITE);
setContentView(drawView);
}
#Override
public void onFinish() {
}
};
timer.start();
}
}
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();
private int height;
public DrawView(Context context, int height) {
super(context);
this.height = height;
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.RED);
canvas.drawRect(30, height, 60, 300, paint );
}
}

Draw Circle on top of image view

Currently on a view I have a ImageView and A custom class that draws a circle on the view. It will draw the circle on the view but it is hidden behind the image view. I know its there because when the radius is big enough I can see a small section that isn't behind the imageview. What code would bring it to the front?
EDIT: Found out that the above issue is not the problem. It seems that it is only drawing it on the portion that is reserved for the seekbar I have on the view?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_process);
mDraw = new Draw(this);
addContentView(mDraw, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
seekBar1 = (SeekBar) findViewById(R.id.seekBar1);
b = (Button) findViewById(R.id.button1);
seekBar1.setMax(500);
seekBar1.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
mDraw.setCords(500, 500, seekBar1.getProgress());
}
public void onStartTrackingTouch(SeekBar seekBar) {
mDraw.setCords(500, 500, seekBar1.getProgress());
}
public void onStopTrackingTouch(SeekBar seekBar) {
mDraw.setCords(500, 500, seekBar1.getProgress());
}
});
}
Here is the Draw class:
package org.DTS.boltsize;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
public class Draw extends View {
private int x = 1;
private int y = 1;
private int r = 1;
public Draw(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public void setCords(int mx, int my, int mr ){
x = mx;
y = my;
r = mr;
}
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
System.out.println("Drew :)");
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
canvas.drawCircle(x, y, r, paint);
super.onDraw(canvas);
}
public void DrawCirlce(Canvas canvas, int x, int y, int r){
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.GREEN);
canvas.drawCircle(x, y, r, paint);
super.onDraw(canvas);
}
}
Here is what it looks like. That red circle should cover the entire screen.
I would draw to a seperate bitmap that you have in a different imageView in the same space as your curent bitmap possibly in a FrameLayout. You can then use .bringToFront to decide the z order.
Solved by converting source to bitmap, then drawing a circle on that bitmap and sending that final bitmap to the imageview.

Only one view is displayed in Android

I am new to Android. When i run this code, only one circle is displayed. If i remove view1, then view2 is displayed. but they are never displayed together!!! why is that?
Any help would be appreciated.
thanks
package com.dots;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class Dots1Activity extends Activity
{
private static final String TAG = "DotsActivity";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
TextView label = new TextView(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
label.setText("Click the circle!");
CustomDrawableView view1 = new CustomDrawableView(this, 100, 100, 50, Color.RED);
CustomDrawableView view2 = new CustomDrawableView(this, 200, 200, 25, Color.GREEN);
CustomDrawableView view3 = new CustomDrawableView(this, 300, 300, 10, Color.WHITE);
ll.addView(label, layoutParams);
ll.addView(view1, layoutParams);
ll.addView(view2, layoutParams);
ll.addView(view3, layoutParams);
setContentView(ll);
}
}
class CustomDrawableView extends View implements OnClickListener{
private Context context;
private int x, y, radius, color;
public CustomDrawableView(Context context, int x, int y, int radius, int color) {
super(context);
this.context = context;
this.x = x;
this.y =y;
this.radius = radius;
this.color = color;
setOnClickListener(this);
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
this.setBackgroundColor(Color.LTGRAY);
Paint paint = new Paint (Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
canvas.drawCircle(x, y, radius, paint);
}
public void onClick(View v) {
Toast.makeText(this.context,
x+"-"+y+"-"+radius,
Toast.LENGTH_SHORT).show();
}
}
ll.setOrientation(LinearLayout.HORIZONTAL);
They are put next to each other. You can't see them, because your display isn't width naught. Put them in a HorizontalScrollView or make them aper VERTICAL.
I'm not sure if this takes effect here, but i found this on the Android Documentation:
Note that the framework will not draw
views that are not in the invalid
region. To force a view to draw, call
invalidate().
Try if this solves your problem (for the moment I guess).
About your Code
Something i noticed: The implemented interface for the onClickListener is View.OnClickListener:
class CustomDrawableView extends View implements View.OnClickListener{ [...] }
How to solve the Problem
I looked around on the Android Docs and found this. They mantioned the method onMeasure(), which:
Measure the view and its content to
determine the measured width and the
measured height.
So I added it to your custom CustomDrawableView-class. Unfortuandly, you can't pass the super.onMeasure()-method simple integers, you'll need to decode them first, using the View.MeasureSpec-class:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY));
}
In the Example, I set both width and height to 100px. Also, I did some other improvements on your code:
Dots1Activity-class
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;
public class Dots1Activity extends Activity
{
private static final String TAG = "DotsActivity";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
TextView label = new TextView(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
label.setText("Click the circle!");
CustomDrawableView view1 = new CustomDrawableView(this, 50, 50, 50, Color.RED);
CustomDrawableView view2 = new CustomDrawableView(this, 75, 75, 25, Color.GREEN);
CustomDrawableView view3 = new CustomDrawableView(this, 85, 85, 10, Color.WHITE);
ll.addView(label, layoutParams);
ll.addView(view1, layoutParams);
ll.addView(view2, layoutParams);
ll.addView(view3, layoutParams);
setContentView(ll);
}
}
CustomDrawableView-class
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
import android.widget.Toast;
class CustomDrawableView extends View implements View.OnClickListener{
private Context context;
private int x, y, radius, color;
public CustomDrawableView(Context context, int x, int y, int radius, int color) {
super(context);
this.context = context;
this.x = x;
this.y =y;
this.radius = radius;
this.color = color;
setOnClickListener(this);
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
canvas.drawCircle(x, y, radius, paint);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY));
}
public void onClick(View v) {
Toast.makeText(this.context,
x+"-"+y+"-"+radius,
Toast.LENGTH_SHORT).show();
}
}
This code compiles, shows all the circles and the onClick-Event works, too.
Although I have to say it was a bit of a challenge and I'm grateful for it.
change the orientation of you layout to vertical like this :
ll.setOrientation(LinearLayout.VERTICAL);

custom View not displayed well in android

My custom view does not display entirely. Please see my screenshot:
And the source code
package com.dots;
import android.graphics.Color;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class Dots1Activity extends Activity
{
private static final String TAG = "DotsActivity";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
CustomDrawableView view1 = new CustomDrawableView(this, 50, 50, Constants.DOTS_RADIUS, Constants.DOTS_COLOR);
CustomDrawableView view2 = new CustomDrawableView(this, 150, 150, Constants.DOTS_RADIUS, Constants.DOTS_COLOR);
CustomDrawableView view3 = new CustomDrawableView(this, 300, 300, Constants.DOTS_RADIUS, Constants.DOTS_COLOR);
ll.addView(view1, layoutParams);
ll.addView(view2, layoutParams);
ll.addView(view3, layoutParams);
setContentView(ll);
}
}
class CustomDrawableView extends View implements View.OnClickListener{
private Context context;
private int x, y, radius, color;
public CustomDrawableView(Context context, int x, int y, int radius, int color) {
super(context);
this.context = context;
this.x = x;
this.y =y;
this.radius = radius;
this.color = color;
setOnClickListener(this);
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
canvas.drawCircle(x, y, radius, paint);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(View.MeasureSpec.makeMeasureSpec(Constants.DOTS_RADIUS*2, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(Constants.DOTS_RADIUS*2, View.MeasureSpec.EXACTLY));
}
public void onClick(View v) {
Toast.makeText(this.context,
x+"-"+y+"-"+radius,
Toast.LENGTH_SHORT).show();
}
}
public interface Constants
{
public static final int DOTS_RADIUS = 50;
public static final int DOTS_COLOR = Color.GREEN;
public static final int NUM_DOTS_ROWS = 5;
public static final int NUM_DOTS_COLS = 5;
public static final int WIDTH_BETWEEN_DOTS = 100;
public static final int HEIGHT_BETWEEN_DOTS = 100;
}
Making the assumption that you don't want the clipping you see in your screenshot. Your problem is that the values you return in onMeasure don't account for your x, y offsets:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(View.MeasureSpec.makeMeasureSpec(Constants.DOTS_RADIUS*2 + x, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(Constants.DOTS_RADIUS*2 + y, View.MeasureSpec.EXACTLY));
}
What exactly do you want to Achieve? if you want to be fullscreen then use the FILL_PARENT flag instead of WRAP_CONTENT at least for the width of your view. also for the height there is a weight parameter that might help even the height of your view. but since its a custom drawing i cant help you further if there are any adjustments needed in your view code. you have to figure that out for yourself.
The radius of each of your "dots" is identical, and this directly translates into the answer you return in onMeasure(). You're changing the x and y location of the center, getting further from the actual View canvas.

Categories

Resources