I want to add a rectangular border on my ImageView which allow users to change it's size from 8 directions to provide them a preview for cropping purpose.
Which way I can implement to achieve my purpose best, defining a custom ImageView and add code to draw rectangle or add ImageView to a SurfaceView?
Here is my code which I can use to draw a rectangle around my image:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
public class CustomCropImageView extends ImageView implements View.OnTouchListener{
// Bitmap to draw.
Bitmap myBitmap;
// Fundamental attributes.
int xPos, yPos;
int originWidth, originHeight;
int widthImg, heightImg;
int xCrop, yCrop;
int cropWidth, cropHeight;
GestureDetector myGesture;
public CustomCropImageView(Context context){
super(context);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
public CustomCropImageView(Context context, AttributeSet attSet){
super(context, attSet);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if(drawable == null)
return;
if(originWidth == 0 && originHeight == 0){
Bitmap tmp = ((BitmapDrawable)drawable).getBitmap();
myBitmap = tmp.copy(Bitmap.Config.ARGB_8888, true);
originWidth = myBitmap.getWidth();
originHeight = myBitmap.getHeight();
Integer[] myDWAndH = getScreenWidthAndHeight();
widthImg = cropWidth = myDWAndH[0];
heightImg = cropHeight = (int)((float)myDWAndH[0]*((float)originHeight / (float)originWidth));
yPos = yCrop = (myDWAndH[1] - heightImg) / 2;
myBitmap = Bitmap.createScaledBitmap(myBitmap, widthImg, heightImg, false);
}
Paint myPaint = new Paint();
canvas.drawBitmap(myBitmap, xPos, yPos, myPaint);
drawAnchorRectangle(canvas);
}
void drawAnchorRectangle(Canvas canvas){
// Anchor rectangle.
Paint myPaint = new Paint();
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVBorder));
myPaint.setStrokeWidth(5);
Rect myRect = new Rect(xCrop, yCrop, cropWidth, yCrop + cropHeight);
canvas.drawRect(myRect, myPaint);
// Anchor point.
myPaint.setStyle(Paint.Style.FILL);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVAnchorPoint));
myPaint.setStrokeWidth(3);
int anchorPointW = 10;
int halfAnchorPointW = anchorPointW / 2;
/*
// Top left.
Rect anchorPoint = new Rect(xCrop + cropWidth - halfAnchorPointW, yCrop - halfAnchorPointW,
anchorPointW, yCrop + halfAnchorPointW);
canvas.drawRect(anchorPoint, myPaint);
// Top right.
anchorPoint.set(xCrop + cropWidth - halfAnchorPointW, yCrop - halfAnchorPointW,
anchorPointW, yCrop + halfAnchorPointW);
canvas.drawRect(anchorPoint, myPaint);
*/
}
Integer[] getScreenWidthAndHeight(){
DisplayMetrics dMetrics = new DisplayMetrics();
((MainActivity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(dMetrics);
Integer[] myResult = new Integer[2];
myResult[0] = dMetrics.widthPixels - 40;
myResult[1] = dMetrics.heightPixels;
return myResult;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
final String TAG = "!!!123";
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "Action was DOWN");
return true;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "Action was MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "Action was UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "Action was CANCEL");
break;
case MotionEvent.ACTION_OUTSIDE:
Log.d(TAG, "Movement occurred outside bounds of current screen element");
break;
}
return super.onTouchEvent(event);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return super.onTouchEvent(event);
}
}
Here's how i solved, by defining a custom image view and make some change in OnDraw method, i also added code to reduce brightness of image so it looks nice with a background image behind the real when you resize the rectangle:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.List;
public class CustomCropImageView extends ImageView implements View.OnTouchListener{
// Bitmap to draw.
Bitmap myBitmap;
// Fundamental attributes.
int xPos, yPos;
int originWidth, originHeight;
int widthImg, heightImg;
int xCrop, yCrop;
int cropWidth, cropHeight;
int offsetLeft = 0, offsetRight = 0, offsetTop = 0, offsetBottom = 0;
// List of anchor point rectangle.
List<Rect> anchorPoints;
int anchorPointW = 30;
int halfAnchorPointW = anchorPointW / 2;
// Background bitmap for cropping.
Bitmap darkBitmap;
public CustomCropImageView(Context context){
super(context);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
public CustomCropImageView(Context context, AttributeSet attSet){
super(context, attSet);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
Integer[] myDWAndH;
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if(drawable == null)
return;
if(originWidth == 0 && originHeight == 0){
Bitmap tmp = ((BitmapDrawable)drawable).getBitmap();
myBitmap = tmp.copy(Bitmap.Config.ARGB_8888, true);
originWidth = myBitmap.getWidth();
originHeight = myBitmap.getHeight();
myDWAndH = getScreenWidthAndHeight();
widthImg = cropWidth = myDWAndH[0] - anchorPointW;
heightImg = cropHeight = (int)((float)myDWAndH[0]*((float)originHeight / (float)originWidth)) - anchorPointW;
yPos = yCrop = (myDWAndH[1] - heightImg) / 2;
myBitmap = Bitmap.createScaledBitmap(myBitmap, widthImg, heightImg, false);
createDarkBitmap(myBitmap);
initAnchorPoint();
}
Paint myPaint = new Paint();
canvas.drawBitmap(darkBitmap, xPos + halfAnchorPointW, yPos + halfAnchorPointW, myPaint);
drawAnchorRectangle(canvas);
}
void drawAnchorRectangle(Canvas canvas){
// Anchor rectangle.
Paint myPaint = new Paint();
canvas.drawBitmap(myBitmap, new Rect(offsetLeft, offsetTop, cropWidth + offsetRight, cropHeight + offsetBottom),
new Rect(xCrop + halfAnchorPointW + offsetLeft, yCrop + halfAnchorPointW + offsetTop,
xCrop + halfAnchorPointW + cropWidth + offsetRight, yCrop + halfAnchorPointW + cropHeight + offsetBottom), myPaint);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVBorder));
myPaint.setStrokeWidth(5);
Rect myRect = new Rect(xCrop + halfAnchorPointW + offsetLeft, yCrop + halfAnchorPointW + offsetTop,
xCrop + halfAnchorPointW + cropWidth + offsetRight, yCrop + halfAnchorPointW + cropHeight + offsetBottom);
canvas.drawRect(myRect, myPaint);
// Anchor point.
myPaint.setStyle(Paint.Style.FILL);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVAnchorPoint));
// Top left.
canvas.drawRect(anchorPoints.get(0), myPaint);
// Top right.
canvas.drawRect(anchorPoints.get(1), myPaint);
// Bottom left.
canvas.drawRect(anchorPoints.get(2), myPaint);
// Bottom right.
canvas.drawRect(anchorPoints.get(3), myPaint);
}
void initAnchorPoint(){
if(anchorPoints != null)
anchorPoints.clear();
else
anchorPoints = new ArrayList<>();
// Top left.
anchorPoints.add(new Rect(xCrop + offsetLeft, yCrop + offsetTop,
xCrop + anchorPointW + offsetLeft, yCrop + anchorPointW + offsetTop));
// Top right.
anchorPoints.add(new Rect(xCrop + cropWidth + offsetRight, yCrop + offsetTop,
xCrop + cropWidth + anchorPointW + offsetRight, yCrop + anchorPointW + offsetTop));
// Bottom left.
anchorPoints.add(new Rect(xCrop + offsetLeft, yCrop + cropHeight + offsetBottom,
xCrop + anchorPointW + offsetLeft, yCrop + cropHeight + anchorPointW + offsetBottom));
// Bottom right.
anchorPoints.add(new Rect(xCrop + cropWidth + offsetRight, yCrop + cropHeight + offsetBottom,
xCrop + cropWidth + anchorPointW + offsetRight, yCrop + cropHeight + anchorPointW + offsetBottom));
}
Integer[] getScreenWidthAndHeight(){
DisplayMetrics dMetrics = new DisplayMetrics();
((MainActivity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(dMetrics);
Integer[] myResult = new Integer[2];
myResult[0] = dMetrics.widthPixels - 40;
myResult[1] = dMetrics.heightPixels;
return myResult;
}
int anchorChoice = -1;
void setAnchorAction(MotionEvent event){
int x = (int)event.getRawX();
int y = (int)event.getRawY();
int offset = 50 + anchorPointW;
anchorChoice = -1;
if(y > (anchorPoints.get(0).top - offset) && y < (anchorPoints.get(0).bottom + offset)){
if(x < (anchorPoints.get(0).right + offset) && x > (anchorPoints.get(0).left - offset)){
anchorChoice = 0;
}
else if(x < (anchorPoints.get(1).right + offset) && x > (anchorPoints.get(1).left - offset))
anchorChoice = 1;
}
else if(y > (anchorPoints.get(2).top - offset) && y < (anchorPoints.get(2).bottom + offset)){
if(x < (anchorPoints.get(2).right + offset) && x > (anchorPoints.get(2).left - offset)){
anchorChoice = 2;
}
else if(x < (anchorPoints.get(3).right + offset) && x > (anchorPoints.get(3).left - offset))
anchorChoice = 3;
}
}
void resizeRectangle(MotionEvent event){
if(anchorChoice == -1)
return;
int x = (int)event.getRawX();
int y = (int)event.getRawY();
int dif = 0;
initAnchorPoint();
invalidate();
// xCrop + halfAnchorPointW + offsetLeft, yCrop + halfAnchorPointW + offsetTop,
// xCrop + halfAnchorPointW + cropWidth + offsetRight, yCrop + halfAnchorPointW + cropHeight + offsetBottom
int prevOLeft = offsetLeft;
int prevORight = offsetRight;
int prevOTop = offsetTop;
int prevOBottom = offsetBottom;
if(anchorChoice == 0){
offsetLeft = (x - xCrop - halfAnchorPointW);
offsetTop = (y - yCrop - halfAnchorPointW);
}
else if(anchorChoice == 1){
offsetRight = (x - xCrop - halfAnchorPointW - cropWidth);
offsetTop = (y - yCrop - halfAnchorPointW);
}
else if(anchorChoice == 2){
offsetLeft = (x - xCrop - halfAnchorPointW);
offsetBottom = (y - yCrop - halfAnchorPointW - cropHeight);
}
else if(anchorChoice == 3){
offsetRight = (x - xCrop - halfAnchorPointW - cropWidth);
offsetBottom = (y - yCrop - halfAnchorPointW - cropHeight);
}
// Boundaries.
// Left boundary.
if(xCrop + offsetLeft < xCrop)
offsetLeft = 0;
if(xCrop + halfAnchorPointW + cropWidth + offsetRight < xCrop + anchorPointW + offsetLeft)
offsetRight = prevORight;
// Top boundary.
if(yCrop + offsetTop < yCrop)
offsetTop = 0;
if(yCrop + halfAnchorPointW + cropHeight + offsetBottom < yCrop + anchorPointW + offsetTop)
offsetBottom = prevOBottom;
// Right boundary.
if(xCrop + halfAnchorPointW + cropWidth + offsetRight > xCrop + halfAnchorPointW + cropWidth)
offsetRight = 0;
if(xCrop + anchorPointW + offsetLeft > xCrop + halfAnchorPointW + cropWidth + offsetRight)
offsetLeft = prevOLeft;
// Bottom boundary.
if(yCrop + halfAnchorPointW + cropHeight + offsetBottom > yCrop + halfAnchorPointW + cropHeight)
offsetBottom = 0;
if(yCrop + anchorPointW + offsetTop > yCrop + halfAnchorPointW + cropHeight + offsetBottom)
offsetTop = prevOTop;
// End boundaries.
return;
}
void createDarkBitmap(Bitmap processedBitmap){
darkBitmap = Bitmap.createBitmap(processedBitmap.getWidth(), processedBitmap.getHeight(), Bitmap.Config.ARGB_8888);
int substractValue = 220;
for(int i = 0; i < processedBitmap.getWidth(); i++){
for(int j = 0; j < processedBitmap.getHeight(); j++){
int pixelToProcess = processedBitmap.getPixel(i, j);
// Get component infos.
int r = Color.red(pixelToProcess);
int g = Color.green(pixelToProcess);
int b = Color.blue(pixelToProcess);
int alpha = Color.alpha(pixelToProcess);
// Process component info.
alpha -= substractValue;
// alpha = alpha - substractValue;
darkBitmap.setPixel(i, j, Color.argb(alpha, r, g, b));
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
final String TAG = "!!!123";
switch (action) {
case MotionEvent.ACTION_DOWN:
setAnchorAction(event);
Log.d(TAG, "" + anchorChoice);
return true;
case MotionEvent.ACTION_MOVE:
resizeRectangle(event);
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "Action was UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "Action was CANCEL");
break;
case MotionEvent.ACTION_OUTSIDE:
Log.d(TAG, "Movement occurred outside bounds of current screen element");
break;
}
return super.onTouchEvent(event);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return super.onTouchEvent(event);
}
}
Related
I am trying to make real time application based on canvas writing here multiple device will be connected with this application if i write something on canvas it should reflect on other devices which are connected with this app here my issue is i am able to write on canvas and its also writes smooth but when it comes to receiving end its getting disjoint segment not clear path visible on canvas.
I am using thread using moveTo() and quadTo()to and receiving points from server
here images for reference
Source writing
Receiving end
Here is my code which i am trying
onDraw method
#Override
protected void onDraw(final Canvas canvas) {
normal_canvas_draw=true;
bckimage = getBackground();
String col = "#333333".substring(1);
col = col.toLowerCase();
col = "#ff" + col;
mc.setcanvas(canvas);
paint1.setAntiAlias(true);
paint1.setDither(true);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeJoin(Paint.Join.ROUND);
paint1.setStrokeCap(Paint.Cap.ROUND);
paint1.setPathEffect(new CornerPathEffect(30) ); // set the path effect when they join.
paint.setDither(true); // set the dither to true
paint.setStyle(Paint.Style.STROKE); // set to STOKE
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(30) ); // set the path effect when they join.
paint.setAntiAlias(true);
mCanvas.drawPath(path, paint);
mCanvas.drawPath(path1, paint1);
/*
for(Path p :paths)
{
mCanvas.drawPath(p, paint1);
}*/
//mCanvas.drawPath(path1, paint1);
//s = paths.size();
s = type.size();
Log.d("BLOCK", s + " , " + leftval.size());
int j = 0, k = 0;
canvas.drawBitmap(img, 0, 0, null);
canvas.drawText(mc.getDisplaymsg(), mCanvas.getWidth()-200, 25, painttext);
r = new Rect(10, 600, 100, 650);
}
onTouchEvent
#Override
public boolean onTouchEvent(MotionEvent event) {
if (mIsScrolling)
sv.requestDisallowInterceptTouchEvent(false);
else
sv.requestDisallowInterceptTouchEvent(true);
float eventX = event.getX();
float eventY = event.getY();
boolean touchcaptured = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.reset();
// path.moveTo(eventX, eventY);
boolean l = r.contains((int) event.getX(), (int) event.getY());
if (markerMode)
{
isEraserDown="false";
isPenDown="false";
isMarkerDown="true";
path.moveTo(eventX,eventY);
startX=eventX/scalefactor;
startY=eventY/scalefactor;
mX=eventX;
mY=eventY;
MainActivity.super.loadUrl("javascript:eraserfunction(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}
else if (eraseMode)
{
isEraserDown="true";
isPenDown="false";
isMarkerDown="false";
System.out.println("--Eraserfromtouch");
path.moveTo(eventX,eventY);
startX=eventX/scalefactor;
startY=eventY/scalefactor;
mX=eventX;
mY=eventY;
MainActivity.super.loadUrl("javascript:eraserfunction(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}
else if (blockerase) {
// left=(int) event.getX();
// right=left+1;
// top=(int) event.getY();
// bottom=top+1;
rx = (int) event.getX();
ry = (int) event.getY();
}
/*------------------- Pendown when we touch on mobile screen------*/
else if (penmode) {
isPenDown="true";
isEraserDown="false";
isMarkerDown="false";
System.out.println("---pen-down---"+eventX+","+eventY);
int historySize = event.getHistorySize();
if(isPenDown=="true")
{
path.moveTo(eventX,eventY);
mX = eventX;
mY = eventY;
startX=eventX/scalefactor;
startY=eventY/scalefactor;
mc.setXY(eventX / scalefactor, eventY / scalefactor);
MainActivity.super.loadUrl("javascript:penDown(0,0,'pen')");
}
else
{
}
// System.out.println(" Lcal x"+eventX+" y"+eventY+" x2"+eventX+" y2"+eventY);
} else if (rectanglemode) {
rx = (int) event.getX();
ry = (int) event.getY();
} else if (linemode) {
rx = (int) event.getX();
ry = (int) event.getY();
} else if (circlemode) {
cx = (int) event.getX();
cy = (int) event.getY();
MainActivity.super.loadUrl("javascript:circleDown(" + cx / scalefactor + "," + cy / scalefactor + ")");
} else if (textmode) {
cx = (int) event.getX();
cy = (int) event.getY();
//MainActivity.super.loadUrl("javascript:drawtext(" +cx + "," + cy+","+"Hello World"+")");
}
//invalidate();
break;
case MotionEvent.ACTION_MOVE:
if (markerMode) {
if (isMarkerDown.equals("true")) {
System.out.println("Marker Move");
Log.d("MARKER", "Hi im marker");
String col = mc.getdrawAttributes().substring(1);
col = col.toLowerCase();
col = "#ff" + col;
int coll = Color.parseColor(col);
paint.setColor(coll);
paint.setAlpha(10);
paint.setStrokeWidth(20);
if (bckimage == null) {
} else {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
}
MainActivity.super.loadUrl("javascript:marker1(" + eventX / scalefactor + "," + eventY / scalefactor + ")");
}
else{
}
path.quadTo(mX,mY,(mX+event.getX())/2,(mY+event.getY())/2);
mX=event.getX();
mY=event.getY();
}
else if (eraseMode)
{
if(isEraserDown=="true")
{
System.out.println("--Eraserfromtouch--MOVE");
System.out.println("Marker Move");
Log.d("Eraser", "Im eraser");
String thh = mc.getdrawAttributes1();
float f = Float.parseFloat(thh);
paint.setStrokeWidth(f);
if (bckimage == null) {
paint.setColor(Color.WHITE); //Toast.makeText(getContext(),"ERASE",Toast.LENGTH_LONG).show();
} else {
// setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
MainActivity.super.loadUrl("javascript:eraserfunction1(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}
path.quadTo(mX,mY,(mX+event.getX())/2,(mY+event.getY())/2);
mX=event.getX();
mY=event.getY();
}
else
{
}
}
else if (blockerase) {
qx = (int) event.getX();
qy = (int) event.getY();
}
/*------------------Pen move on the screen following by finger-------------*/
else if (penmode) {
if(isPenDown=="true")
{
String thh1 = mc.getdrawAttributes1();
float width = Float.parseFloat(thh1);
paint.setStrokeWidth(width);
paint.setColor(color);
paint.setDither(true); // set the dither to true
paint.setStyle(Paint.Style.STROKE); // set to STOKE
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(30) ); // set the path effect when they join.
paint.setAntiAlias(true);
// Line current = lines.get(lines.size() - 1);
System.out.println("---penmove---");
float dx = Math.abs((int) event.getX() - mX);
float dy = Math.abs((int) event.getY() - mY);
System.out.println("--Value of dx-dy-"+dx+"-"+dy);
if (dx >= 4 || dy >= 4) {
// setXY function set X and Y values to be used in JS File
mc.setXY((int) event.getX() / scalefactor, (int) event.getY() / scalefactor);
MainActivity.super.loadUrl("javascript:penMove(0,0,'pen')");
path.quadTo(mX,mY,(mX+event.getX())/2,(mY+event.getY())/2);
mX=event.getX();
mY=event.getY();
}
else
{
}
}
} else if (rectanglemode) {
qx = (int) event.getX();
qy = (int) event.getY();
} else if (linemode) {
qx = (int) event.getX();
qy = (int) event.getY();
} else if (circlemode) {
//MainActivity.super.loadUrl("javascript:circleDown(" + eventX + "," + eventY + ")");
}
break;
case MotionEvent.ACTION_UP:
boolean ll = r.contains((int) event.getX(), (int) event.getY());
if (markerMode)
MainActivity.super.loadUrl("javascript:marker12()");
else if (eraseMode) {
MainActivity.super.loadUrl("javascript:penUp()");
isEraserDown="false";
isMarkerDown="false";
System.out.println("--Eraserfromtouch---actionup");
path.lineTo(mX,mY);
mCanvas.drawPath(path,paint);
path= new Path();
// path1= new Path();
paths.add(path);
// MainActivity.super.loadUrl("javascript:eraserfunction1(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}else if (blockerase) {
qx = (int) event.getX();
qy = (int) event.getY();
MainActivity.super.loadUrl("javascript:bigeraserfunction1(" + rx / scalefactor + "," + ry / scalefactor + "," + qx / scalefactor + "," + qy / scalefactor + ")");
}
/*---------------------Pen up for writing on canvas------------------*/
else if (penmode) {
MainActivity.super.loadUrl("javascript:penUp()");
isPenDown="false";
System.out.println("---pen--up---");
path.lineTo(mX,mY);
mCanvas.drawPath(path,paint);
path= new Path();
// path1= new Path();
paths.add(path);
} else if (rectanglemode) {
qx = (int) event.getX();
qy = (int) event.getY();
MainActivity.super.loadUrl("javascript:rectangle(" + rx / scalefactor + "," + ry / scalefactor + "," + qx / scalefactor + "," + qy / scalefactor + ",'" + Prefs.getString(Elucido_APP_CONSTANTS.shared_user_name, "") + "')");
} else if (linemode) {
qx = (int) event.getX();
qy = (int) event.getY();
MainActivity.super.loadUrl("javascript:line(" + rx / scalefactor + "," + ry / scalefactor + "," + qx / scalefactor + "," + qy / scalefactor + ",'" + Prefs.getString(Elucido_APP_CONSTANTS.shared_user_name, "") + "')");
} else if (circlemode) {
c1x = (int) event.getX();
c1y = (int) event.getY();
MainActivity.super.loadUrl("javascript:circleup(" + c1x / scalefactor + "," + c1y / scalefactor + ")");
} else if (textmode) {
cx = (int) event.getX();
cy = (int) event.getY();
opentextDialog((int) (cx / scalefactor), (int) (cy / scalefactor));
}
break;
default:
return false;
}
invalidate();
return true;
}
draw() Method is in thread for continuously receiving points path
public boolean draw() {
//------------------------ Starting Reciving points--------------------------
String s1 = mc.getdrawlinesdual();
words1 = s1.split(",");
float xx11 = Float.parseFloat(words1[0].replaceAll("[\\(\\)\\[\\]\\{\\}]", "")) * scalefactor;
float yy11 = Float.parseFloat(words1[1]) * scalefactor;
float xx21 = Float.parseFloat(words1[2]) * scalefactor;
float yy21 = Float.parseFloat(words1[3].replaceAll("[\\(\\)\\[\\]\\{\\}]", "")) * scalefactor;
System.out.println("---------x" + xx11 + " y" + yy11 + " x2" + xx21 + " y2" + yy21);
if (a1 == 0)
{
System.out.println("----paint from pen--a1 == 0");
Log.d("TAGG", "INTEGER value " + mc.getdrawAttributes());
if (mc.getdrawTypeAttributes().toString().compareTo("eraser") == 0) {
System.out.println("Eraser--a1==0---ifllop");
Log.d("Eraser", "Im eraser");
String thh = mc.getdrawThAttributes();
float f = Float.parseFloat(thh);
paint1.setStrokeWidth(f);
if (bckimage == null) {
paint1.setColor(Color.WHITE); //Toast.makeText(getContext(),"ERASE",Toast.LENGTH_LONG).show();
} else {
paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
} else {
System.out.println("Eraser--a1==0---elsellop");
String th = mc.getdrawThAttributes();
float f = Float.parseFloat(th);
paint1.setColor(color);
}
String t = mc.getdrawTypeAttributes().trim();
if ((t.compareTo("marker") == 0)) {
Log.d("MARKER", "Hi im marker");
String col = mc.getdrawColorAttributes().substring(1);
col = col.toLowerCase();
col = "#ff" + col.trim();
int coll = Color.parseColor(col);
paint1.setColor(coll);
paint1.setAlpha(10);
paint1.setStrokeWidth(20);
if (bckimage == null) {
} else {
paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
}
}
path1.moveTo(xx11, yy11);
// path1.lineTo(xx21, yy21);
path1.quadTo(xx11, yy11, (xx11 + xx21) / 2, (yy11 + yy21) / 2);
// invalidate();
// type.add("Line");
path1 = new Path();
a1 = xx11;
b1 = yy11;
c1 = xx21;
d1 = yy21;
}
else if (a1 == xx11)
{
//il.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
System.out.println("----paint from pen--a1 == xx11");
MainActivity.this.blankwhiteboard = 1;
path1.moveTo(c1, d1);
// float x = c+(xx2-c)/2;
// float y= d+(yy2-d)/2;
path1.quadTo(c1, d1, (c1 + xx21) / 2, (d1 + yy21) / 2);
// path1.lineTo(xx21, yy21);
invalidate();
c1 = xx21;
d1 = yy21;
}
else
{
type.add("Line");
System.out.println("----paint from pen");
path1 = new Path();
paint1 = new Paint();
paint1.setAntiAlias(true);
String th = mc.getdrawThAttributes();
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeJoin(Paint.Join.ROUND);
paint1.setStrokeCap(Paint.Cap.ROUND);
paint1.setPathEffect(new CornerPathEffect(30));
paint1.setDither(true);
String t = mc.getdrawTypeAttributes();
if (mc.getdrawTypeAttributes().toString().compareTo("eraser") == 0)
{
System.out.println("Eraser--a1!=0---ifllop");
System.out.println("inside cuming erase");
//float val = 20;
String thh = mc.getdrawThAttributes();
float f = Float.parseFloat(thh);
paint1.setStrokeWidth(f);
Log.d("Eraser", "Im in eraser");
if (bckimage == null) {
paint1.setColor(Color.WHITE); //Toast.makeText(getContext(),"ERASE",Toast.LENGTH_LONG).show();
} else
paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
invalidate();
}
else
{
System.out.println("Eraser--a1!=0---elsellop");
float f = Float.parseFloat(th);
paint1.setStrokeWidth(f);
String col = mc.getdrawColorAttributes().substring(1);
col = col.toLowerCase();
col = "#ff" + col;
int coll = Color.parseColor(col);
paint1.setColor(coll);
if ((t.compareTo("marker") == 0))
{
Log.d("MARKER", "Hi im marker");
paint1.setAlpha(10);
paint1.setStrokeWidth(20);
if (bckimage == null)
{
}
else
{
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
}
paint1.setStrokeWidth(f);
mc.getTelephoneNumber(Integer.toHexString(color).substring(2));
MainActivity.super.loadUrl("javascript:colorSelectListener('')");
}
else
{
}
}
path1.moveTo(xx11, yy11);
// path1.lineTo(xx21,yy21);
path1.quadTo(xx11, yy11, (xx11 + xx21) / 2, (yy11 + yy21) / 2);
a1 = xx11;
b1 = yy11;
c1 = xx21;
d1 = yy21;
}
invalidate();
//------------------------ End Reciving points--------------------------
}
I have problem, with rendering blocks after reScalling (zoom in-out) whole thing in my game
(sorry with my eng syntax , cuz Eng not my native language)
first look at my video
>Error Rendering Video
there are problem , When it's rendering blocks after change blocks scale to some specific number
look at my code
GameLoopThread.java
public class GameLoopThread extends Thread {
static long FPS = 20;
private GameView view;
private boolean running = false;
public GameLoopThread ( GameView view ) {
this.view = view;
}
#Override
public void run () {
long ticksPS = 1000 / GameLoopThread.FPS; // 0.05 second (50) ;
long startTime;
long delayDelta = 0;
long tmpDelta = 0;
while (this.running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = this.view.getHolder().lockCanvas();
synchronized (this.view.getHolder()) {
this.view.onDraw(c);
}
ClientCoreStatic.clientGear.updateWorlds();
}
catch (NullPointerException e) {
e.printStackTrace();
}
finally {
if (c != null) this.view.getHolder().unlockCanvasAndPost(c);
}
// 50
// sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
tmpDelta = (System.currentTimeMillis() - startTime);
// time use Should below than 50
try {
if (tmpDelta > ticksPS) delayDelta += tmpDelta - ticksPS;
// d.pl("gameloop thread + " + delayDelta);
if (delayDelta > 0) {
//Thread.sleep(10);
if (ticksPS >= tmpDelta) {
delayDelta -= ticksPS - tmpDelta;
}
}
else {
delayDelta = 0;
Thread.sleep(ticksPS - tmpDelta);
}
if (this.view.hashCode() != ClientStatic.gameView.hashCode()) {
this.setRunning(false);
GameView.parentActivity.finish();
break;
}
}
catch (Exception e) {
e.printStackTrace();
d.pl("gameloop error");
}
}
}
GameView.java
#Override
public boolean onTouchEvent ( MotionEvent event ) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
// true
if (event.getPointerCount() == 1 ) {
if (GameView.spriteKeypadcircle.isCollition(
event.getX(),
event.getY()) == true) // d.pl("true..");
return true;
if (GameView.spriteBlocks.isCollition(event.getX(), event.getY())) {
// check
GameView.spriteBlocks.isCollitionOnBlock(event.getX(),event.getY());
d.pl("touching at "+ event.getX() + "," + event.getY());
return true;
}
}
if (event.getPointerCount() == 2 ) {
d.pl("distance 1 " +
GameView.distance1XY[0][0] +
"," +
GameView.distance1XY[0][1] +
" + " +
GameView.distance1XY[1][0] +
"," +
GameView.distance1XY[1][1] +
" | " +
GameView.distance2XY[0][0] +
"," +
GameView.distance2XY[0][1] +
" + " +
GameView.distance2XY[1][0] +
"," +
GameView.distance2XY[1][1]);
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
// PointF point = mActivePointers.get(event.getPointerId(i));
// if (point != null) {
// point.x = event.getX(i);
// point.y = event.getY(i);
// }
float x = event.getX(i);
float y = event.getY(i);
if (!GameView.spriteBlocks.isCollition(x, y)) break;
GameView.distance2XY[i][0] = x;
GameView.distance2XY[i][1] = y;
} // for
// after get position
// check distance
double tmp1 = Math.sqrt((Math.pow(GameView.distance1XY[0][0] -
GameView.distance1XY[1][0], 2)) +
(Math.pow(GameView.distance1XY[0][1] -
GameView.distance1XY[1][1], 2)));
double tmp2 = Math.sqrt((Math.pow(GameView.distance2XY[0][0] -
GameView.distance2XY[1][0], 2)) +
(Math.pow(GameView.distance2XY[0][1] -
GameView.distance2XY[1][1], 2)));
GameView.newDistance = Math.abs(tmp1 - tmp2);
if (GameView.newDistance > 200) { // change too much
GameView.distance1XY[0][0] = GameView.distance2XY[0][0];
GameView.distance1XY[0][1] = GameView.distance2XY[0][1];
GameView.distance1XY[1][0] = GameView.distance2XY[1][0];
GameView.distance1XY[1][1] = GameView.distance2XY[1][1];
return true;
}
// if (newDistance < 100) break;
// if (newD < 100) break;
if (tmp1 < tmp2)
SpriteBlocks.viewScale += GameView.newDistance / 1000;
else
SpriteBlocks.viewScale -= GameView.newDistance / 1000;
if (SpriteBlocks.viewScale < 0.2) SpriteBlocks.viewScale = 0.2;
if (SpriteBlocks.viewScale > 10) SpriteBlocks.viewScale = 10;
GameView.spriteBlocks.updateScale();
GameView.distance1XY[0][0] = GameView.distance2XY[0][0];
GameView.distance1XY[0][1] = GameView.distance2XY[0][1];
GameView.distance1XY[1][0] = GameView.distance2XY[1][0];
GameView.distance1XY[1][1] = GameView.distance2XY[1][1];
return true;
}
return true;
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_UP:
return true;
}
return false;
}
#Override
protected void onDraw ( Canvas canvas ) {
canvas.drawColor(Color.GRAY);
GameView.spriteBlocks.onDraw(canvas);
GameView.spriteCharStand.onDraw(canvas);
GameView.spriteKeypadcircle.onDraw(canvas);
}
SpriteBlocks.java
public SpriteBlocks ( GameView gameView, Bitmap bmp ) {
this.bmp = bmp;
SpriteBlocks.width = bmp.getWidth() / SpriteBlocks.BMP_COLUMNS;
SpriteBlocks.height = bmp.getHeight() / SpriteBlocks.BMP_ROWS;
SpriteBlocks.widthPixels = Resources.getSystem().getDisplayMetrics().widthPixels;
SpriteBlocks.heightPixels = Resources.getSystem().getDisplayMetrics().heightPixels;
SpriteBlocks.centerXScreen = SpriteBlocks.widthPixels / 2;
SpriteBlocks.centerYScreen = SpriteBlocks.heightPixels / 2;
// System.out.println("fififi " + this.weightPixels + "," +
// this.heightPixels);
updateScale();
src2 = new Rect(0, 0, 400, 400);
paintTextPlayCur.setColor(Color.BLACK);
paintTextPlayCur.setTextSize(32);
paintTextSelectBlock.setColor(Color.RED);
paintTextSelectBlock.setTextSize(32);
}
public void updateScale () {
// SpriteBlocks.viewScale = 1;
SpriteBlocks.curBlockWidth = SpriteBlocks.viewScale *
SpriteBlocks.width;
SpriteBlocks.xBlockCount = Math.round(SpriteBlocks.widthPixels /
SpriteBlocks.curBlockWidth);
SpriteBlocks.yBlockCount = Math.round(SpriteBlocks.heightPixels /
SpriteBlocks.curBlockWidth);
SpriteCharStand.curPlayerRenderHeight = SpriteCharStand.playerRenderHeight *
SpriteBlocks.viewScale;
SpriteCharStand.curPlayerRenderWidth = SpriteCharStand.playerRenderWidth *
SpriteBlocks.viewScale;
SpriteCharStand.playerLeftTopX = SpriteBlocks.centerXScreen -
(SpriteCharStand.curPlayerRenderWidth / 2);
SpriteCharStand.playerLeftTopY = SpriteBlocks.centerYScreen -
(SpriteCharStand.curPlayerRenderHeight / 2);
SpriteCharStand.playerRightDownX = SpriteBlocks.centerXScreen +
(SpriteCharStand.curPlayerRenderWidth / 2);
SpriteCharStand.playerRightDownY = SpriteBlocks.centerYScreen +
(SpriteCharStand.curPlayerRenderHeight / 2);
d.pl("viewScale = " +
SpriteBlocks.viewScale +
", width = " +
SpriteBlocks.curBlockWidth);
}
#Override
public void onDraw ( Canvas canvas ) {
update();
if (ClientStatic.minePlayer == null) {
ClientStatic.minePlayer = ClientStatic.playerList
.get(ClientStatic.mineID);
if (ClientStatic.playerList.get(ClientStatic.mineID) == null) {
d.pl(" uuuu " + ClientStatic.mineID);
return;
}
}
// center screen point is this location
minePlayerX = ClientStatic.minePlayer.getLocation().getX();// + 0.5;
minePlayerY = ClientStatic.minePlayer.getLocation().getY();// + 1;
double adderPoint = 0.1;
for ( double adder = 0 ; adder <= 1 ; adder += adderPoint) {
minePlayerX += adderPoint;
// left top of screen is this location
bX = ((minePlayerX) - (SpriteBlocks.xBlockCount / 2) - 1);
bY = ((minePlayerY) + (SpriteBlocks.yBlockCount / 2) + 1);
// right down of screen is this position
cX = ((minePlayerX) + (SpriteBlocks.xBlockCount / 2) + 1);
cY = ((minePlayerY) - (SpriteBlocks.yBlockCount / 2) - 1);
// (SpriteCharStand.curPlayerRenderWidth / 2)
Material me;
Block bbo;
leftXdiff = (minePlayerX * 100) % 100;
leftYdiff = (minePlayerY * 100) % 100;
/*
* leftXdiff = Math.abs(leftXdiff);
* leftYdiff = Math.abs(leftYdiff);
*/
// calculating them from scale
leftXdiff = (curBlockWidth * leftXdiff) / 100;
leftYdiff = (curBlockWidth * leftYdiff) / 100;
// d.pl("cur x " + minePlayerX + " |m " + leftXdiff + " |bx " + bX);
for (double xloop = bX; xloop <= cX; xloop++) { // loop all position X
//for (double yloop = bY; yloop >= cY; yloop--) { // loop all position
// Y
for (double yloop = 140.5 ; yloop == 140.5 ; yloop ++) {
// range Y
if ((yloop < 0) || yloop > (FixVariable.CHUNK_HEIGHT - 1)) {
continue;
}
// get block of that location
bbo = ClientStatic.minePlayer
.getLocation()
.getWorld()
.getBlockAt(((xloop)), ((yloop)));
me = Material.getMaterial(bbo.getTypeId());
srcX = me.getX(bbo.getData()) * SpriteBlocks.width;
srcY = me.getY(bbo.getData()) * SpriteBlocks.height;
srcKey = ((double) srcX * 10) + ((double) (srcY));
src = srcList.get(srcKey);
if (src == null) {
src = new Rect(srcX, srcY, srcX + SpriteBlocks.width, srcY +
SpriteBlocks.height);
srcList.put(srcKey, src);
}
// position to drawing
if (xloop == 5 && yloop == 140.5) {
d.pl("SPY!! " + tmpXPosition + " = " + xloop + " - " + bX + " ) * 200 -" + leftXdiff);
}
tmpXPosition = ((xloop - bX) * SpriteBlocks.curBlockWidth) -
(leftXdiff );
if (xloop == 5 && yloop == 140.5) {
if (me != Material.BED){
d.pl("bed is spy");
}
if (Math.abs(lastTmpXPosition- tmpXPosition) < 1 &&
(Math.abs(lastTmpXPosition- tmpXPosition) > 0)) {
System.out.println("WT " + (Math.abs(lastTmpXPosition- tmpXPosition)));
}
d.pl("lastTmpXPos = " + lastTmpXPosition + " | " + tmpXPosition);
if (lastTmpXPosition != tmpXPosition) {
lastTmpXPosition = tmpXPosition;
}
}
tmpYPosition = (((SpriteBlocks.yBlockCount) - (yloop - cY + (10*adder) )) * SpriteBlocks.curBlockWidth) +
(leftYdiff);
if (dst == null) {
dst = new Rect();
}
dst.set(
(int) tmpXPosition,
(int) tmpYPosition,
(int) (tmpXPosition + SpriteBlocks.curBlockWidth),
(int) (tmpYPosition + SpriteBlocks.curBlockWidth));
canvas.drawBitmap(bmp, src, dst, null);
dst2.set(
(int) (tmpXPosition),
(int) (tmpYPosition),
(int) (tmpXPosition + SpriteBlocks.curBlockWidth),
(int) (tmpYPosition + SpriteBlocks.curBlockWidth));
canvas.drawBitmap(GameView.bmpRect, src2, dst2, null);
// break;
}
} // for
bbo = ClientStatic.minePlayer
.getLocation()
.getWorld()
.getBlockAt(
ClientStatic.minePlayer.getLocation().getX(),
ClientStatic.minePlayer.getLocation().getY());
me = Material.getMaterial(bbo.getTypeId());
srcX = me.getX(bbo.getData()) * SpriteBlocks.width;
srcY = me.getY(bbo.getData()) * SpriteBlocks.height;
srcKey = ((double) srcX * 10) + ((double) (srcY));
tmpXPosition = 5;
tmpYPosition = 5;
dst.set(
(int) tmpXPosition,
(int) tmpYPosition,
(int) (tmpXPosition + SpriteBlocks.curBlockWidth),
(int) (tmpYPosition + SpriteBlocks.curBlockWidth));
canvas.drawText(
"playLoc " +
ClientStatic.minePlayer.getLocation().getX() +
"," +
ClientStatic.minePlayer.getLocation().getY(),
200,
200,
paintTextPlayCur);
canvas.drawBitmap(bmp, src, dst, null);
canvas.drawText(
"block " +
ClientStatic.minePlayer
.getLocation()
.getWorld()
.getBlockAt(
ClientStatic.minePlayer
.getLocation()
.getX(),
ClientStatic.minePlayer
.getLocation()
.getY())
.getTypeId() +
" | chunk " +
ClientStatic.minePlayer
.getLocation()
.getWorld()
.getChunkAt(
ClientStatic.minePlayer
.getLocation()
.getX())
.getChunkNumberX() +
" | " +
ClientStatic.minePlayer
.getLocation()
.getWorld()
.getChunkAt(
ClientStatic.minePlayer
.getLocation()
.getX()).getX()
,
200,
300,
paintTextPlayCur);
canvas.drawBitmap(bmp, src, dst, null);
// draw touch block
if (blockTouching != null) {
canvas.drawText("touch " +
blockTouching.getX() +
"," +
blockTouching.getY() +
" = " +
blockTouching.getTypeId() +
":" +
blockTouching.getData()
, 300, 400, paintTextSelectBlock);
}
} // adder
}
I have a game board with 5x5 squares made of canvas drawrect:
protected void onDraw(Canvas canvas) {
for (int rowNo = 0; rowNo < nSquares; rowNo++) {
paint.setColor(((rowNo & 1) == 0) ? colorA : colorB);
for (int colNo = 0; colNo < nSquares; colNo++) {
int left = colNo * squareWidth;
int top = rowNo * squareWidth;
Rect areaRect = new Rect(left, top, left + squareWidth, top + squareWidth);
canvas.drawRect(areaRect, paint);
paint.setColor((paint.getColor() == colorA) ? colorB : colorA);
paint.setTextSize((float)(squareWidth*0.8));
RectF bounds = new RectF(areaRect);
String letter = "A";
bounds.right = paint.measureText(letter, 0, letter.length());
bounds.bottom = paint.descent() - paint.ascent();
bounds.left += (areaRect.width() - bounds.right) / 2.0f;
bounds.top += (areaRect.height() - bounds.bottom) / 2.0f;
canvas.drawText(letter, bounds.left, bounds.top - paint.ascent(), paint);
}
}
I want to track touch input to get the squares the user are touching..
My attempt was
public boolean onTouchEvent(MotionEvent event){
int action = MotionEventCompat.getActionMasked(event);
int x = (int)event.getX();
int y = (int)event.getY();
Log.i(DEBUG_TAG, "Position: (" + x + ", " + y + ")");
int squareTouched = gameBoard.getSquare(x,y);
}
where getSquare is
public int getSquare(int x, int y) {
int row = 0;
int col = 0;
for(int rowNo = 1; rowNo <= nSquares; rowNo++) {
Log.i("Row", "Width: " + squareWidth + " rowNo: " + rowNo + " rowNo*squareW: " + rowNo*squareWidth + " y: " + y);
if(rowNo*squareWidth > y)
{
row = rowNo;
break;
}
}
for (int colNo = 1; colNo <= nSquares; colNo++) {
if(colNo*squareWidth > x)
{
col = colNo;
break;
}
}
Log.i(DEBUG_TAG, "Row: " + row + " Col: " + col);
return (row-1)*nSquares + col;
}
The problem is that the onTouchEvent getX and getY are referring to the screen 0,0, but when I draw the squares 0,0,0,0 is referring to the view origin? Am I right?
How can I get the input position relative to the game board view?
Could it be a solution to get the view position in the screen and add/subtract this to the tochEvent x- and y position?
I assume that the onDraw() and getSquare() belong to GameBoardView and onTouchEvent() to its immediate parent. If so then the onTouchEvent() should be like this
public boolean onTouchEvent(MotionEvent event){
int action = MotionEventCompat.getActionMasked(event);
int x = (int)event.getX() - gameBoard.getX();
int y = (int)event.getY() - gameBoard.getY();
Log.i(DEBUG_TAG, "Position: (" + x + ", " + y + ")");
int squareTouched = gameBoard.getSquare(x, y);
}
In a View x and y in both onDraw() and onTouchEvent() is relative to the View itself (Except when the View is scrolled). Since in your case onTouchEvent() belongs to parent and onDraw() to child, I used View.getX() and getY() to translate the coordinates. View.getX() returns the x position plus translationX of the View relative to its parent.
I could not get the gameBoard().getX/Y() to return the correct values. My guess is that the action bar is excluded?
I now use getLocationOnScreen
#Override
public boolean onTouchEvent(MotionEvent event){
int action = MotionEventCompat.getActionMasked(event);
int boardLocation[] = new int[2];
gameBoard.getLocationOnScreen(boardLocation);
int touchX = (int)event.getX();
int touchY = (int)event.getY();
int x = touchX - boardLocation[0];
int y = touchY - boardLocation[1];
int squareTouched = gameBoard.getSquare(x,y);
}
Which solved my issue..
I am creating a custom analog clock with images for hour, second, minute hands. The clock works fine but only problem is the anchoring of the hands. Below is an image of the clock attached. The hour, minute hands are anchored at the center which makes the clock look bad. All the hands should be anchored at the edges so that it looks more realistic and readable. Can someone suggest something. My custom view is attached here.
package com.example.submission_customclock;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews.RemoteView;
import java.util.TimeZone;
/**
* This widget display an analogic clock with two hands for hours and
* minutes.
*
* #attr ref android.R.styleable#AnalogClock_dial
* #attr ref android.R.styleable#AnalogClock_hand_hour
* #attr ref android.R.styleable#AnalogClock_hand_minute
*/
#RemoteView
public class AnalogClock extends View {
private Time mCalendar;
private static final String DEBUGTAG = "FA";
private Drawable mHourHand;
private Drawable mMinuteHand;
private Drawable mSecondHand;
private Drawable mDial;
private Drawable mDial_frame;
private int mDialWidth;
private int mDialHeight;
private boolean mAttached;
private final Handler mHandler = new Handler();
private float mMinutes;
private float mHour;
private boolean mChanged;
public AnalogClock(Context context) {
this(context, null);
}
public AnalogClock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
Context mContext;
public AnalogClock(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
Resources r = context.getResources();
mContext=context;
Log.d(AnalogClock.DEBUGTAG,"Analog clock started");
mDial = r.getDrawable(R.drawable.clock4);
mDial_frame = r.getDrawable(R.drawable.clock_frame);
mHourHand = r.getDrawable(R.drawable.hour_hand);
mMinuteHand = r.getDrawable(R.drawable.minute_hand);
mSecondHand = r.getDrawable(R.drawable.second_hand);
mCalendar = new Time();
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
}
// NOTE: It's safe to do these after registering the receiver since the receiver always runs
// in the main thread, therefore the receiver can't run before this method returns.
// The time zone may have changed while the receiver wasn't registered, so update the Time
mCalendar = new Time();
// Make sure we update to the current time
onTimeChanged();
counter.start();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
counter.cancel();
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
float hScale = 1.0f;
float vScale = 1.0f;
if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
hScale = (float) widthSize / (float) mDialWidth;
}
if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
vScale = (float )heightSize / (float) mDialHeight;
}
float scale = Math.min(hScale, vScale);
Log.d(AnalogClock.DEBUGTAG,"onMeasure params: " + widthSize + " "
+ heightSize + " " + hScale + " " + vScale + " " + scale);
try {
setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mChanged = true;
}
boolean mSeconds=false;
float mSecond=0;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
boolean seconds = mSeconds;
if (seconds ) {
mSeconds = false;
}
int availableWidth = this.getMeasuredWidth();
int availableHeight = this.getMeasuredHeight();
int x = availableWidth / 2;
int y = availableHeight / 2;
final Drawable dial = mDial;
final Drawable dial_frame = mDial_frame;
int w = dial.getIntrinsicWidth();
int h = dial.getIntrinsicHeight();
boolean scaled = false;
// Log.d(AnalogClock.DEBUGTAG,"onDraw params: " + availableWidth +" "+ availableHeight + " " +
// x + " " + y + " " + w + " "+ h + " " + changed);
if (availableWidth < w || availableHeight < h) {
scaled = true;
//float scale = Math.min((float) availableWidth / (float) w,
// (float) availableHeight / (float) h);
canvas.save();
float scale1 = (float) 0.6;
float scale2 = (float) 0.8;
// Log.d(AnalogClock.DEBUGTAG,"scale params: " + scale1 + " " + scale2);
canvas.scale(scale1, scale2, x, y);
}
if (changed) {
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2)) + " " + (y - (h / 2)) + " " + ( x + (w / 2)) + " " + (y + (h / 2)));
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//dial_frame.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2 + w/10)) + " " + (y - (h / 2 + h/10)) + " " + ( x + (w / 2 + w/10)) + " " +
// (y + (h / 2 + h/10)));
dial_frame.setBounds(x - (w/2 + w/10), y - (h/2 + h/10), x + (w/2 + w/10), y + (h/2 + h/10));
}
dial.draw(canvas);
dial_frame.draw(canvas);
canvas.save();
canvas.rotate(mHour / 12.0f * 180.0f, x, y);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth();
h = hourHand.getIntrinsicHeight();
hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mMinutes / 60.0f * 180.0f, x, y);
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth();
h = minuteHand.getIntrinsicHeight();
minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
minuteHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mSecond, x, y);
if (seconds) {
w = mSecondHand.getIntrinsicWidth();
h = mSecondHand.getIntrinsicHeight();
mSecondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
mSecondHand.draw(canvas);
canvas.restore();
if (scaled) {
canvas.restore();
}
}
MyCount counter = new MyCount(10000, 1000);
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
counter.start();
}
#Override
public void onTick(long millisUntilFinished) {
mCalendar.setToNow();
int second = mCalendar.second;
mSecond=6.0f*second;
mSeconds=true;
//mChanged = true;
AnalogClock.this.invalidate();
}
}
private void onTimeChanged() {
mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
int second = mCalendar.second;
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
}
onTimeChanged();
invalidate();
}
};
}
your problem is with specific dimensions for clock_frame ,minute_hand,hour_hand and second_hand in drawable folder.for example if you take 240 x 240 clockframe the you should takeminute_hand,hour_hand and second_hand as 19 x 240 and these hands should start from top and end with exactly center position of clock_frame with comparition.if u want more fashionable you can end up with slightly distance from exactly center position of clock_frame
Simplest way is to set hands bitmaps the same size as dial and rotate to 12 o clock.
I have created a circle in custom view. I want to add 6 colors to it based on a condition. The 6 regions will keep changing based on the condition. For eg, each region can vary from 30 degrees to 90 degrees to 120 degrees.
My question is
1) How do I add 6 colors to the circle. Please note that I cannot divide the circle into 6 equal regions, thats not how it is supposed to be.
2) How do I assign the starting and ending points of the regions. For example if I want to add green color from 45degrees to 90 degrees. How do I do this?
The end product is supposed to look as below
package com.example.submission_customclock;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews.RemoteView;
import java.util.TimeZone;
/**
* This widget display an analogic clock with two hands for hours and
* minutes.
*
* #attr ref android.R.styleable#AnalogClock_dial
* #attr ref android.R.styleable#AnalogClock_hand_hour
* #attr ref android.R.styleable#AnalogClock_hand_minute
*/
#RemoteView
public class AnalogClock extends View {
private Time mCalendar;
private static final String DEBUGTAG = "FA";
private Drawable mHourHand;
private Drawable mMinuteHand;
private Drawable mSecondHand;
private Drawable mDial;
private Drawable mDial_frame;
private Drawable mDial_center;
private int mDialWidth;
private int mDialHeight;
private boolean mAttached;
private final Handler mHandler = new Handler();
private float mMinutes;
private float mHour;
private boolean mChanged;
public AnalogClock(Context context) {
this(context, null);
}
public AnalogClock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
Context mContext;
public AnalogClock(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
Resources r = context.getResources();
mContext=context;
Log.d(AnalogClock.DEBUGTAG,"Analog clock started");
mDial = r.getDrawable(R.drawable.clock4);
mDial_frame = r.getDrawable(R.drawable.clock_frame);
mDial_center = r.getDrawable(R.drawable.clock_dot);
mHourHand = r.getDrawable(R.drawable.hour_hand);
mMinuteHand = r.getDrawable(R.drawable.minute_hand);
mSecondHand = r.getDrawable(R.drawable.second_hand);
mCalendar = new Time();
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
}
// NOTE: It's safe to do these after registering the receiver since the receiver always runs
// in the main thread, therefore the receiver can't run before this method returns.
// The time zone may have changed while the receiver wasn't registered, so update the Time
mCalendar = new Time();
// Make sure we update to the current time
onTimeChanged();
counter.start();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
counter.cancel();
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
float hScale = 1.0f;
float vScale = 1.0f;
if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
hScale = (float) widthSize / (float) mDialWidth;
}
if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
vScale = (float )heightSize / (float) mDialHeight;
}
float scale = Math.min(hScale, vScale);
Log.d(AnalogClock.DEBUGTAG,"onMeasure params: " + widthSize + " "
+ heightSize + " " + hScale + " " + vScale + " " + scale);
try {
setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mChanged = true;
}
boolean mSeconds=false;
float mSecond=0;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
boolean seconds = mSeconds;
if (seconds ) {
mSeconds = false;
}
int availableWidth = this.getMeasuredWidth();
int availableHeight = this.getMeasuredHeight();
int x = availableWidth / 2;
int y = availableHeight / 2;
final Drawable dial = mDial;
final Drawable dial_frame = mDial_frame;
final Drawable dial_dot = mDial_center;
int w = dial.getIntrinsicWidth();
int h = dial.getIntrinsicHeight();
boolean scaled = false;
// Log.d(AnalogClock.DEBUGTAG,"onDraw params: " + availableWidth +" "+ availableHeight + " " +
// x + " " + y + " " + w + " "+ h + " " + changed);
if (availableWidth < w || availableHeight < h) {
scaled = true;
//float scale = Math.min((float) availableWidth / (float) w,
// (float) availableHeight / (float) h);
canvas.save();
float scale1 = (float) 0.6;
float scale2 = (float) 0.8;
// Log.d(AnalogClock.DEBUGTAG,"scale params: " + scale1 + " " + scale2);
canvas.scale(scale1, scale2, x, y);
}
if (changed) {
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2)) + " " + (y - (h / 2)) + " " + ( x + (w / 2)) + " " + (y + (h / 2)));
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//dial_frame.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2 + w/10)) + " " + (y - (h / 2 + h/10)) + " " + ( x + (w / 2 + w/10)) + " " +
// (y + (h / 2 + h/10)));
dial_frame.setBounds(x - (w/2 + w/10), y - (h/2 + h/10), x + (w/2 + w/10), y + (h/2 + h/10));
dial_dot.setBounds(x -30 , y -20 , x + 30, y + 20);
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x ) + " " + (y) + " " + ( x + (w / 2 )) + " " +
// (y + (h / 2)));
}
int radius = 0;
if(x>y)
radius=y-10;
else
radius=x-10;
Paint circlepaint;
circlepaint = new Paint();
circlepaint.
dial.draw(canvas);
dial_frame.draw(canvas);
// canvas.drawCircle(x, y, radius, circlepaint);
canvas.save();
canvas.rotate(mHour / 12.0f * 180.0f, x - 10, y - 10);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth();
h = hourHand.getIntrinsicHeight();
hourHand.setBounds(x -w/2, y - h/2 - h/4 , x + w/6, y + h/6);
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mMinutes / 60.0f * 360.0f, x - 10, y - 10);
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth();
h = minuteHand.getIntrinsicHeight();
//minuteHand.setBounds(x, y, x + (w / 2 + w/10), y + (h / 2 + w/10));
minuteHand.setBounds(x - w, y - h/2, x + w/6, y + h/6);
// Log.d(AnalogClock.DEBUGTAG,"Bounds params:x " + (x) + " y " + (y) + " w " + ( w ) + " h " +
// (h));
// Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - w) + " " + (y - h/2) + " " + ( x ) + " " +
// (y));
}
minuteHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mSecond, x, y);
if (seconds) {
w = mSecondHand.getIntrinsicWidth();
h = mSecondHand.getIntrinsicHeight();
// mSecondHand.setBounds(x, y, x + (w / 2 + w/10), y + (h / 2 + w/10));
mSecondHand.setBounds(x-w/6, y-h/6, x + w,y + h/2);
Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x ) + " " + (y) + " " + ( w) + " " +
(h));
}
mSecondHand.draw(canvas);
canvas.restore();
canvas.save();
dial_dot.draw(canvas);
if (scaled) {
canvas.restore();
}
}
MyCount counter = new MyCount(10000, 1000);
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
counter.start();
}
#Override
public void onTick(long millisUntilFinished) {
mCalendar.setToNow();
int second = mCalendar.second;
mSecond=6.0f*second;
mSeconds=true;
//mChanged = true;
AnalogClock.this.invalidate();
}
}
private void onTimeChanged() {
mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
int second = mCalendar.second;
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
}
onTimeChanged();
invalidate();
}
};
}