I have this class:
My problem:
public class Example extends Activity implements OnClickListener{
DrawView view1;
Canvas canvas = new Canvas();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view1 = new DrawView(this);
setContentView(view1);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
view1.setFirstCoord(x, y);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
view1.setSecondCoord(x, y);
view1.dispatchDraw(canvas);
break;
}
return true;
}
public class DrawView extends LinearLayout {
private Paint paint = new Paint();
public int x1, x2;
public int y1, y2;
public DrawView(Context c){
super(c);
LayoutInflater inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
addView(inflater.inflate(R.layout.union, null));
x1 = 0;
x2 = 0;
y1 = 0;
y2 = 0;
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(10);
}
#Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.drawLine(0, 50, 900,2000 , paint);//WORKS
canvas.drawLine((int) x1, (int) y1,(int) x2,(int) y2, paint);//NO WORKS
}
public void setFirstCoord(int e, int f){
x1 = e;
y1 = f;
}
public void setSecondCoord(int e, int f){
x2 = e;
y2 = f;
}
}
}
When the next line is executed I see the "example" line on the screem:
canvas.drawLine(0, 50, 900,2000 , paint);
But when the following line "is executed" is not painted any straight line. Why???
canvas.drawLine((int) x1, (int) y1,(int) x2,(int) y2, paint);
I also tried with:
canvas.drawLine(x1, y1, x2, y2, paint);
But, obviously, the results are the same.
I also tried with executed a onDraw() method but any line is painted because onDraw paint under de "UI" (under the content of the layout .xml file)
I hope found somebody who can help me. I think the solution can very easy but I'm going crazy trying things without finding the solution.
Thanks!!!
The solution:
public class Example extends Activity implements OnClickListener{
DrawView view1;
Canvas canvas = new Canvas();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view1 = new DrawView(this);
setContentView(view1);
view1.setOnClickListener(this);
}
public class DrawView extends LinearLayout {
private Paint paint = new Paint();
public int x1, x2;
public int y1, y2;
public DrawView(Context c){
super(c);
LayoutInflater inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
addView(inflater.inflate(R.layout.union, null));
x1 = 0;
x2 = 0;
y1 = 0;
y2 = 0;
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(10);
}
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
view1.setFirstCoord(x, y);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
view1.setSecondCoord(x, y);
view1.onDraw(canvas);
view1.postInvalidate();
break;
}
return true;
}
public void setFirstCoord(int e, int f){
x1 = e;
y1 = f;
}
public void setSecondCoord(int e, int f){
x2 = e;
y2 = f;
}
public void onDraw(Canvas canvas){
canvas.drawLine((int) x1, (int) y1,(int) x2,(int) y2, paint);
}
}
}
THANKS AGAIN for your help and your attention. It's a pleasure!!!
Instead of putting your drawing code in dispatch draw, try putting it in onDraw.
Then modify your onTouch method to look like this:
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
view1.setFirstCoord(x, y);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
view1.setSecondCoord(x, y);
view1.postInvalidate();
break;
}
return true;
}
If you want to use the OnClickListener interface for this, you need to set your activity as an OnClickListener for the view:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view1 = new DrawView(this);
setContentView(view1);
// Add this:
view1.setOnClickListener(this);
}
Otherwise, onTouchEvent will never be called.
Also, onTouchEvent should be named onClick.
move OnTouchEvent to the DrawView, not the activity
Make DrawView extend View, not LinearLayout
Instead of dispatchDraw, implement method onDraw and in onTouchEvent, call invalidate()
I think your problem might be that the x/y coordinates you retrieve in the activity are in the screen space, while your draw coordinates on the canvas are in the canvas space.
So (0,0) in your activity is not the same location as (0,0) of your canvas.
You should probably receive the touchevent inside the view instead of in the activity, then the coordinate system will be the same for both the touchevent and the canvas draw.
Related
Edit :
my first part of question is unique, but the second part is similar to some other questions.
Main Problem:
this is my class code,I use this class to draw lines with custom stroke shape from drawable . I want to draw a line, but it just draw some dots as shown in the picture below. Is there any idea to fix this problem?
public class MainDrawingView extends View {
private Bitmap mBitmapBrush;
private Bitmap rBitmapBrush;
private Vector2 mBitmapBrushDimensions;
private List<Vector2> mPositions = new ArrayList<Vector2>(100);
private static final class Vector2 {
public Vector2(float x, float y) {
this.x = x;
this.y = y;
}
public final float x;
public final float y;
}
public MainDrawingView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
mBitmapBrush = BitmapFactory.decodeResource(context.getResources(), R.drawable.brush01);
rBitmapBrush = Bitmap.createScaledBitmap(mBitmapBrush, 10, 10, false);
mBitmapBrushDimensions = new Vector2(rBitmapBrush.getWidth(), rBitmapBrush.getHeight());
}
#Override
protected void onDraw(Canvas canvas) {
for (Vector2 pos : mPositions) {
canvas.drawBitmap(rBitmapBrush, pos.x, pos.y, null);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_MOVE:
final float posX = event.getX();
final float posY = event.getY();
mPositions.add(new Vector2(posX - mBitmapBrushDimensions.x / 2, posY - mBitmapBrushDimensions.y / 2));
invalidate();
}
return true;
}
}
Update:
I try another class to draw a line with my drawable, but I faced 2 new problem! the first; when I use setShader , there is no any line when touch and move my finger on the screen. and the second;when comment the setShader line in the code, I could draw a simple black line, but if I draw a curved line rapidly, the result is a broken line ! and not a true curve line.so what is your idea to solve these problems?
public class MainDrawingView extends View {
private Bitmap mBitmapBrush;
private Bitmap rBitmapBrush;
private BitmapShader mBitmapShader;
private Paint paint = new Paint();
private Path path = new Path();
public MainDrawingView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
mBitmapBrush = BitmapFactory.decodeResource(context.getResources(), R.drawable.brush01);
rBitmapBrush = Bitmap.createScaledBitmap(mBitmapBrush, 10, 10, false);
mBitmapShader = new BitmapShader(rBitmapBrush, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setAntiAlias(true);
paint.setStrokeWidth(5f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
//paint.setShader(mBitmapShader);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
#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;
default:
return false;
}
invalidate();
return true;
}
}
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 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.
I am trying to implement a simple drawable view.
Right now I am using Path's quadTo method to draw a smooth line.
And the result like this :
I don't know how can draw a line small gradually when user move his finger fast. The same with this example :
Do you know how can I get this result ? (any way, engine or open source). Right now, I am thinking about implement my own "quadTo" method. But I think it is gonna be slow (or it over my ability). Because it is a native method on Android SDK.
Thank you for any help.
this is my implement for my simple drawable view for anyone who need it:
public class TestView extends LinearLayout{
private static final String TAG = "TestView";
private PointF previousPoint;
private PointF startPoint;
private PointF currentPoint;
private static final float STROKE_WIDTH = 5f;
private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint paintBm = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap bmp;
private Canvas canvasBmp;
private Path path;
private int paintSize = 25;
public TestView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setWillNotDraw(false);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
paint.setColor(Color.BLACK);
//paint.setAlpha(100);
paintBm.setAntiAlias(true);
paintBm.setStyle(Paint.Style.STROKE);
paintBm.setStrokeJoin(Paint.Join.ROUND);
paintBm.setStrokeCap(Paint.Cap.ROUND);
paintBm.setStrokeWidth(STROKE_WIDTH);
paintBm.setColor(Color.BLACK);
paintBm.setAlpha(100);
path = new Path();
//paint.setPathEffect(new CornerPathEffect(2));
}
public TestView(Context context) {
super(context);
// TODO Auto-generated constructor stub
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
paint.setColor(Color.BLACK);
path = new Path();
//paint.setPathEffect(new CornerPathEffect(2));
}
#Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
if(bmp == null){
bmp = Bitmap.createBitmap(right-left,bottom-top,Bitmap.Config.ARGB_8888);
canvasBmp = new Canvas(bmp);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//printSamples(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
currentPoint = new PointF(event.getX(), event.getY());
previousPoint = currentPoint;
startPoint = previousPoint;
path.reset();
break;
case MotionEvent.ACTION_MOVE:
startPoint = previousPoint;
previousPoint = currentPoint;
currentPoint = new PointF(event.getX(), event.getY());
int historySize = event.getHistorySize();
for(int i = 0; i < historySize; i++){
}
drawLine(canvasBmp, path, paint, previousPoint, currentPoint);
//path.moveTo(currentPoint.x, currentPoint.y);
break;
case MotionEvent.ACTION_UP:
startPoint = previousPoint;
previousPoint = currentPoint;
currentPoint = new PointF(event.getX(), event.getY());
drawLine(canvasBmp, path, paint, previousPoint, currentPoint);
paintSize = 25;
break;
default:
break;
}
invalidate();
return true;// super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
Log.v("pichan", "dasd");
//canvas.drawBitmap(bmp, 0,0, null);
//canvas.drawColor(Color.BLUE);
//canvas.drawPath(path, paint);
canvas.drawBitmap(bmp, 0, 0, paintBm);
}
private void drawLine(Canvas canvas, Path path, Paint paint, PointF start, PointF end)
{
PointF mid1 = midPoint(previousPoint, startPoint);
PointF mid2 = midPoint(end, start);
path.reset();
paint.setStrokeWidth(paintSize);
path.moveTo(mid1.x, mid1.y);
path.quadTo(previousPoint.x, previousPoint.y, mid2.x, mid2.y);
canvas.drawPath(path, paint);
//canvas.
//paintSize -= 1;
}
private PointF midPoint(PointF p1, PointF p2)
{
return new PointF((p1.x + p2.x) / 2.0f , (p1.y + p2.y) * 0.5f);
}
}
After time researching, I build a SignView which let user sign on or draw and the result will be save to an image file.
Anyone interested in can take a look here:
SignView
Hoping this custom view can save someone time.
My basic goal is to subtract a Path from a predetermined region (also created with a Path) in Android 1.6.
Is there anyway to get Region.setPath to treat the path passed to it the same way the canvas treats a stroked path (which is what my users are seeing)?
I understand that the Style is used for Painting to the canvas, but I need the behavior to reflect what is drawn on canvas and the path being drawn is Stroked.
The behavior works find when adding shapes to the path (path.addRect, path.addCircle), but not when using lineTo, quadTo, cubeTo. My only other option is to compose a path of nothing but rects or circles.
public class ComplexRegions extends Activity {
static Display display;
/** Code Sample for StackOverflow */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
display = getWindowManager().getDefaultDisplay();
setContentView(new SampleView(this));
}
private static class SampleView extends View {
Path orig_path, finger_path;
Paint dirty_paint, fingerpaint, temp_paint;
Region orig_region, clip, fingerregion, tempregion;
Canvas c;
int h, w;
public float mX, mY, dx, dy;
boolean b;
public SampleView(Context context) {
super(context);
fingerregion = new Region();
tempregion = new Region();
orig_region = new Region();
clip = new Region();
orig_path = new Path();
finger_path = new Path();
dirty_paint = new Paint();
dirty_paint.setStyle(Paint.Style.STROKE);
dirty_paint.setColor(Color.BLUE);
dirty_paint.setStrokeWidth(5);
dirty_paint.setStrokeCap(Paint.Cap.ROUND);
dirty_paint.setStrokeJoin(Paint.Join.ROUND);
dirty_paint.setAntiAlias(false);
fingerpaint = new Paint();
fingerpaint.setColor(Color.GREEN);
fingerpaint.setStrokeWidth(10);
fingerpaint.setStyle(Paint.Style.STROKE);
fingerpaint.setStrokeCap(Paint.Cap.ROUND);
fingerpaint.setStrokeJoin(Paint.Join.ROUND);
fingerpaint.setAntiAlias(false);
temp_paint = new Paint();
temp_paint.setColor(Color.RED);
temp_paint.setStrokeWidth(1);
temp_paint.setStyle(Paint.Style.STROKE);
temp_paint.setStrokeCap(Paint.Cap.ROUND);
temp_paint.setStrokeJoin(Paint.Join.ROUND);
temp_paint.setAntiAlias(false);
w = display.getWidth();
h = display.getHeight();
clip.set(0, 0, w, h);
orig_path.addRect(w*0.25f, h*0.55f, w*0.65f, h*0.65f, Path.Direction.CW);
orig_region.setPath(orig_path, clip);
}
#Override
protected void onDraw(Canvas c) {
c.drawPath(orig_path, dirty_paint);
c.drawPath(finger_path, fingerpaint);
//following line shows that finger_path is
//behaving as though fill and stroke is on
//after being passed to the region class
c.drawPath(tempregion.getBoundaryPath(), temp_paint);
invalidate();
}
//L T R B
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
private void touch_start(float x, float y) {
finger_path.moveTo(x, y);
//finger_path.addCircle(x, y, 25, Path.Direction.CCW);
//when addCircle is only Path method used on path the result is fine
}
private void touch_move(float x, float y){
finger_path.lineTo(x, y);
}
private void touch_up() {
//*PROBLEM* Seems like setPath forces finger_path to default to fill and stroke
fingerregion.setPath(finger_path, clip);
//set tempregion to the region resulting from this Op
tempregion.op(orig_region, fingerregion, Region.Op.DIFFERENCE);
//check if the resulting region is empty
if(tempregion.isEmpty()){
for(int i = 0;i<100;i++)
Log.e("CR", "Region Completely Covered.");
}
}
}
}