Google Vision: Drawing mask on Face with animations - android

I am using google vision library for face detection. Face detection is perfect and I get all the info like vertices, angles like eulerY, eulerZ.
I want to draw mask on face, drawing is ok but the face mask is not following the face position as it should, the position is not correct. Here is my edited code to draw face mask on googly eyes project.
Here is my source code:
package com.google.android.gms.samples.vision.face.googlyeyes;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.google.android.gms.samples.vision.face.googlyeyes.ui.camera.GraphicOverlay;
import com.google.android.gms.vision.face.Face;
import java.util.HashMap;
/**
* Graphics class for rendering Googly Eyes on a graphic overlay given the current eye positions.
*/
class GooglyEyesGraphic extends GraphicOverlay.Graphic {
private Paint mEyeWhitesPaint;
private Paint mEyeIrisPaint;
private Paint mEyeOutlinePaint;
private Paint mEyeLidPaint;
Paint mBoxPaint;
Context mContext;
private static final float BOX_STROKE_WIDTH = 20.0 f;
FrameLayout frameLayout;
ImageView imageView;
// Bitmap bmpOriginal;
//==============================================================================================
// Methods
//==============================================================================================
GooglyEyesGraphic(GraphicOverlay overlay, Context mContext) {
super(overlay);
this.mContext = mContext;
mEyeWhitesPaint = new Paint();
mEyeWhitesPaint.setColor(Color.WHITE);
mEyeWhitesPaint.setStyle(Paint.Style.FILL);
mEyeLidPaint = new Paint();
mEyeLidPaint.setColor(Color.YELLOW);
mEyeLidPaint.setStyle(Paint.Style.FILL);
mEyeIrisPaint = new Paint();
mEyeIrisPaint.setColor(Color.BLACK);
mEyeIrisPaint.setStyle(Paint.Style.FILL);
mEyeOutlinePaint = new Paint();
mEyeOutlinePaint.setColor(Color.BLACK);
mEyeOutlinePaint.setStyle(Paint.Style.STROKE);
mEyeOutlinePaint.setStrokeWidth(5);
mBoxPaint = new Paint();
mBoxPaint.setColor(Color.MAGENTA);
mBoxPaint.setStyle(Paint.Style.STROKE);
mBoxPaint.setStrokeWidth(BOX_STROKE_WIDTH);
mBoxPaint.setAlpha(40);
LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = li.inflate(R.layout.mask_layout, null);
imageView = (ImageView) view.findViewById(R.id.flMaskIV);
frameLayout = (FrameLayout) view.findViewById(R.id.frameLayout);
}
private volatile Face mFace;
/**
* Updates the eye positions and state from the detection of the most recent frame. Invalidates
* the relevant portions of the overlay to trigger a redraw.
*/
void updateEyes(PointF leftPosition, boolean leftOpen,
PointF rightPosition, boolean rightOpen, Face mFace) {
if (facesList.containsKey(mFace.getId())) {
PointF pointF1 = facesList.get(mFace.getId()).getPosition();
PointF pointF2 = mFace.getPosition();
double x = Math.sqrt(Math.pow(pointF2.x - pointF1.x, 2) - Math.pow(pointF2.y - pointF1.y, 2));
if (x < 0)
x = (-1 * x);
if (x < 10)
return;
Log.e("face Called", "FaceCalled");
}
this.mFace = mFace;
facesList.put(mFace.getId(), mFace);
postInvalidate();
}
public HashMap < Integer, Face > facesList = new HashMap < > ();
/**
* Draws the current eye state to the supplied canvas. This will draw the eyes at the last
* reported position from the tracker, and the iris positions according to the physics
* simulations for each iris given motion and other forces.
*/
#Override
public void draw(Canvas canvas) {
if (mFace == null)
return;
// if (facesList.containsKey(mFace.getId())) {
// PointF pointF1 = facesList.get(mFace.getId()).getPosition();
// PointF pointF2 = mFace.getPosition();
//
// double x = Math.sqrt(Math.pow(pointF2.x - pointF1.x, 2) - Math.pow(pointF2.y - pointF1.y, 2));
// if (x < 0)
// x = (-1 * x);
// if (x < 10)
// return;
// Log.e("face Called", "FaceCalled");
//
// }
//
// facesList.put(mFace.getId(), mFace);
if (this.canvas == null)
this.canvas = canvas;
applyMask();
}
Drawable drawable;
Canvas canvas;
private void applyMask() {
if (canvas == null)
return;
// Log.e("mFace.getEulerY()", "mFace.getEulerY()=> " + mFace.getEulerY());
if (GooglyEyesActivity.maskImgView != null) {
GooglyEyesActivity.maskImgView.setVisibility(View.GONE);
GooglyEyesActivity.maskImgView.setImageResource(GooglyEyesActivity.currEmoticonID);
}
float x = translateX(mFace.getPosition().x + mFace.getWidth() / 2);
float y = translateY(mFace.getPosition().y + mFace.getHeight() / 2);
// Draws a bounding box around the face.
float xOffset = scaleX(mFace.getWidth() / 2.0 f);
float yOffset = scaleY(mFace.getHeight() / 2.0 f);
float left = x - xOffset - 50;
float top = y - (yOffset) - 50;
float right = x + xOffset + 50;
float bottom = y + (yOffset) + 50;
// canvas.drawRect((int) left, (int) top, (int) right, (int) bottom, mBoxPaint);
drawable = GooglyEyesActivity.maskImgView.getDrawable();
///////////////////
canvas.save();
canvas.translate(left, top);
// frameLayout.setX(left);
// frameLayout.setY(top);
Rect rect = new Rect((int) left, (int) top, (int) right, (int) bottom);
frameLayout.measure(rect.width(), rect.height());
frameLayout.setLayoutParams(new LinearLayout.LayoutParams(rect.width(), rect.height()));
frameLayout.layout(0, 0, (int) right, (int) bottom);
frameLayout.setClipBounds(rect);
imageView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height()));
imageView.setRotationY(mFace.getEulerY());
imageView.setRotation(mFace.getEulerZ());
imageView.setImageDrawable(drawable);
frameLayout.draw(canvas);
canvas.restore();
}
}
Also i need to add animations so i tried using dlib library to get landmarks points and draw it using opengl but in opengl i dont have any function to populate the vertice array i am getting from dlib. As the dlib landmarks are in points but the array there is not in such a way. Any help will be appreciated for both scenarios.
Thank you in advance.
Thanks.

Related

spherical animation with text for using tag cloud in android app [News Republic]

I want to create spherical animation in my android app similar to this in
News Republic app.
I have tried to create a sphere so far but can anyone guide me how to proceed to develop animations like this in android.
Do we have to use opengl only or we can achieve it with other alternative option.
Also, when the text is clicked it opens the related news in a different screen.
EDIT
I finally found some solution for this, which is available under this package.
But, the animation is not smooth enough.
Let me know if anyone can help me in the smoothing of the animations?
You don't need OpenGL. You can do that using a simple view and Canvas. I wrote a bit of code for you. You can just copy it to your project, add to xml and run:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class TagCloudView extends View {
String[] tags = new String[]{"Lemon","Orange","Strawberry","Plum","Pear","Pineapple","Blackberry","Watermelon"};
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float scroll = 0;
private float prevY;
public TagCloudView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
float r = getHeight() / 3;
paint.setColor(Color.BLACK);
paint.setTextAlign(Paint.Align.CENTER);
for (int i = 0; i < tags.length; i++) {
float t = i + scroll / getHeight();
float y = (float) (r * Math.cos(Math.PI * 2 * t / tags.length)); // parametric circle equation
float z = (float) (r * Math.sin(Math.PI * 2 * t / tags.length));
paint.setTextSize((r + z) / r/2 * 40 + 20); // magic values, change to something better
paint.setAlpha((int) ((r + z) / r/2 * 127 + 128));
canvas.drawText(tags[i], getWidth() / 2, getHeight() / 2 + y, paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN)
scroll -= event.getY() - prevY; // only one plane
prevY = event.getY();
invalidate();
return true;
}
}
To achieve the result you described, you have to add smooth scrolling using Scroller, change the circle equation to the sphere equation, tweak parameters and add some getters/setters. Using parametric equations you can also find the text touched by the user. This View looks like this:

TileProvider graphics gets skewed on higher zoom levels

Im currently playing with TileProver in Android Maps API v2 and kinda stuck with the following problem: graphics which I paint manually into Bitmap gets skewed significantly on higher zoom levels:
Let me explain what Im doing here. I have number of LatLng points and I draw a circle for every point on a map, so as you zoom in - point stays at the same geo location. As you can see on the screenshot, circles look fine on lower zoom levels, but as you start zooming in - circles get skewed..
That's how it is implemented:
package trickyandroid.com.locationtracking;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.Log;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Tile;
import com.google.android.gms.maps.model.TileProvider;
import com.google.maps.android.geometry.Point;
import com.google.maps.android.projection.SphericalMercatorProjection;
import java.io.ByteArrayOutputStream;
/**
* Created by paveld on 8/8/14.
*/
public class CustomTileProvider implements TileProvider {
private final int TILE_SIZE = 256;
private int density = 1;
private int tileSizeScaled;
private Paint circlePaint;
private SphericalMercatorProjection projection;
private Point[] points;
public CustomTileProvider(Context context) {
density = 3; //hardcoded for now, but should be driven by DisplayMetrics.density
tileSizeScaled = TILE_SIZE * density;
projection = new SphericalMercatorProjection(TILE_SIZE);
points = generatePoints();
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setColor(0xFF000000);
circlePaint.setStyle(Paint.Style.FILL);
}
private Point[] generatePoints() {
Point[] points = new Point[6];
points[0] = projection.toPoint(new LatLng(47.603861, -122.333393));
points[1] = projection.toPoint(new LatLng(47.600389, -122.326741));
points[2] = projection.toPoint(new LatLng(47.598942, -122.318973));
points[3] = projection.toPoint(new LatLng(47.599000, -122.311549));
points[4] = projection.toPoint(new LatLng(47.601373, -122.301721));
points[5] = projection.toPoint(new LatLng(47.609764, -122.311850));
return points;
}
#Override
public Tile getTile(int x, int y, int zoom) {
Bitmap bitmap = Bitmap.createBitmap(tileSizeScaled, tileSizeScaled, Bitmap.Config.ARGB_8888);
float scale = (float) (Math.pow(2, zoom) * density);
Matrix m = new Matrix();
m.setScale(scale, scale);
m.postTranslate(-x * tileSizeScaled, -y * tileSizeScaled);
Canvas c = new Canvas(bitmap);
c.setMatrix(m);
for (Point p : points) {
c.drawCircle((float) p.x, (float) p.y, 20 / scale, circlePaint);
}
return bitmapToTile(bitmap);
}
private Tile bitmapToTile(Bitmap bmp) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bitmapdata = stream.toByteArray();
return new Tile(tileSizeScaled, tileSizeScaled, bitmapdata);
}
}
Logic tells me that this is happening because I'm translating LatLng into screen position only for 1 tile (256x256 which is zoom level 0) and then in order to translate this screen point to other zoom levels, I need to scale my bitmap and translate it to appropriate position. At the same time, since bitmap is scaled, I need to compensate circle radius, so I divide radius by scale factor. So at zoom level 19 my scale factor is already 1572864 which is huge. It is like looking at this circle via huge magnifying glass. That's why I have this effect.
So I suppose the solution would be to avoid bitmap scaling and scale/translate only screen coordinates. In this case my circle radius will be always the same and will not be downscaled.
Unfortunately, matrix math is not my strongest skill, so my question is - how do I scale/translate set of points for arbitrary zoom level having set of points calculated for zoom level '0'?
The easiest way for doing this would be to have different Projection instances for each zoom level, but since GeoPoint -> ScreenPoint translation is quite expensive operation, I would keep this approach as a back-up and use some simple math for translating already existing screen points.
NOTE
Please note that I need specifically custom TileProvider since in the app I will be drawing much more complicated tiles than just circles. So simple Marker class is not going to work for me here
UPDATE
Even though I figured out how to translate individual points and avoid bitmap scaling:
c.drawCircle((float) p.x * scale - (x * tileSizeScaled), (float) p.y * scale - (y * tileSizeScaled), 20, circlePaint);
I still don't know how to do this with Path objects. I cannot translate/scale path like you would do this with individual points, so I still have to scale my bitmap which causes drawing artifacts again (stroke width is skewed on higher zoom levels):
And here is a code snippet:
package trickyandroid.com.locationtracking;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Tile;
import com.google.android.gms.maps.model.TileProvider;
import com.google.maps.android.geometry.Point;
import com.google.maps.android.projection.SphericalMercatorProjection;
import java.io.ByteArrayOutputStream;
/**
* Created by paveld on 8/8/14.
*/
public class CustomTileProvider implements TileProvider {
private final int TILE_SIZE = 256;
private int density = 1;
private int tileSizeScaled;
private SphericalMercatorProjection projection;
private Point[] points;
private Path path;
private Paint pathPaint;
public CustomTileProvider(Context context) {
density = 3; //hardcoded for now, but should be driven by DisplayMetrics.density
tileSizeScaled = TILE_SIZE * density;
projection = new SphericalMercatorProjection(TILE_SIZE);
points = generatePoints();
path = generatePath(points);
pathPaint = new Paint();
pathPaint.setAntiAlias(true);
pathPaint.setColor(0xFF000000);
pathPaint.setStyle(Paint.Style.STROKE);
pathPaint.setStrokeCap(Paint.Cap.ROUND);
pathPaint.setStrokeJoin(Paint.Join.ROUND);
}
private Path generatePath(Point[] points) {
Path path = new Path();
path.moveTo((float) points[0].x, (float) points[0].y);
for (int i = 1; i < points.length; i++) {
path.lineTo((float) points[i].x, (float) points[i].y);
}
return path;
}
private Point[] generatePoints() {
Point[] points = new Point[10];
points[0] = projection.toPoint(new LatLng(47.603861, -122.333393));
points[1] = projection.toPoint(new LatLng(47.600389, -122.326741));
points[2] = projection.toPoint(new LatLng(47.598942, -122.318973));
points[3] = projection.toPoint(new LatLng(47.599000, -122.311549));
points[4] = projection.toPoint(new LatLng(47.601373, -122.301721));
points[5] = projection.toPoint(new LatLng(47.609764, -122.311850));
points[6] = projection.toPoint(new LatLng(47.599221, -122.311531));
points[7] = projection.toPoint(new LatLng(47.599663, -122.312410));
points[8] = projection.toPoint(new LatLng(47.598823, -122.312614));
points[9] = projection.toPoint(new LatLng(47.599959, -122.310651));
return points;
}
#Override
public Tile getTile(int x, int y, int zoom) {
Bitmap bitmap = Bitmap.createBitmap(tileSizeScaled, tileSizeScaled, Bitmap.Config.ARGB_8888);
float scale = (float) (Math.pow(2, zoom) * density);
Canvas c = new Canvas(bitmap);
Matrix m = new Matrix();
m.setScale(scale, scale);
m.postTranslate(-x * tileSizeScaled, -y * tileSizeScaled);
c.setMatrix(m);
pathPaint.setStrokeWidth(6 * density / scale);
c.drawPath(path, pathPaint);
return bitmapToTile(bitmap);
}
private Tile bitmapToTile(Bitmap bmp) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bitmapdata = stream.toByteArray();
return new Tile(tileSizeScaled, tileSizeScaled, bitmapdata);
}
}
I see you are using google's tileview, you can try and consider mogarius's library which is an open source on github
I never tried it before but it support most of the functionalities you need (markers\dots and dynamic path drawing) out of the box so that'll save you the time spending on making matrix calculations for upscaling and downscaling.
there is also a demo video for some of the usage he made, and a great javadoc he published.

How to draw only a part of arc in canvas

I'm developing an analog clock widget and the dial of clock is an image.
I want to draw an arc segment like in the image(as shown in orange).
paint.setColor(Color.GREEN);
paint.setStrokeWidth(20);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(100, 100, 200, paint);
I tried with drawcircle and also with drawArc but could not proceed since i want only a part of arc and not a complete arc. Any ideas ?
I made this class hope it help you, all variable are in spanish but its quite simple,
the constructor SemiCirculo use as parameters the rgb for the semicircle and the resolution (number of triangles for your semicircle)
the CalcularPuntosPorcentaje method use as parameters the center of the circle, the starting angle, the widht of the angle, and the radio.
the method ImprimeCirculo use the canvas as parameter, it is used to draw the semicircle once it has allready been calcultaed the points of the semicircle with the previus mentioned method.
the CalcularPuntosPorcentaje method is similar to CalcularPuntosPorcentaje, but insted of the starting and the widht angle parameters it use a % from 0 to 100
finaly the SetOffset and SetColor are used to change the default starting poing o reference for the angle and the color of the semicircle
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
public class SemiCirculo {
private Path circulo;
private Paint color;
private float px, py, radio, anguloI, anchoa,offset;
private int r, g, b;
private int resolucion;
private float puntox[],puntoy[];
public SemiCirculo(int r1, int g1, int b1, int resolucion1) {
this.offset = 0;
this.color = new Paint();
this.r = r1;
this.g = g1;
this.b = b1;
this.color.setColor(Color.rgb(r, g, b));
color.setAntiAlias(true);
circulo = new Path();
this.resolucion = resolucion1;
this.puntox = new float[this.resolucion];
this.puntoy = new float[this.resolucion];
this.anguloI = 0;
this.anchoa = 1;
}
public void SetOffset(float off) {
this.offset = off;
}
public void SetColor(int r1,int g1, int b1){
this.r=r1;
this.g=g1;
this.b=b1;
this.color.setColor(Color.rgb(r, g, b));
}
public void CalcularPuntosPorcentaje(float px1, float py1,
float porcentaje, float radio1) {
this.anguloI = 0 + this.offset;
this.px = px1;
this.py = py1;
this.radio = radio1;
this.anguloI = 0;
this.anchoa = porcentaje / 100 * 360;
this.CalcularPuntos(px, py, anguloI, anchoa, radio);
}
public void CalcularPuntos(float px1, float py1, float anguloI1,
float anchoangulo, float radio1) {
this.anguloI = anguloI1 + this.offset;
this.anchoa = anchoangulo;
this.px = px1;
this.py = py1;
this.radio = radio1 ;
float angulo = 360 - this.anguloI - this.anchoa;
for (int i = 0; i < resolucion; i++) {
this.puntox[i] = this.px - (float) Math.sin(Math.toRadians(angulo))
* this.radio;
this.puntoy[i] = this.py - (float) Math.cos(Math.toRadians(angulo))
* this.radio;
angulo = (360 - this.anguloI - this.anchoa)
+ ((this.anchoa / (float) (this.resolucion)) * (i + 2));
}
this.circulo.reset();
this.circulo.moveTo(this.px, this.py);
for (int i = 0; i < resolucion; i++) {
this.circulo.lineTo(this.puntox[i], this.puntoy[i]);
}
}
public void ImprimeCirculo(Canvas canvas) {
canvas.drawPath(this.circulo, this.color);
}
}
You need to use this method:
canvas.drawArc(innerRect, -11.0f, 11.0f + 6.0f, true, paintx);
for docs see here:
http://developer.android.com/reference/android/graphics/Canvas.html#drawArc%28android.graphics.RectF,%20float,%20float,%20boolean,%20android.graphics.Paint%29
Be sure set the angle parameters correctly! And use float!
The first angle is the start of your arc and the second angle param is the sweep angle, ie how many degrees long should the angle be - measured clockwise.
Try it, it will work for sure. Just needs a little playing around :-)

How to set a high res Image in xml?

I just need to set a high res image, but wants to know if its possible to set it in xml. I want to be able to set it even if it will be bigger than the mobile screen.
EDIT: I want to add a huge image, so the user will have to scroll it. Something like a map, but need to add clickable areas on it and I only know how to do this in xml. That's why I asked to add the image using xml not in java. But if someone can tell me how to add clickable areas in java. That will do it better, since I already have the image but using java and its able to scroll.
EDIT: Heres where I got the code from : Anddev.org I'm using exactly the same code, just with other image.
What are you trying for? In android the resolutions are based on like below -
Screen Support
MultipleResolution
Just read out this. Hope these two links enough for your query.
Have a look at this sample code to see how to scroll an image larger than the screen. It also does bitmap caching to speed up drawing of a complex image, and shows how to respond to long-taps and double-taps at any point on the image.
Ok I'm posting this as an answer, just because it will be easier to post this. (It's not working how I want it to, but I got something) I want to share this so anyone else, who knows how to, can help me out here to find a solution for this one. This is the code
package com.example.largeimagescroller;
import android.app.Activity;
import android.os.Bundle;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;
public class LargeImageScroller extends Activity {
// Physical display width and height.
private static int displayWidth = 0;
private static int displayHeight = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// displayWidth and displayHeight will change depending on screen
// orientation. To get these dynamically, we should hook
// onSizeChanged().
// This simple example uses only landscape mode, so it's ok to get them
// once on startup and use those values throughout.
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
// SampleView constructor must be constructed last as it needs the
// displayWidth and displayHeight we just got.
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private static Bitmap bmLargeImage; // bitmap large enough to be
// scrolled
private static Rect displayRect = null; // rect we display to
private Rect scrollRect = null; // rect we scroll over our bitmap with
private int scrollRectX = 0; // current left location of scroll rect
private int scrollRectY = 0; // current top location of scroll rect
private float scrollByX = 0; // x amount to scroll by
private float scrollByY = 0; // y amount to scroll by
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
public SampleView(Context context) {
super(context);
// Destination rect for our main canvas draw. It never changes.
displayRect = new Rect(0, 0, displayWidth, displayHeight);
// Scroll rect: this will be used to 'scroll around' over the
// bitmap in memory. Initialize as above.
scrollRect = new Rect(0, 0, displayWidth, displayHeight);
// Load a large bitmap into an offscreen area of memory.
bmLargeImage = BitmapFactory.decodeResource(getResources(),
R.drawable.alienware);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//This code define what to do if you touch the x and y coordinates.
float x1 = event.getX();
float y1 = event.getY();
switch (event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
if (x1>150 & x1<200 & y1>400 & y1<500){
Toast.makeText(getContext(), "Touched the coordinates.", Toast.LENGTH_SHORT).show();
}
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Remember our initial down event location.
startX = event.getRawX();
startY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float x = event.getRawX();
float y = event.getRawY();
// Calculate move update. This will happen many times
// during the course of a single movement gesture.
scrollByX = x - startX; // move update x increment
scrollByY = y - startY; // move update y increment
startX = x; // reset initial values to latest
startY = y;
invalidate(); // force a redraw
break;
}
return true; // done with this event so consume it
}
#Override
protected void onDraw(Canvas canvas) {
// Our move updates are calculated in ACTION_MOVE in the opposite
// direction
// from how we want to move the scroll rect. Think of this as
// dragging to
// the left being the same as sliding the scroll rect to the right.
int newScrollRectX = scrollRectX - (int) scrollByX;
int newScrollRectY = scrollRectY - (int) scrollByY;
// Don't scroll off the left or right edges of the bitmap.
if (newScrollRectX < 0)
newScrollRectX = 0;
else if (newScrollRectX > (bmLargeImage.getWidth() - displayWidth))
newScrollRectX = (bmLargeImage.getWidth() - displayWidth);
// Don't scroll off the top or bottom edges of the bitmap.
if (newScrollRectY < 0)
newScrollRectY = 0;
else if (newScrollRectY > (bmLargeImage.getHeight() - displayHeight))
newScrollRectY = (bmLargeImage.getHeight() - displayHeight);
// We have our updated scroll rect coordinates, set them and draw.
scrollRect.set(newScrollRectX, newScrollRectY, newScrollRectX
+ displayWidth, newScrollRectY + displayHeight);
Paint paint = new Paint();
canvas.drawBitmap(bmLargeImage, scrollRect, displayRect, paint);
// Reset current scroll coordinates to reflect the latest updates,
// so we can repeat this update process.
scrollRectX = newScrollRectX;
scrollRectY = newScrollRectY;
}
}
}
I rec the application in use. (Since touch events don't work with cpu emulators I did it on my phone)
http://www.youtube.com/watch?v=NrszZoDenXE&feature=youtube_gdata
As you can see its taking the touch, but it moves with the scroll rect, so the question will be: How can I do the touch to stay in the image, so it doesn't move with the scrolling rect?
Thanks

Android Listener on canvas?

I just got started with Android and I was wondering how to use listeners in a canvas. Particularly as part of my project, the objective is for an event to occur when we drag click from one point to another. The concept is from a game called brainvita. The game need not be understood to answer my question. All I want to know is the simplest way to make a listener for the drag clicks from one point to another on the canvas?
Do I need to map the canvas to a grid and have multiple listeners? What is the simplest way?
Additionally I'm attaching the code of the game developed so far, just the basics that help in displaying the grid!
package com.project.android.brainvita;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class GameView extends View {
Paint paint = new Paint();
Paint paintF = new Paint();
Paint paintG = new Paint();
int width, height;
int MARGIN = 4;
int MARGIN_BIG = 10;
int sx = 2;
public GameView(Context context) {
super(context);
paint.setColor(Color.WHITE);
paintF.setColor(Color.rgb(40, 60, 204));
paintG.setColor(Color.rgb(240, 30, 20));
}
public void onDraw(Canvas canvas) {
// Draw external circle
canvas.drawCircle(width / 2, height / 2, (width - MARGIN) / 2, paintF);
// Calculate radius of small circles
int radius = (width - MARGIN_BIG*2) / 14;
// Draw grid
for (int j = -3; j <= 3; j++) {
if (j >= -1 && j <= 1)
for (int i = -3; i <= 3; i++) {
canvas.drawCircle(width / 2 + (2 * radius * i), height / 2
+ (2 * radius * j), radius - sx, paint);
}
else
for (int i = -1; i <= 1; i++) {
canvas.drawCircle(width / 2 + (2 * radius * i), height / 2
+ (2 * radius * j), radius - sx, paint);
}
}
}
protected void onSizeChanged(int w, int h, int ow, int oh) {
width = w;
height = h;
}
}
In android development, a canvas is used for drawing. A view is used for interacting with the user. There isn't a direct mechanism for a canvas to receive user input. This must be handled through a view.
You'll want to add an onTouchListener to the View that is hosting your canvas and use that listener to store state information about touches from the user.

Categories

Resources