I think that my problem is minor but I can't find solution. I am trying to make application which will help me to make WEB pages and I want to make application which will put graphic element on the screen.
I made drawable png images of rectangles and I can put them on the screen where I want, no problem, but I can not make new graphic/bitmap.
How I can put new graphics object on the screen when I press in meni DIV or iFrame?
public class Objects extends View {
private float X;
private float Y;
private Paint myPaint;
final String C_DIV = "DIV";
final String C_TABLE = "Table";
final String C_IFRAME = "iFrame";
final String C_LIST = "List";
Canvas canvas;
Bitmap divimg = BitmapFactory.decodeResource(getResources(), R.drawable.div);
Bitmap iframeimg = BitmapFactory.decodeResource(getResources(), R.drawable.iframe);
Bitmap img = null;
String objectname = " ";
public Objects(Context context) {
super(context);
myPaint = new Paint();
}
public void HTMLObjects(String object) {
Log.d(object, "see");
if (object.equals(C_DIV)) {
myPaint.setColor(Color.GREEN);
img = Bitmap.createBitmap(divimg);
objectname = "DIV";
}
if (object.equals(C_IFRAME)) {
myPaint.setColor(Color.BLUE);
img = Bitmap.createBitmap(iframeimg);
objectname = "iFrame";
}
}
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
X = (int) event.getX();
Y = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
X = (int) event.getX();
Y = (int) event.getY();
break;
}
return true;
}
public void onDraw(Canvas canvas) {
if (img != null) {
canvas.drawBitmap(img, X - 50, Y - 50, myPaint);
canvas.drawText(objectname, X, Y - 50, myPaint);
}
invalidate();
}
}
This is a class which I am calling from the activity Workspace with
ob.HTMLObjects((String) item.getTitle());
and I am sending information which menu is pressed.
I do not know how to make new/different object/bitmap when I pressed DIV or iFrame.
Try these version. I replaces x,y,img,objectname with according lists:
public class Objects extends View {
private Paint myPaint;
public final String C_DIV="DIV";
public final String C_TABLE="Table";
public final String C_IFRAME="iFrame";
public final String C_LIST="List";
private Canvas canvas;
private Bitmap divimg= BitmapFactory.decodeResource(getResources(), R.drawable.div);
private Bitmap iframeimg=BitmapFactory.decodeResource(getResources(), R.drawable.iframe);
private List<Bitmap> images;
private List<Float> xs;
private List<Float> ys;
private List<String> objectNames;
public Objects(Context context) {
super(context);
myPaint = new Paint();
images = new ArrayList<Bitmap>();
xs = new ArrayList<Float>();
ys = new ArrayList<Float>();
objectNames = new ArrayList<String>();
}
public void HTMLObjects(String object){
Log.d(object, "see");
if (object.equals(C_DIV)) {
myPaint.setColor(Color.GREEN);
images.add(Bitmap.createBitmap(divimg));
objectNames.add("DIV");
xs.add(0F);
ys.add(0F);
}
if (object.equals(C_IFRAME)){
myPaint.setColor(Color.BLUE);
images.add(Bitmap.createBitmap(iframeimg));
objectNames.add("iFrame");
xs.add(0F);
ys.add(0F);
}
}
public boolean onTouchEvent(MotionEvent event) {
int action=event.getAction();
if (xs.isEmpty()) {
return true;
}
int pos = xs.size() - 1;
switch(action) {
case MotionEvent.ACTION_DOWN:
xs.set(pos, event.getX());
ys.set(pos, event.getY());
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
xs.set(pos, event.getX());
ys.set(pos, event.getY());
break;
}
return true;
}
public void onDraw(Canvas canvas){
for (int i = 0; i < images.size(); i++) {
float x = xs.get(i);
float y = ys.get(i);
canvas.drawBitmap(images.get(i), x-50, y-50, myPaint);
canvas.drawText(objectNames.get(i), x, y-50, myPaint);
}
invalidate();
}
}
Related
I have a problem with canvas I have two options either to draw with a paint or to add an image but when I choose to add an image after drawing the drawing is gone but when I choose drawing again and start to draw the previous drawing show up and remove the image.
public class DrawCanvas extends View {
Bitmap bitmap;
private Paint paint = new Paint();
private Path path;
ArrayList<Path> paths = new ArrayList<>();
ArrayList<Path> undo = new ArrayList<>();
final Paint mBackgroundPaint;
ArrayList<Emotion> emotions;
private boolean mDrawingEnabled = true;
float currentX = 0, currentY = 0;
public DrawCanvas(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.launcher);
paint.setAntiAlias(false);
paint.setColor(Color.BLACK);
paint.setStrokeJoin(Paint.Join.MITER);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(30f);
emotions = new ArrayList<>();
path = new Path();
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(Color.WHITE);
}
#Override
protected void onDraw(Canvas canvas){
if (mDrawingEnabled ) {
canvas.drawPath(path, paint);
}
else{
canvas.drawBitmap(bitmap, currentX, currentY, null);
}
}
#Override
public boolean onTouchEvent(MotionEvent motionEvent){
int xPos =(int) motionEvent.getX(), yPos =(int) motionEvent.getY();
final int action = motionEvent.getAction();
if (mDrawingEnabled){
switch (action) {
case MotionEvent.ACTION_DOWN:
path.moveTo(xPos, yPos);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(xPos, yPos);
break;
case MotionEvent.ACTION_UP:
paths.add(path);
break;
default:
return false;
}
}
else {
final float me_x = motionEvent.getX();
final float me_y = motionEvent.getY();
switch ( action ) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
currentX = me_x;
currentY = me_y;
break;
}
}
invalidate();
return true;
}
public void undo(){
if (paths.size()>0){
undo.add(paths.remove(paths.size()-1));
}
}
public void redo(){
if (undo.size()>0){
paths.add(undo.remove(undo.size()-1));
}
}
final void enableDrawing() { mDrawingEnabled = true; }
final void disableDrawing() { mDrawingEnabled = false; }
public void changeBrushColor(int color){
paint.setColor(color);
}
public void changeBrushSize(int size){
paint.setStrokeWidth(size);
}
}
here is the drawing
and when I add image clears the drawing
I want to keep the drawn path alongside the image.
Please Help to solve this problem...
First Fragment
Here this is a 1stFragment file sends the string of encoded bitmap
tmp = getArguments().getString("PHOTO");
byte [] encodeByte=Base64.decode(tmp,Base64.DEFAULT);
bmp=BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
ByteArrayOutputStream b=new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG,100, b);
bm =b.toByteArray();
temp=Base64.encodeToString(bm, Base64.DEFAULT);Fragment fr = new CropToolActivity();
fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
args = new Bundle();
args.putString("PHOTO", temp);
fr.setArguments(args);
ft.replace(R.id.frame,fr);
ft.commit();
CropToolActivity
Here this is a 2ndFragment file receives the string of encoded bitmap
also set the CropView ti the layout
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.croptool, container, false);
myCropView = (CropView)view.findViewById(R.id.crop_tool);
myCropView = new CropView(getActivity().getApplicationContext());
tmp = getArguments().getString("PHOTO");
byte [] encodeByte=Base64.decode(tmp,Base64.DEFAULT);
bmp=BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
myCropView.setImageBitmap(bmp);
croptool.xml
This is a XML file for 2nd Fragment layout
<com.tcss.photostyle.CropView
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:id="#+id/crop_tool" />
</LinearLayout>
CropView.Java
Here this is a croptool java file to demonstrate the Croptool on bitmap
public class CropView extends ImageView {
Paint paint = new Paint();
private int initial_size = 300;
private static Point leftTop, rightBottom, center, previous;
private static final int DRAG= 0;
private static final int LEFT= 1;
private static final int TOP= 2;
private static final int RIGHT= 3;
private static final int BOTTOM= 4;
private int imageScaledWidth,imageScaledHeight;
// Adding parent class constructors
public CropView(Context context) {
super(context);
initCropView();
}
public CropView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initCropView();
}
public CropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initCropView();
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if(leftTop.equals(0, 0))
resetPoints();
canvas.drawRect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
previous.set((int)event.getX(), (int)event.getY());
break;
case MotionEvent.ACTION_MOVE:
if(isActionInsideRectangle(event.getX(), event.getY())) {
adjustRectangle((int)event.getX(), (int)event.getY());
invalidate(); // redraw rectangle
previous.set((int)event.getX(), (int)event.getY());
}
break;
case MotionEvent.ACTION_UP:
previous = new Point();
break;
}
return true;
}
private void initCropView() {
paint.setColor(Color.YELLOW);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(5);
leftTop = new Point();
rightBottom = new Point();
center = new Point();
previous = new Point();
}
public void resetPoints() {
center.set(getWidth()/2, getHeight()/2);
leftTop.set((getWidth()-initial_size)/2,(getHeight()-initial_size)/2);
rightBottom.set(leftTop.x+initial_size, leftTop.y+initial_size);
}
private static boolean isActionInsideRectangle(float x, float y) {
int buffer = 10;
return (x>=(leftTop.x-buffer)&&x<=(rightBottom.x+buffer)&& y>=(leftTop.y-buffer)&&y<=(rightBottom.y+buffer))?true:false;
}
private boolean isInImageRange(PointF point) {
// Get image matrix values and place them in an array
float[] f = new float[9];
getImageMatrix().getValues(f);
// Calculate the scaled dimensions
imageScaledWidth = Math.round(getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X]);
imageScaledHeight = Math.round(getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y]);
return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false;
}
private void adjustRectangle(int x, int y) {
int movement;
switch(getAffectedSide(x,y)) {
case LEFT:
movement = x-leftTop.x;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
leftTop.set(leftTop.x+movement,leftTop.y+movement);
break;
case TOP:
movement = y-leftTop.y;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement)))
leftTop.set(leftTop.x+movement,leftTop.y+movement);
break;
case RIGHT:
movement = x-rightBottom.x;
if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
break;
case BOTTOM:
movement = y-rightBottom.y;
if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement)))
rightBottom.set(rightBottom.x+movement,rightBottom.y+movement);
break;
case DRAG:
movement = x-previous.x;
int movementY = y-previous.y;
if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movementY)) && isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movementY))) {
leftTop.set(leftTop.x+movement,leftTop.y+movementY);
rightBottom.set(rightBottom.x+movement,rightBottom.y+movementY);
}
break;
}
}
private static int getAffectedSide(float x, float y) {
int buffer = 10;
if(x>=(leftTop.x-buffer)&&x<=(leftTop.x+buffer))
return LEFT;
else if(y>=(leftTop.y-buffer)&&y<=(leftTop.y+buffer))
return TOP;
else if(x>=(rightBottom.x-buffer)&&x<=(rightBottom.x+buffer))
return RIGHT;
else if(y>=(rightBottom.y-buffer)&&y<=(rightBottom.y+buffer))
return BOTTOM;
else
return DRAG;
}
public byte[] getCroppedImage() {
BitmapDrawable drawable = (BitmapDrawable)getDrawable();
float x = leftTop.x-center.x+(drawable.getBitmap().getWidth()/2);
float y = leftTop.y-center.y+(drawable.getBitmap().getHeight()/2);
Bitmap cropped = Bitmap.createBitmap(drawable.getBitmap(),(int)x,(int)y,(int)rightBottom.x-(int)leftTop.x,(int)rightBottom.y-(int)leftTop.y);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
cropped.compress(Bitmap.CompressFormat.PNG, 100, stream);
return stream.toByteArray();
}
}
Here is a method for cropping bitmap from center, assume that newWidth < bitmap.getWidth() and newHeight < bitmap.getHeight()
public Bitmap cropBitmap(Bitmap bitmap, int newWidth, int newHeight) {
double x = (bitmap.getWidth() - newWidth) / 2;
double y = (bitmap.getHeight() - newHeight) / 2;
Bitmap b = Bitmap.createBitmap((int)newWidth, (int)newHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
c.drawBitmap(bitmap, new Rect((int)x , (int)y, (int)(x + newWidth), (int)(y + newHeight)), new Rect(0, 0, (int)newWidth, (int)newHeight), null);
return b;
}
I have a custom view in which i am drawing one big circle and a small circle on the edge of this big circle.
I would like to move the small circle and so would like to have a ontouch listener only for the small circle.
Could some please tell me how to set the ontouch listener for only the small circle.
public class ThermoView extends View{
private ImageView mThermostatBgrd;
private ImageView mCurTempArrow;
private ImageView mSetPointIndicator;
public static final int THEMROSTAT_BACKGROUND = 0;
public static final int THEMROSTAT_CURR_TEMP = 1;
public static final int THEMROSTAT_SET_POINT = 2;
private float mViewCentreX;
private float mViewCentreY;
private float mThermostatRadius;
private Canvas mCanvas;
private Paint mPaint;
private Paint mPaintCurTemp;
private Paint mPaintSetTemp;
private Paint mPaintOverrideTemp;
private Paint mPaintCurTempIndicator;
private Boolean mManualOverride = false;
private double mManualOverrideAngle;
private int mMaxTemp = 420;
private int mMinTemp = 120;
private RectF mCurrTempBox;
private float mCurTempCircleX;
private float mCurTempCircleY;
private Matrix mMatrix;
public double getManualOverrideAngle() {
return mManualOverrideAngle;
}
public void setManualOverrideAngle(double mManualOverrideAngle) {
this.mManualOverrideAngle = mManualOverrideAngle;
}
public RectF getCurrTempBox() {
if (mCurrTempBox == null){
mCurrTempBox = new RectF();
}
return mCurrTempBox;
}
public void setCurrTempBox(RectF mCurrTempBox) {
this.mCurrTempBox = mCurrTempBox;
}
public Boolean getManualOverride() {
return mManualOverride;
}
public void setManualOverride(Boolean mManualOverride) {
this.mManualOverride = mManualOverride;
}
public ThermoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path smallCirle = new Path();
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
mViewCentreX = viewWidth/2;
mViewCentreY = viewHeight/2;
float paddingPercent = 0.2f;
int thermostatThickness = 20;
mThermostatRadius = (int) ((Math.min(mViewCentreX, mViewCentreY)*(1- paddingPercent)));
if (mPaint == null){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(thermostatThickness);
mPaint.setColor(0xffff0000);
Path arcPath = new Path();
RectF container = new RectF();
container.set(mViewCentreX - mThermostatRadius, mViewCentreY - mThermostatRadius,
mViewCentreX + mThermostatRadius, mViewCentreY + mThermostatRadius);
arcPath.addArc(container, 120, 300);
canvas.drawPath(arcPath, mPaint);
int dummyCurTemp = 200;
if (mPaintCurTemp == null){
mPaintCurTemp = new Paint(Paint.ANTI_ALIAS_FLAG);
}
mPaintCurTemp.setTextAlign(Align.CENTER);
mPaintCurTemp.setTextSize(100);
canvas.drawText(String.valueOf(dummyCurTemp), mViewCentreX, mViewCentreY, mPaintCurTemp);
if (this.mManualOverride == false){
double angle = (360-120-(300/(mMaxTemp - mMinTemp))*(dummyCurTemp-mMinTemp))*(Math.PI/180);
this.mCurTempCircleX = (float) (mViewCentreX + mThermostatRadius*(Math.cos(angle)));
this.mCurTempCircleY = (float) (mViewCentreY - mThermostatRadius*(Math.sin(angle)));
if (mCurrTempBox == null){
mCurrTempBox = new RectF();
}
if (mPaintCurTempIndicator == null){
mPaintCurTempIndicator = new Paint(Paint.ANTI_ALIAS_FLAG);
}
mPaintCurTempIndicator.setStyle(Paint.Style.STROKE);
mPaintCurTempIndicator.setStrokeWidth(thermostatThickness/2);
mPaintCurTempIndicator.setColor(Color.GREEN);
mCurrTempBox.set(mCurTempCircleX-50, mCurTempCircleY-50, mCurTempCircleX+50, mCurTempCircleY+50);
smallCirle.addCircle(mCurTempCircleX, mCurTempCircleY, 50, Direction.CW);
canvas.drawPath(smallCirle, mPaintCurTempIndicator);
}else{
if (mCurrTempBox == null){
mCurrTempBox = new RectF();
}
if (mPaintCurTempIndicator == null){
mPaintCurTempIndicator = new Paint(Paint.ANTI_ALIAS_FLAG);
}
if (mMatrix == null){
mMatrix = new Matrix();
}
//mMatrix.reset();
mMatrix.postRotate((float) (mManualOverrideAngle), mViewCentreX,mViewCentreY);
//mMatrix.postTranslate(mViewCentreX, mViewCentreY);
mPaintCurTempIndicator.setStyle(Paint.Style.STROKE);
mPaintCurTempIndicator.setStrokeWidth(thermostatThickness/2);
mPaintCurTempIndicator.setColor(Color.GREEN);
canvas.concat(mMatrix);
smallCirle.addCircle(mCurTempCircleX, mCurTempCircleY, 50, Direction.CW);
canvas.drawPath(smallCirle, mPaintCurTempIndicator);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialX = event.getX();
mInitialY = event.getY();
RectF touchedAt = new RectF(mInitialX-10, mInitialY-10, mInitialX+10, mInitialY+10);
RectF indicatorAt = mThermoStatView.getCurrTempBox();
if (RectF.intersects(indicatorAt, touchedAt)){
this.isIndicatorSelected = true;
mThermoStatView.setManualOverride(true);
}
break;
case MotionEvent.ACTION_MOVE:
if (this.isIndicatorSelected == true){
float angle = (float) (180*Math.atan2(event.getY() - mThermostatHeight/2, event.getX() - mThermostatWidth/2) / Math.PI);
mThermoStatView.setManualOverrideAngle(angle);
mThermoStatView.invalidate();
//mThermoStatView.requestLayout();
}
break;
case MotionEvent.ACTION_UP:
if (this.isIndicatorSelected == true){
this.isIndicatorSelected = false;
}
break;
}
return true;
}
}
try this (this is a little modified version of MyView i already posted as an answer for your previous question):
public class MyView extends View {
private final static String TAG = "Main.MyView";
private static final float CX = 0;
private static final float CY = 0;
private static final float RADIUS = 20;
private static final float BIGRADIUS = 50;
private static final int NORMAL_COLOR = 0xffffffff;
private static final int PRESSED_COLOR = 0xffff0000;
private Paint mPaint;
private Path mSmallCircle;
private Path mCircle;
private Matrix mMatrix;
private float mAngle;
private int mSmallCircleColor;
public MyView(Context context) {
super(context);
mPaint = new Paint();
mSmallCircle = new Path();
mSmallCircle.addCircle(BIGRADIUS + RADIUS + CX, CY, RADIUS, Direction.CW);
mSmallCircleColor = NORMAL_COLOR;
mCircle = new Path();
mCircle.addCircle(0, 0, BIGRADIUS, Direction.CW);
mMatrix = new Matrix();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP) {
mSmallCircleColor = NORMAL_COLOR;
invalidate();
return false;
}
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
float r = 0;
if (action == MotionEvent.ACTION_DOWN) {
float[] pts = {
BIGRADIUS + RADIUS + CX, CY
};
mMatrix.mapPoints(pts);
r = (float) Math.hypot(event.getX() - pts[0], event.getY() - pts[1]);
}
if (r < RADIUS) {
mSmallCircleColor = PRESSED_COLOR;
mAngle = (float) (180 * Math.atan2(event.getY() - h2, event.getX() - w2) / Math.PI);
invalidate();
return true;
}
return false;
}
#Override
protected void onDraw(Canvas canvas) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mMatrix.reset();
mMatrix.postRotate(mAngle);
mMatrix.postTranslate(w2, h2);
canvas.concat(mMatrix);
mPaint.setColor(0x88ffffff);
canvas.drawPath(mCircle, mPaint);
mPaint.setColor(mSmallCircleColor);
canvas.drawPath(mSmallCircle, mPaint);
}
}
You can get the rectangle of your touch point and the rectangle(position) of your inner circle and check if they cross over with the Intersects method.
http://docs.oracle.com/javase/7/docs/api/java/awt/Rectangle.html#intersects(java.awt.Rectangle)
Your canvas onTouchListener can do whatever it needs to do if the touchpoint intersect your circle.
e.g:
// Create a rectangle from the point of touch
Rect touchpoint = new Rect(x,y,10,10);
// Create a rectangle from the postion of the circle.
Rect myCircle=new Rect(10,10,20,20);
if (Rect.intersects(myCircle,touchpoint)){
Log.d("The circle was touched");
}
I am using android Canvas class from creating a drawing application. This is my first attempt to work with the Canvas class. So far the code that I used is working fine and the drawing is working fine. But what I realized in this code is that it allow the user to draw with one finger only, I mean to say if the user used more then one finger to draw on canvas it doesn't allow the user to draw with multiple fingers. I go through documentation regarding multiple touch events but failed to implement it in my code. So can anyone help me to figure this out?
The code I used for drawing on canvas:
public class DrawView extends View implements OnTouchListener
{
private Canvas m_Canvas;
private Path m_Path;
private Paint m_Paint;
ArrayList<Pair<Path, Paint>> arrayListPaths = new ArrayList<Pair<Path, Paint>>();
ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>();
private float mX, mY;
private Bitmap bitmapToCanvas;
private static final float TOUCH_TOLERANCE = 4;
public DrawView(Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
onCanvasInitialization();
}
public void onCanvasInitialization()
{
m_Paint = new Paint();
m_Paint.setAntiAlias(true);
m_Paint.setDither(true);
m_Paint.setColor(Color.parseColor("#37A1D1"));
m_Paint.setStyle(Paint.Style.STROKE);
m_Paint.setStrokeJoin(Paint.Join.ROUND);
m_Paint.setStrokeCap(Paint.Cap.ROUND);
m_Paint.setStrokeWidth(2);
m_Path = new Path();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
bitmapToCanvas = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
m_Canvas = new Canvas(bitmapToCanvas);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmapToCanvas, 0f, 0f, null);
canvas.drawPath(m_Path, m_Paint);
}
public boolean onTouch(View arg0, MotionEvent event)
{
float x = event.getX();
float y = 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)
{
undonePaths.clear();
m_Path.reset();
m_Path.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y)
{
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
{
m_Path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up()
{
m_Path.lineTo(mX, mY);
// commit the path to our offscreen
m_Canvas.drawPath(m_Path, m_Paint);
// kill this so we don't double draw
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
arrayListPaths.add(new Pair<Path, Paint>(m_Path, newPaint));
m_Path = new Path();
}
}
I tried making changes in my code to support multiple touch, but it doesn't work properly. This is my changed code.
Since there is no answer with working code, I can share a working example. The key is to have an array of currently active pointer ids and their paths. It is also important to know that in case of multiple moving pointers, onTouchEvent gets called only once for all of them and you need to iterate through all of the pointers to draw their new positions.
public class DrawView extends View {
private Paint drawPaint, canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private SparseArray<Path> paths;
public DrawingView(Context context) {
super(context);
setupDrawing();
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public DrawingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setupDrawing();
}
private void setupDrawing() {
paths = new SparseArray<>();
drawPaint = new Paint();
drawPaint.setColor(Color.RED);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(20);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
for (int i=0; i<paths.size(); i++) {
canvas.drawPath(paths.valueAt(i), drawPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int id = event.getPointerId(index);
Path path;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
path = new Path();
path.moveTo(event.getX(index), event.getY(index));
paths.put(id, path);
break;
case MotionEvent.ACTION_MOVE:
for (int i=0; i<event.getPointerCount(); i++) {
id = event.getPointerId(i);
path = paths.get(id);
if (path != null) path.lineTo(event.getX(i), event.getY(i));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
path = paths.get(id);
if (path != null) {
drawCanvas.drawPath(path, drawPaint);
paths.remove(id);
}
break;
default:
return false;
}
invalidate();
return true;
}
}
See Making Sense of Multitouch, it helped me a lot. It explanes how to handle multi touches
Points to remember
1.Make sure that you switch on action & MotionEvent.ACTION_MASK
2.if you want to draw multiple lines at same time, follow PointerId of each pointer which comes in MotionEvent.ACTION_POINTER_DOWN and release it in MotionEvent.ACTION_POINTER_UP by comparing pointer ids.
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
// Existing code ...
#Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
mLastTouchX = x;
mLastTouchY = y;
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
Edit
Please see this code... This still has some issues but i think you can debug it and fix those ... Also the logic is not there persisting lines please implement that...
package com.example.stackgmfdght;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
public class JustDoIt extends View
{
private Canvas m_Canvas;
// private Path m_Path;
int current_path_count=-1;
ArrayList <Path> m_Path_list = new ArrayList<Path>();
ArrayList <Float> mX_list = new ArrayList<Float>();
ArrayList <Float> mY_list = new ArrayList<Float>();
ArrayList <Integer> mActivePointerId_list = new ArrayList<Integer>();
private Paint m_Paint;
ArrayList<Pair<Path, Paint>> arrayListPaths = new ArrayList<Pair<Path, Paint>>();
//ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>();
private float mX, mY;
private Bitmap bitmapToCanvas;
private static final float TOUCH_TOLERANCE = 4;
public JustDoIt (Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
onCanvasInitialization();
}
public JustDoIt(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
setFocusable(true);
setFocusableInTouchMode(true);
onCanvasInitialization();
}
public void onCanvasInitialization()
{
m_Paint = new Paint();
m_Paint.setAntiAlias(true);
m_Paint.setDither(true);
m_Paint.setColor(Color.parseColor("#37A1D1"));
m_Paint.setStyle(Paint.Style.STROKE);
m_Paint.setStrokeJoin(Paint.Join.ROUND);
m_Paint.setStrokeCap(Paint.Cap.ROUND);
m_Paint.setStrokeWidth(2);
// m_Path = new Path();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
bitmapToCanvas = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
m_Canvas = new Canvas(bitmapToCanvas);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmapToCanvas, 0f, 0f, null);
for(int i=0;i<=current_path_count;i++)
{
canvas.drawPath(m_Path_list.get(i), m_Paint);
}
}
public void onDrawCanvas()
{
for (Pair<Path, Paint> p : arrayListPaths)
{
m_Canvas.drawPath(p.first, p.second);
}
}
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
#Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
final int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
{
float x = event.getX();
float y = event.getY();
current_path_count=0;
mActivePointerId_list.add ( event.getPointerId(0),current_path_count);
touch_start((x ),(y ),current_path_count );
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
{
if(event.getPointerCount()>current_path_count)
{
current_path_count++;
float x = event.getX(current_path_count);
float y = event.getY(current_path_count);
mActivePointerId_list.add ( event.getPointerId(current_path_count),current_path_count);
touch_start((x ),(y ),current_path_count);
}
}
break;
case MotionEvent.ACTION_MOVE:
{
for(int i=0;i<=current_path_count;i++)
{ try{
int pointerIndex = event
.findPointerIndex(mActivePointerId_list.get(i));
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
touch_move((x ),(y ),i);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
break;
case MotionEvent.ACTION_UP:
{ current_path_count=-1;
for(int i=0;i<=current_path_count;i++)
{
touch_up(i);
}
mActivePointerId_list = new ArrayList<Integer>();
}
break;
case MotionEvent.ACTION_CANCEL:
{
mActivePointerId = INVALID_POINTER_ID;
current_path_count=-1;
}
break;
case MotionEvent.ACTION_POINTER_UP:
{
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
for(int i=0;i<=current_path_count;i++)
{
if (pointerId == mActivePointerId_list.get(i))
{
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
mActivePointerId_list.remove(i);
touch_up(i);
break;
}
}
}
break;
case MotionEvent.ACTION_OUTSIDE:
break;
}
invalidate();
return true;
}
private void touch_start(float x, float y, int count)
{
// undonePaths.clear();
Path m_Path=new Path();
m_Path_list.add(count,m_Path);
m_Path_list.get(count).reset();
m_Path_list.get(count).moveTo(x, y);
mX_list.add(count,x);
mY_list.add(count,y);
}
private void touch_move(float x, float y,int count)
{
float dx = Math.abs(x - mX_list.get(count));
float dy = Math.abs(y - mY_list.get(count));
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
{
m_Path_list.get(count).quadTo(mX_list.get(count), mY_list.get(count), (x + mX_list.get(count))/2, (y + mY_list.get(count))/2);
try{
mX_list.remove(count);
mY_list.remove(count);
}
catch(Exception e)
{
e.printStackTrace();
}
mX_list.add(count,x);
mY_list.add(count,y);
}
}
private void touch_up(int count)
{
m_Path_list.get(count).lineTo(mX_list.get(count), mY_list.get(count));
// commit the path to our offscreen
m_Canvas.drawPath( m_Path_list.get(count), m_Paint);
// kill this so we don't double draw
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
arrayListPaths.add(new Pair<Path, Paint>( m_Path_list.get(count), newPaint));
m_Path_list.remove(count);
mX_list.remove(count);
mY_list.remove(count);
}
}
Here example for copy-paste. Just create class that extend View and implement following methods.
private final Paint paint = new Paint(); // Don't forgot to init color, form etc.
#Override
protected void onDraw(Canvas canvas) {
for (int size = paths.size(), i = 0; i < size; i++) {
Path path = paths.get(i);
if (path != null) {
canvas.drawPath(path, paint);
}
}
}
private HashMap<Integer, Float> mX = new HashMap<Integer, Float>();
private HashMap<Integer, Float> mY = new HashMap<Integer, Float>();
private HashMap<Integer, Path> paths = new HashMap<Integer, Path>();
#Override
public boolean onTouchEvent(MotionEvent event) {
int maskedAction = event.getActionMasked();
Log.d(TAG, "onTouchEvent");
switch (maskedAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
Path p = new Path();
p.moveTo(event.getX(i), event.getY(i));
paths.put(event.getPointerId(i), p);
mX.put(event.getPointerId(i), event.getX(i));
mY.put(event.getPointerId(i), event.getY(i));
}
break;
}
case MotionEvent.ACTION_MOVE: {
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
Path p = paths.get(event.getPointerId(i));
if (p != null) {
float x = event.getX(i);
float y = event.getY(i);
p.quadTo(mX.get(event.getPointerId(i)), mY.get(event.getPointerId(i)), (x + mX.get(event.getPointerId(i))) / 2,
(y + mY.get(event.getPointerId(i))) / 2);
mX.put(event.getPointerId(i), event.getX(i));
mY.put(event.getPointerId(i), event.getY(i));
}
}
invalidate();
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
Path p = paths.get(event.getPointerId(i));
if (p != null) {
p.lineTo(event.getX(i), event.getY(i));
invalidate();
paths.remove(event.getPointerId(i));
mX.remove(event.getPointerId(i));
mY.remove(event.getPointerId(i));
}
}
break;
}
}
return true;
}
public class Sample2 extends Activity {
private SampleView sView;
private static int displayWidth = 100; //movement area
private static int displayHeight = 100;
float angle = 0;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
sView = new SampleView(this);
setContentView(sView);
}//oncreate
private class SampleView extends View {
Context con;
private Rect displayRect = null; //rect we display to
private int scrollRectX = 0; //current left location of scroll rect
private int scrollRectY = 0; //current top location of scroll rect
private float scrollByX = 0; //scroll by amounts
private float scrollByY = 0;
private float startX = 0; //track x from one ACTION_MOVE to the next
private float startY = 0; //track y from one ACTION_MOVE to the next
private int state = 0;
Bitmap bitmap2;
public SampleView(Context context) {
super(context);
displayRect = new Rect(0, 0, displayWidth, displayHeight);
}//constructor
public boolean onTouchEvent(MotionEvent event) {
float x;
float y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Initial down event location.
startX = event.getRawX();
startY = event.getRawY()-50;
// Log.e("TOUCHED",startY+" "+(scrollRectY+displayHeight));
if (((startX>scrollRectX)&(startX<(scrollRectX+displayWidth)))&
((startY>scrollRectY)&(startY<(scrollRectY+displayHeight)))) state = 1;
//Log.e("TOUCHED","State "+state);
break;
case MotionEvent.ACTION_MOVE:
x = event.getRawX();
y = event.getRawY()-50;
scrollByX = x - startX;
scrollByY = y - startY;
startX = x;
startY = y;
if (state != 0) invalidate(); //move it
break;
case MotionEvent.ACTION_UP:
x = event.getRawX();
y = event.getRawY()-50;
scrollByX = x - startX;
scrollByY = y - startY;
startX = x;
startY = y;
state = 0;
invalidate();
break;
}//switch
return true;
}//ontouch
protected void onDraw(Canvas canvas) {
scrollRectX = scrollRectX+(int)scrollByX;
scrollRectY = scrollRectY+(int)scrollByY;
displayRect.set(scrollRectX,scrollRectY,scrollRectX+displayWidth,
scrollRectY+displayHeight);
Paint paint = new Paint();
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
bitmap2= BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher).copy(Config.RGB_565, true);
canvas.drawBitmap(bitmap2, null, displayRect, paint);
//TODO: Fill In Methods Etc.
}
}
}
i have used this code....now my question is this how to set separate toast messages for 2 bitmap in android?....if i touch in background rectangle it shows toast message and if i touch on image it shows another toast message by using if condition on ontouchevents....plz any1 can say this....
you can do like this way,
Demo.java
public class Demo extends Activity implements OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_layout);
final LinearLayout lin_layout = (LinearLayout) findViewById(R.id.lin_layout);
final ImageView img_view = (EditText) findViewById(R.id.img_view);
// call your touch event
l_l.setOnClickListener(this);
imageView1.setOnClickListener(this);
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.l_l: // if you touch on layout
// do your task
Toast.makeText(getApplicationContext(), "You Touch on: Linear_Layout",
Toast.LENGTH_LONG).show();
break;
case R.id.imageView1: // if you touch on Image
// do your task
Toast.makeText(getApplicationContext(), "You Touch on : Image ", Toast.LENGTH_LONG)
.show();
break;
default:
break;
}
}
}