In my application, I have some images and when I tap on that image, it should be rotated by 90 degree. I am able to rotate image once but can't rotate on second tap. Can anyone help me to solve this problem? How can I rotate image on every touch event?
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.quartercircle1);
Matrix m = new Matrix();
imgvwQrtr1.setScaleType(ScaleType.MATRIX);
m.setRotate(90f, imgvwQrtr1.getDrawable().getBounds().width()/2, imgvwQrtr1.getDrawable().getBounds().height()/2);
bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
imgvwQrtr1.setImageBitmap(bm);
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new DragShadowBuilder(v);
v.startDrag(data, shadowBuilder, v, 0);
return true;
}
you need to create global variable like:
int degree = 0;
and in the code
.....
//shortest way
degree = degree + 90;
if(degree % 360 == 0) {
degree = 0;
}
//if(degree >= 270) {
//degree = 0;
//} else {
//degree+=90;
//}
m.setRotate(degree, imgvwQrtr1.getDrawable().getBounds().width()/2,
imgvwQrtr1.getDrawable().getBounds().height()/2);
....
try this
public static float getRotationAngle(final float x1, final float y1, final float x2, final float y2) {
final float CLOCK_WISE = 1.0f;
final float ANTI_CLOCK_WISE = -1.0f;
final float deltaX = Math.abs(x2 - x1);
final float deltaY = Math.abs(y2 - y1);
if (deltaX == 0) {
return 0.0f;
}
final float angle = (float) Math.toDegrees(Math.atan(deltaY / deltaX));
if (x1 <= x2 && y2 <= y1) {
return CLOCK_WISE * (90.0f - angle);
} else if (x2 <= x1 && y2 <= y1) {
return ANTI_CLOCK_WISE * (90.0f - angle);
} else if (x2 <= x1 && y1 <= y2) {
return ANTI_CLOCK_WISE * (90.0f + angle);
} else if (x1 <= x2 && y1 <= y2) {
return CLOCK_WISE * (90.0f + angle);
} else {
return 0.0f;
}
}
Related
When using scaling, MotionEvent coordinates can be corrected by dividing by the ScaleFactor.
Further, when scaling and paning, divide by scalefactor and subtract offset.
When dealing with zoom, however, it isn't as easy. Dividing does get the correct relative coordinates, but because pan is involved, 0 isn't 0. 0 can be -2000 in offset.
So how can I correct the TouchEvents to give the correct coordinates after zoom and pan?
Code:
Zoom:
class Scaler extends ScaleGestureDetector {
public Scaler(Context context, OnScaleGestureListener listener) {
super(context, listener);
}
#Override
public float getScaleFactor() {
return super.getScaleFactor();
}
}
class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener{
#Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
if(scaleFactor > 2) scaleFactor = 2;
else if(scaleFactor < 0.3f) scaleFactor = 0.3f;
scaleFactor = ((float)((int)(scaleFactor * 100))) / 100;//jitter-protection
scaleMatrix.setScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
return true;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {return true;}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
System.out.println("ScaleFactor: " + scaleFactor);
}
}
TouchEvent:
#Override
public boolean onTouchEvent(MotionEvent ev) {
int pointers = ev.getPointerCount();
if(pointers == 2 ) {
zoom = true;
s.onTouchEvent(ev);
}else if(pointers == 1 && zoom){
if(ev.getAction() == MotionEvent.ACTION_UP)
zoom = false;
return true;
}else {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
//scaled physical coordinates
x = ev.getX() /*/ mScaleFactorX*/;//unscaled
y = ev.getY() /*/ mScaleFactorY*/;
sx = ev.getX() / scaleFactor;//scaled
sy = ev.getY() / scaleFactor;
//////////////////////////////////////////
tox = toy = true;
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
if (tox && toy) {
x = ev.getX() /*/ mScaleFactorX*/;
y = ev.getY() /*/ mScaleFactorY*/;
sx = ev.getX() / scaleFactor;
sy = ev.getY() / scaleFactor;
System.out.println("XY: " + sx + "/" + sy);
Rect cursor = new Rect((int) x, (int) y, (int) x + 1, (int) y + 1);
Rect scaledCursor = new Rect((int)sx, (int)sy, (int)sx+1, (int)sy+1);
...
}
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
//This is where the pan happens.
float currX = ev.getX() / scaleFactor;
float currY = ev.getY() / scaleFactor;
float newOffsetX = (sx - currX),
newOffsetY = (sy - currY);
if (newOffsetY < Maths.convertDpToPixel(1, c) && newOffsetY > -Maths.convertDpToPixel(1, c))
newOffsetY = 0;
else tox = false;
if (newOffsetX < Maths.convertDpToPixel(1, c) && newOffsetX > -Maths.convertDpToPixel(1, c))
newOffsetX = 0;
else toy = false;
this.newOffsetX = newOffsetX;
this.newOffsetY = newOffsetY;
offsetX += newOffsetX;
offsetY += newOffsetY;
sx = ev.getX() / scaleFactor;
sy = ev.getY() / scaleFactor;
}
}
return true;
}
Implementation of the zooming matrix:
Matrix scaleMatrix = new Matrix();
public void render(Canvas c) {
super.draw(c);
if (c != null) {
backgroundRender(c);
c.setMatrix(scaleMatrix);
//Example rendering:
c.drawRect(0 - offsetX,0 - offsetY,10 - offsetX,10 - offsetY,paint);
c.setMatrix(null);//null the matrix to allow for unscaled rendering after this line. For UI objects.
}
}
What the issue is, is that when zooming 0 shifts but the coordinates of the objects does not. Meaning objects rendered at e.g. -2500, -2500 will appear to be rendered at over 0,0. Their coordinates are different from the TouchEvent. So how can I correct the touch events?
What I have tried:
This causes laggy zoom and the objects flying away. ev = MotionEvent in onTouchEvent. Doesn't correct the coordinates
Matrix invert = new Matrix(scaleMatrix);
invert.invert(invert);
ev.transform();
This doesn't work because the coordinates are wrong compared to objects. Objects with coordinates < 0 show over 0 meaning MotionEvents are wrong no matter what.
int sx = ev.getX() / scaleFactor;//same with y, but ev.getY()
Found a solution after doing a ton more research
Whenever getting the scaled coordinates, get the clipBounds of the canvas and add the top and left coordinates to X/Y coordinates:
sx = ev.getX() / scaleFactor + clip.left;
sy = ev.getY() / scaleFactor + clip.top ;
clip is a Rect defined as the clipBounds of the Canvas.
public void render(Canvas c) {
super.draw(c);
if (c != null) {
c.setMatrix(scaleMatrix);
clip = c.getClipBounds();
(...)
}
}
I'm working on a method to remove the transparent bounds of a Bitmap. The method looks like this:
private static final int STEP = 4;//Don't check all the pixel, only a sampling
private Bitmap clipTransparent(Bitmap image) {
int x1, x2, y1, y2;
final int width = image.getWidth();
final int height = image.getHeight();
for (x1 = 0; x1 < width - 1; x1 += STEP) {
if (checkColumn(image, x1)) {
break;
}
}
x1 = Math.max(0, x1 - STEP);
for (x2 = width - 1; x2 > x1; x2 -= STEP) {
if (checkColumn(image, x2)) {
break;
}
}
x2 = Math.min(width, x2 + STEP);
for (y1 = 0; y1 < height - 1; y1 += STEP) {
if (checkRow(x1, x2, image, y1)) {
break;
}
}
y1 = Math.max(0, y1 - STEP);
for (y2 = height - 1; y2 > 0; y2 -= STEP) {
if (checkRow(x1, x2, image, y2)) {
break;
}
}
y2 = Math.min(height, y2 + STEP);
try {
image = Bitmap.createBitmap(image, x1, y1, x2 - x1, y2 - y1);
} catch (Throwable t) {
t.printStackTrace();
}
return image;
}
private boolean checkColumn(Bitmap image, int x1) {
for (int y = 0; y < image.getHeight(); y += STEP) {
if (Color.alpha(image.getPixel(x1, y)) > 0) {
return true;
}
}
return false;
}
private boolean checkRow(int x1, int x2, Bitmap image, int y1) {
for (int x = x1; x < x2; x += STEP) {
if (Color.alpha(image.getPixel(x, y1)) > 0) {
return true;
}
}
return false;
}
It works great, but not as fast as I would like it to be.
The bottleneck of the code is to get the color of a pixel.
Now I read that value by calling image.getPixel(x, y), but looking at the source code of Android, getPixel checks the indexes and does other stuff that slows the code down (x>=0 && x<getWidth() && y>=0 && y<getHeight() && !isRecycled)...
Is there a way to access the pixel data without any index check or other useless stuff (useless in my case of course)?
PS: I already tryed to use getPixels() that returns a int array containing all the colors. But the image is big and allocating all the memory triggers a GC... the result was an even slower method
According to the docs you can pass an array to getPixels() which you can later reuse. This way no GC should ever happen.
This is the zoom the layout.
public class Zoom extends FrameLayout {
/**
* Zooming view listener interface.
*
* #author karooolek
*
*/
public interface ZoomViewListener {
void onZoomStarted(float zoom, float zoomx, float zoomy);
void onZooming(float zoom, float zoomx, float zoomy);
void onZoomEnded(float zoom, float zoomx, float zoomy);
}
// zooming
float zoom = 1.0f;
float maxZoom = 2.0f;
float smoothZoom = 1.0f;
float zoomX, zoomY;
float smoothZoomX, smoothZoomY;
private boolean scrolling; // NOPMD by karooolek on 29.06.11 11:45
// minimap variables
/* private boolean showMinimap = false;
private int miniMapColor = Color.BLACK;
private int miniMapHeight = 0;
private String miniMapCaption;
private float miniMapCaptionSize = 0;
private int miniMapCaptionColor = Color.WHITE;*/
private boolean showMinimap = false;
private int miniMapColor = Color.BLACK;
private int miniMapHeight = -1;
private String miniMapCaption;
private float miniMapCaptionSize = 10.0f;
private int miniMapCaptionColor = Color.WHITE;
// touching variables
private long lastTapTime;
private float touchStartX, touchStartY;
private float touchLastX, touchLastY;
private float startd;
private boolean pinching;
private float lastd;
private float lastdx1, lastdy1;
private float lastdx2, lastdy2;
// drawing
private final Matrix m = new Matrix();
private final Paint p = new Paint();
// listener
ZoomViewListener listener;
private Bitmap ch;
public Zoom(final Context context) {
super(context);
}
public float getZoom() {
return zoom;
}
public float getMaxZoom() {
return maxZoom;
}
public void setMaxZoom(final float maxZoom) {
if (maxZoom < 1.0f) {
return;
}
this.maxZoom = maxZoom;
}
public void setMiniMapEnabled(final boolean showMiniMap) {
this.showMinimap = showMiniMap;
}
public boolean isMiniMapEnabled() {
return showMinimap;
}
public void setMiniMapHeight(final int miniMapHeight) {
if (miniMapHeight < 0) {
return;
}
this.miniMapHeight = miniMapHeight;
}
public int getMiniMapHeight() {
return miniMapHeight;
}
public void setMiniMapColor(final int color) {
miniMapColor = color;
}
public int getMiniMapColor() {
return miniMapColor;
}
public String getMiniMapCaption() {
return miniMapCaption;
}
public void setMiniMapCaption(final String miniMapCaption) {
this.miniMapCaption = miniMapCaption;
}
public float getMiniMapCaptionSize() {
return miniMapCaptionSize;
}
public void setMiniMapCaptionSize(final float size) {
miniMapCaptionSize = size;
}
public int getMiniMapCaptionColor() {
return miniMapCaptionColor;
}
public void setMiniMapCaptionColor(final int color) {
miniMapCaptionColor = color;
}
public void zoomTo(final float zoom, final float x, final float y) {
this.zoom = Math.min(zoom, maxZoom);
zoomX = x;
zoomY = y;
smoothZoomTo(this.zoom, x, y);
}
public void smoothZoomTo(final float zoom, final float x, final float y) {
smoothZoom = clamp(1.0f, zoom, maxZoom);
smoothZoomX = x;
smoothZoomY = y;
if (listener != null) {
listener.onZoomStarted(smoothZoom, x, y);
}
}
public ZoomViewListener getListener() {
return listener;
}
public void setListner(final ZoomViewListener listener) {
this.listener = listener;
}
public float getZoomFocusX() {
return zoomX * zoom;
}
public float getZoomFocusY() {
return zoomY * zoom;
}
#Override
public boolean dispatchTouchEvent(final MotionEvent ev) {
// single touch
if (ev.getPointerCount() == 1) {
processSingleTouchEvent(ev);
}
// // double touch
if (ev.getPointerCount() == 2) {
processDoubleTouchEvent(ev);
}
// redraw
getRootView().invalidate();
invalidate();
return true;
}
private void processSingleTouchEvent(final MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
final float w = miniMapHeight * (float) getWidth() / getHeight();
final float h = miniMapHeight;
final boolean touchingMiniMap = x >= 10.0f && x <= 10.0f + w && y >= 10.0f && y <= 10.0f + h;
if (showMinimap && smoothZoom > 1.0f && touchingMiniMap) {
processSingleTouchOnMinimap(ev);
} else {
processSingleTouchOutsideMinimap(ev);
}
}
private void processSingleTouchOnMinimap(final MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
final float w = miniMapHeight * (float) getWidth() / getHeight();
final float h = miniMapHeight;
final float zx = (x - 10.0f) / w * getWidth();
final float zy = (y - 10.0f) / h * getHeight();
smoothZoomTo(smoothZoom, zx, zy);
}
private void processSingleTouchOutsideMinimap(final MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
float lx = x - touchStartX;
float ly = y - touchStartY;
final float l = (float) Math.hypot(lx, ly);
float dx = x - touchLastX;
float dy = y - touchLastY;
touchLastX = x;
touchLastY = y;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
touchStartX = x;
touchStartY = y;
touchLastX = x;
touchLastY = y;
dx = 0;
dy = 0;
lx = 0;
ly = 0;
scrolling = false;
break;
case MotionEvent.ACTION_MOVE:
if (scrolling || (smoothZoom > 1.0f && l > 30.0f)) {
if (!scrolling) {
scrolling = true;
ev.setAction(MotionEvent.ACTION_CANCEL);
super.dispatchTouchEvent(ev);
}
smoothZoomX -= dx / zoom;
smoothZoomY -= dy / zoom;
return;
}
break;
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_UP:
// tap
if (l < 30.0f) {
// check double tap
if (System.currentTimeMillis() - lastTapTime < 500) {
if (smoothZoom == 1.0f) {
smoothZoomTo(maxZoom, x, y);
} else {
smoothZoomTo(1.0f, getWidth() / 2.0f, getHeight() / 2.0f);
}
lastTapTime = 0;
ev.setAction(MotionEvent.ACTION_CANCEL);
super.dispatchTouchEvent(ev);
return;
}
lastTapTime = System.currentTimeMillis();
performClick();
}
break;
default:
break;
}
ev.setLocation(zoomX + (x - 0.5f * getWidth()) / zoom, zoomY + (y - 0.5f * getHeight()) / zoom);
ev.getX();
ev.getY();
super.dispatchTouchEvent(ev);
}
private void processDoubleTouchEvent(final MotionEvent ev) {
final float x1 = ev.getX(0);
final float dx1 = x1 - lastdx1;
lastdx1 = x1;
final float y1 = ev.getY(0);
final float dy1 = y1 - lastdy1;
lastdy1 = y1;
final float x2 = ev.getX(1);
final float dx2 = x2 - lastdx2;
lastdx2 = x2;
final float y2 = ev.getY(1);
final float dy2 = y2 - lastdy2;
lastdy2 = y2;
// pointers distance
final float d = (float) Math.hypot(x2 - x1, y2 - y1);
final float dd = d - lastd;
lastd = d;
final float ld = Math.abs(d - startd);
Math.atan2(y2 - y1, x2 - x1);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startd = d;
pinching = false;
break;
case MotionEvent.ACTION_MOVE:
if (pinching || ld > 30.0f) {
pinching = true;
final float dxk = 0.5f * (dx1 + dx2);
final float dyk = 0.5f * (dy1 + dy2);
smoothZoomTo(Math.max(1.0f, zoom * d / (d - dd)), zoomX - dxk / zoom, zoomY - dyk / zoom);
}
break;
case MotionEvent.ACTION_UP:
default:
pinching = false;
break;
}
ev.setAction(MotionEvent.ACTION_CANCEL);
super.dispatchTouchEvent(ev);
}
private float clamp(final float min, final float value, final float max) {
return Math.max(min, Math.min(value, max));
}
private float lerp(final float a, final float b, final float k) {
return a + (b - a) * k;
}
private float bias(final float a, final float b, final float k) {
return Math.abs(b - a) >= k ? a + k * Math.signum(b - a) : b;
}
#Override
protected void dispatchDraw(final Canvas canvas) {
// do zoom
zoom = lerp(bias(zoom, smoothZoom, 0.05f), smoothZoom, 0.2f);
smoothZoomX = clamp(0.5f * getWidth() / smoothZoom, smoothZoomX, getWidth() - 0.5f * getWidth() / smoothZoom);
smoothZoomY = clamp(0.5f * getHeight() / smoothZoom, smoothZoomY, getHeight() - 0.5f * getHeight() / smoothZoom);
zoomX = lerp(bias(zoomX, smoothZoomX, 0.1f), smoothZoomX, 0.35f);
zoomY = lerp(bias(zoomY, smoothZoomY, 0.1f), smoothZoomY, 0.35f);
if (zoom != smoothZoom && listener != null) {
listener.onZooming(zoom, zoomX, zoomY);
}
final boolean animating = Math.abs(zoom - smoothZoom) > 0.0000001f
|| Math.abs(zoomX - smoothZoomX) > 0.0000001f || Math.abs(zoomY - smoothZoomY) > 0.0000001f;
// nothing to draw
if (getChildCount() == 0) {
return;
}
// prepare matrix
m.setTranslate(0.5f * getWidth(), 0.5f * getHeight());
m.preScale(zoom, zoom);
m.preTranslate(-clamp(0.5f * getWidth() / zoom, zoomX, getWidth() - 0.5f * getWidth() / zoom),
-clamp(0.5f * getHeight() / zoom, zoomY, getHeight() - 0.5f * getHeight() / zoom));
// get view
final View v = getChildAt(0);
m.preTranslate(v.getLeft(), v.getTop());
// get drawing cache if available
if (animating && ch == null && isAnimationCacheEnabled()) {
v.setDrawingCacheEnabled(true);
ch = v.getDrawingCache();
}
// draw using cache while animating
if (animating && isAnimationCacheEnabled() && ch != null) {
p.setColor(0xffffffff);
canvas.drawBitmap(ch, m, p);
} else { // zoomed or cache unavailable
ch = null;
canvas.save();
canvas.concat(m);
v.draw(canvas);
canvas.restore();
}
// draw minimap
if (showMinimap) {
if (miniMapHeight < 0) {
miniMapHeight = getHeight() / 4;
}
canvas.translate(10.0f, 10.0f);
p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
final float w = miniMapHeight * (float) getWidth() / getHeight();
final float h = miniMapHeight;
canvas.drawRect(0.0f, 0.0f, w, h, p);
if (miniMapCaption != null && miniMapCaption.length() > 0) {
p.setTextSize(miniMapCaptionSize);
p.setColor(miniMapCaptionColor);
p.setAntiAlias(true);
canvas.drawText(miniMapCaption, 10.0f, 10.0f + miniMapCaptionSize, p);
p.setAntiAlias(false);
}
p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
final float dx = w * zoomX / getWidth();
final float dy = h * zoomY / getHeight();
canvas.drawRect(dx - 0.5f * w / zoom, dy - 0.5f * h / zoom, dx + 0.5f * w / zoom, dy + 0.5f * h / zoom, p);
canvas.translate(-10.0f, -10.0f);
}
// redraw
// if (animating) {
getRootView().invalidate();
invalidate();
// }
}
}
in my main activity i included the layout like this
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.grd_flr);
View v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.grd_flr, null, false);
v.setLayoutParams(new LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT, android.widget.LinearLayout.LayoutParams.FILL_PARENT));
zoom = new Zoom(this);
zoom.addView(v);
}
Now my layout is zooming on tap of the screen i want to pinch zoom this how can i do can some one help me with this. Thanks in advance buddy
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// Gesture starts
case MotionEvent.ACTION_DOWN:
firstFingerpreviousX = event.getX();
firstFingerpreviousY = event.getY();
touchState = TOUCH;
break;
// Second finger is now on the show
case MotionEvent.ACTION_POINTER_DOWN:
touchState = PINCH;
secondFingerpreviousX = event.getX(1);
secondFingerpreviousY = event.getY(1);
distance1 = makeDistance(firstFingerpreviousX,
firstFingerpreviousY, secondFingerpreviousX,
secondFingerpreviousY);
break;
// Fingers are moving
case MotionEvent.ACTION_MOVE:
if (touchState == PINCH) {
firstFingernewX = event.getX(0);
firstFingernewY = event.getX(0);
secondFingernewX = event.getX(1);
secondFingernewY = event.getY(1);
distance2 = makeDistance(firstFingernewX,
firstFingernewY,
secondFingernewX, secondFingernewY);
break;
}
break;
// Second finger gets tired
case MotionEvent.ACTION_POINTER_UP:
touchState = ENDOFPINCH;
// We calculate the distances between the fingers
// to know if there is zoom in or out
if (distance2 > distance1) {
System.out.println("Zoom in detected");
} else {
System.out.println("Zoom out detected");
}
break;
}
return true;
}
// Pythagorean Theorem distance maker method
public static float makeDistance(float x1, float y1, float x2, float y2) {
float delta1 = (x2 - x1) * (x2 - x1);
float delta2 = (y2 - y1) * (y2 - y1);
float distance = (float) Math.sqrt(delta1 + delta2);
return distance;
}
add this to your code and make sure your layout is linear and set its orientation.
I think you have to change your approach. Why don't you try these links out ?
http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-6-implementing-the-pinch-zoom-gesture/1847
http://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener.html
https://code.google.com/p/android-pinch/
I want to draw a line in AndEngine with the effect of a blade similar to Fruit Ninja or Veggie Samurai.
Can anyone help me? and give a sample code?
Maybe, I am late but hope this will help others.
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
final float touchX = pSceneTouchEvent.getX();
final float touchY = pSceneTouchEvent.getY();
if (pSceneTouchEvent.isActionDown()) {
initTrail(touchX, touchY);
swipeGestureSprite = addSwipeSprite(touchX, touchY);
} else if (pSceneTouchEvent.isActionMove()) {
moveTrail(pSceneTouchEvent.getX(), pSceneTouchEvent.getY(), 0);
if (swipeGestureSprite != null) {
swipeGestureSprite.setX(touchX);
swipeGestureSprite.setY(touchY);
}
} else if (pSceneTouchEvent.isActionUp()) {
mScene.detachChild(this.particleSystem);
if (swipeGestureSprite != null) {
this.mScene.detachChild(swipeGestureSprite);
swipeGestureSprite = null;
}
return true;
}
return false;
}
private void initTrail(float mX, float mY) {
this.particleEmitter = new PointParticleEmitter(mX, mY);
this.particleSystem = new SpriteParticleSystem(particleEmitter, 1000, 1000, 5000, this.mRibbon, this.getVertexBufferObjectManager());
particleSystem.addParticleInitializer(new BlendFunctionParticleInitializer<Sprite>(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE));
particleSystem.addParticleInitializer(new ExpireParticleInitializer<Sprite>(1));
particleSystem.addParticleModifier(new ScaleParticleModifier<Sprite>(0, 1, 1, 0f));
particleSystem.addParticleModifier(new AlphaParticleModifier<Sprite>(0, 1, 1, 0));
this.mScene.attachChild(particleSystem);
}
private void moveTrail(float trailX, float trailY, int count) {
if (particleEmitter == null) {
initTrail(trailX, trailY);
}
particleEmitter.setCenter(trailX, trailY);
}
I think you have to use point particle effect and use line drawing algorithm in that to create line between points. Line drawn using particle represent more reality and also the particle represent the dynamic way so you can destroy it. Further you can ask.
EDIT : For particle generation you can use this code
public void generateParticles(float pX, float pY) {
pointParticleEmtitter = new PointParticleEmitter(pX, pY);
particleSystem = new ParticleSystem(pointParticleEmtitter, maxRate,
minRate, maxParticles, mParticleTextureRegion.deepCopy());
particleSystem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
particleSystem.addParticleInitializer(new ColorInitializer(0.8f, 0.43f,
0.2f));
particleSystem.addParticleModifier(new AlphaModifier(1, 0, 0, 0.25f));
particleSystem.addParticleModifier(new ExpireModifier(0.25f));
gameObject.getScene().attachChild(particleSystem);
}
For Line algorithm you can use this one
public void drawLine() {
int x;
float y, m;
x = (int) previousX;
y = (int) previousY;
m = (currentY - previousY) / (currentX - previousX);
if (Math.round(previousX) == Math.round(currentX)) {
if (previousY < currentY) {
for (y = (int) previousY; y < currentY; ++y)
pointParticleEmtitter.setCenter(previousX, y);
} else {
for (y = (int) previousY; y > currentY; --y)
pointParticleEmtitter.setCenter(previousX, y);
}
} else {
if (previousX < currentX) {
for (x = (int) previousX; x < currentX; ++x) {
y = m * (x - previousX) + previousY;
pointParticleEmtitter.setCenter(x, y);
}
} else if (previousX > currentX) {
for (x = (int) previousX; x > currentX; --x) {
y = m * (x - currentX) + currentY;
pointParticleEmtitter.setCenter(x, y);
}
}
}
}
I have an imageView with multitouch roughly based on this tutorial. One of the commenters there put together a semi-dirty method of limiting the image drag to the boundaries of the image, so that the image edge cannot be dragged beyond its edge. This method sorta works, but not entirely. It only limits drag of two edges.
Does anyone know a less messy and actually functional method for limiting image drag?
This is a highly important concept for android app development that is not adequately addressed....
I was thinking of the following ideas:
1) setScaleType(scaleType.fitXY) when zoom = 1.0F (i.e. min zoom), and drag only enabled when zoom > 1.0f
2) when zoom > 1.0f, setScaleType(scaleType.MATRIX), then you determine image bounds and screen dimensions, and in some way that is too smart for me, using an if statement you only allow drag when the image edge is not on the screen. I don't know how to declare that, is the thing.
anyways, for completeness, here is the limit pan code from that link. This seems to be the most popular suggestion on stackoverflow, but I think we can do better:
// limit pan
matrix.getValues(matrixValues);
float currentY = matrixValues[Matrix.MTRANS_Y];
float currentX = matrixValues[Matrix.MTRANS_X];
float currentScale = matrixValues[Matrix.MSCALE_X];
float currentHeight = height * currentScale;
float currentWidth = width * currentScale;
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
float newX = currentX+dx;
float newY = currentY+dy;
RectF drawingRect = new RectF(newX, newY, newX+currentWidth, newY+currentHeight);
float diffUp = Math.min(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffDown = Math.max(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffLeft = Math.min(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
float diffRight = Math.max(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
if(diffUp > 0 ){
dy +=diffUp;
}
if(diffDown < 0){
dy +=diffDown;
}
if( diffLeft> 0){
dx += diffLeft;
}
if(diffRight < 0){
dx += diffRight;
}
matrix.postTranslate(dx, dy);
private void limitDrag(Matrix m, ImageView view) {
float[] values = new float[9];
m.getValues(values);
float transX = values[Matrix.MTRANS_X];
float transY = values[Matrix.MTRANS_Y];
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
Rect bounds = view.getDrawable().getBounds();
int viewWidth = getResources().getDisplayMetrics().widthPixels;
int viewHeight = getResources().getDisplayMetrics().heightPixels;
if(viewHeight<=480)
{
_y_up=0;
}
if(viewHeight>480&&viewHeight<980)
{
_y_up=140;
}
int width = bounds.right - bounds.left;
int height = bounds.bottom - bounds.top;
int __width=width;
int __height=height;
width = viewWidth / 2;
height = viewHeight / 2;
//height = 200 ;
float minX = (-width) ;//* scaleX;
float minY = (-height) ;//* scaleY;
if ((transX) > (viewWidth)) {
//_x_left
transX = viewWidth;
} else if (transX < minX) {
transX = minX;
}
if ((-transX) > (viewWidth)) {
// _x_right
transX = -(viewWidth);
} else if (-transX < minX) {
transX = -(minX+30);
}
if ((transY) > (viewHeight)) {
// _y_up
transY =( viewHeight);
} else if (transY < minY) {
transY = (minY+_y_up);
}
if ((-transY) > (viewHeight)) {
// _y_down
transY = -(viewHeight);
} else if (-transY < minY) {
transY = -(minY+170);
}
values[Matrix.MTRANS_X] = transX;
values[Matrix.MTRANS_Y] = transY;
m.setValues(values);
}
call this above your view.setImageMatrix(matrix) ;
I realize this is rather old now, but try this. imageWidth and imageHeight are unscaled values.
private void limitDrag(Matrix m, ImageView view, int imageWidth, int imageHeight) {
float[] values = new float[9];
m.getValues(values);
float[] orig = new float[] {0,0, imageWidth, imageHeight};
float[] trans = new float[4];
m.mapPoints(trans, orig);
float transLeft = trans[0];
float transTop = trans[1];
float transRight = trans[2];
float transBottom = trans[3];
float transWidth = transRight - transLeft;
float transHeight = transBottom - transTop;
float xOffset = 0;
if (transWidth > view.getWidth()) {
if (transLeft > 0) {
xOffset = -transLeft;
} else if (transRight < view.getWidth()) {
xOffset = view.getWidth() - transRight;
}
} else {
if (transLeft < 0) {
xOffset = -transLeft;
} else if (transRight > view.getWidth()) {
xOffset = -(transRight - view.getWidth());
}
}
float yOffset = 0;
if (transHeight > view.getHeight()) {
if (transTop > 0) {
yOffset = -transTop;
} else if (transBottom < view.getHeight()) {
yOffset = view.getHeight() - transBottom;
}
} else {
if (transTop < 0) {
yOffset = -transTop;
} else if (transBottom > view.getHeight()) {
yOffset = -(transBottom - view.getHeight());
}
}
float transX = values[Matrix.MTRANS_X];
float transY = values[Matrix.MTRANS_Y];
values[Matrix.MTRANS_X] = transX + xOffset;
values[Matrix.MTRANS_Y] = transY + yOffset;
m.setValues(values);
}