Ontouch multitouch zooming in Imageswitcher? - android

I am trying to enable pinch-zooming on an imageswitcher. I am stuck right now in how to declare the imageview in the ontouch method. I realize that the ImageView i = (Imageview) v is incorrect, I just dont know what to switch it to to declare the imageswitcher imageview in the ontouch...
Here is my java and xml. Thank you for your help!
public class ImageSwitch1 extends Activity implements
AdapterView.OnItemSelectedListener, ViewSwitcher.ViewFactory, OnTouchListener {
Matrix matrix = new Matrix();
Matrix eventMatrix = new Matrix();
final static int NONE = 0;
final static int DRAG = 1;
final static int ZOOM = 2;
int touchState = NONE;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.imageswitcher);
mSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
mSwitcher.setFactory(this);
mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_in));
mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_out));
Gallery g = (Gallery) findViewById(R.id.gallery);
g.setAdapter(new ImageAdapter(this));
g.setOnItemSelectedListener(this);
}
public void onItemSelected(AdapterView parent, View v, int position, long id) {
final TextView tv = (TextView)findViewById(R.id.SwitcherText);
mSwitcher.setImageResource(mImageIds[position]);
tv.setText(mText[position]);
}
public void onNothingSelected(AdapterView parent) {
}
public View makeView() {
ImageView i = new ImageView(this);
i.setScaleType(ScaleType.MATRIX);
i.setBackgroundColor(0xFF000000);
i.setScaleType(ImageView.ScaleType.FIT_CENTER);
i.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
i.setOnTouchListener(this);
return i;
}
final static float MIN_DIST = 50;
static float eventDistance = 0;
static float centerX =0, centerY = 0;
public boolean onTouch(View v, MotionEvent event) {
ImageView i = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
//primary touch event starts: remember touch down location
touchState = DRAG;
centerX = event.getX(0);
centerY = event.getY(0);
eventMatrix.set(matrix);
break;
case MotionEvent.ACTION_POINTER_DOWN:
//secondary touch event starts: remember distance and center
eventDistance = calcDistance(event);
calcMidpoint(centerX, centerY, event);
if (eventDistance > MIN_DIST) {
eventMatrix.set(matrix);
touchState = ZOOM;
}
break;
case MotionEvent.ACTION_MOVE:
if (touchState == DRAG) {
//single finger drag, translate accordingly
matrix.set(eventMatrix);
matrix.setTranslate(event.getX(0) - centerX,
event.getY(0) - centerY);
} else if (touchState == ZOOM) {
//multi-finger zoom, scale accordingly around center
float dist = calcDistance(event);
if (dist > MIN_DIST) {
matrix.set(eventMatrix);
float scale = dist / eventDistance;
matrix.postScale(scale, scale, centerX, centerY);
}
}
// Perform the transformation
i.setImageMatrix(matrix);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
touchState = NONE;
break;
}
return true;
}
private float calcDistance(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void calcMidpoint(float centerX, float centerY,
MotionEvent event) {
centerX = (event.getX(0) + event.getX(1))/2;
centerY = (event.getY(0) + event.getY(1))/2;
}
private ImageSwitcher mSwitcher;
public class ImageAdapter extends BaseAdapter {
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i = new ImageView(mContext);
i.setImageResource(mThumbIds[position]);
i.setAdjustViewBounds(true);
i.setLayoutParams(new Gallery.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
i.setBackgroundResource(R.drawable.picture_frame);
return i;
}
private Context mContext;
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Rellayout1"
android:layout_width="match_parent" android:layout_height="match_parent" android:isScrollContainer="true">
<RelativeLayout android:id="#+id/RelativeLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:isScrollContainer="true" android:layout_marginBottom="120dp">
<ImageSwitcher android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:id="#+id/switcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="60dp"
>
</ImageSwitcher>
<Gallery android:spacing="16dp" android:layout_height="80dp" android:id="#+id/gallery" android:unselectedAlpha="0.5" android:background="#55000000" android:gravity="center_vertical" android:layout_width="match_parent" android:minHeight="20px"></Gallery>
</RelativeLayout>
<ScrollView
android:id="#+id/ScrollViewSwitcher"
android:layout_width="fill_parent" android:scrollbarAlwaysDrawVerticalTrack="true" android:isScrollContainer="true" android:layout_alignParentBottom="true" android:layout_height="120dp">
<TextView android:scrollbarAlwaysDrawVerticalTrack="true" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="#+id/SwitcherText" android:textSize="18dp"></TextView>
</ScrollView>
</RelativeLayout>

I solved this problem changing this line:
ImageView i = (ImageView) v;
By
ImageView i = mSwitcher;
But can't use matrix, imageSwitcher don't use matrix or i do not know how it's done.
I hope help you with this.

Related

Erase with draggable Object

I am trying to create an Android application that will erase parts of an image. I am trying to accomplish so by using a dragable object (image of eraser).
I have already implemented the features of dragging the eraser image to anywhere in the app and erasing a background image upon dragging your finger. Now I want to bridge the two features so that the background image erases only when the eraser image is being dragged. How can I accomplish this task?
Below is what I have done so far:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewGroup rootLayout;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private ImageView w1;
private boolean clicked1 = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyCustomView myCustomView = new MyCustomView(MainActivity.this);
w1 = (ImageView) findViewById(R.id.wand1);
pl = (RelativeLayout) findViewById(R.id.coordAct);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.coordAct);
rootLayout.addView(myCustomView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
myCustomView.setLayoutParams(layoutParams1w2);
w1.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
private final class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1){
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
// detach the child from parent
rootLayout.removeView(w1);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
w1.setLayoutParams(layoutParams1);
clicked1 = true;
}
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
break;
}
rootLayout.invalidate();
return true;
}
}
MyCustomView.java
public class MyCustomView extends View {
private Bitmap sourceBitmap;
private Canvas sourceCanvas = new Canvas();
private Paint destPaint = new Paint();
private Path destPath = new Path();
public MyCustomView(Context context) {
super(context);
//converting drawable resource file into bitmap
Bitmap rawBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.armissueserase);
//converting bitmap into mutable bitmap
sourceBitmap = Bitmap.createBitmap(rawBitmap.getWidth(), rawBitmap.getHeight(), Bitmap.Config.ARGB_8888);
sourceCanvas.setBitmap(sourceBitmap);
sourceCanvas.drawBitmap(rawBitmap, 0, 0, null);
destPaint.setAlpha(0);
destPaint.setAntiAlias(true);
destPaint.setStyle(Paint.Style.STROKE);
destPaint.setStrokeJoin(Paint.Join.ROUND);
destPaint.setStrokeCap(Paint.Cap.ROUND);
//change this value as per your need
destPaint.setStrokeWidth(50);
destPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
}
#Override
protected void onDraw(Canvas canvas) {
sourceCanvas.drawPath(destPath, destPaint);
canvas.drawBitmap(sourceBitmap, 0, 0, null);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float xPos = event.getX();
float yPos = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
destPath.moveTo(xPos, yPos);
break;
case MotionEvent.ACTION_MOVE:
destPath.lineTo(xPos, yPos);
break;
default:
return false;
}
invalidate();
return true;
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/coordAct"
android:background="#drawable/background"
tools:context="com.erasewithtouch.MainActivity">
<RelativeLayout
android:id="#+id/parLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3"
android:background="#0000ff">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="28dp"
android:background="#BA9DF7"
android:gravity="bottom"
android:orientation="vertical">
<HorizontalScrollView
android:id="#+id/backgd"
android:layout_width="match_parent"
android:layout_height="100dp"
android:weightSum="1">
<LinearLayout
android:id="#+id/parentLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="5">
<ImageView
android:id="#+id/wand1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#drawable/wand1" />
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</RelativeLayout>
Any help is greatly appreciated. Thanks!

Draw on canvas wherever view is dragged

I am trying to create a simple paint app using canvas. The end product would be for the user to select a tool of choice (pen, marker, eraser, etc) and draw or erase accordingly anywhere the tool is dragged on the canvas.
As of now, I only have a pen and I am trying to draw a line wherever the pen is dragged in the canvas. However, I am finding this task challenging. I can drag the pen and I can draw lines, but I can't draw while I am dragging the pen. I am reaching out to the SO community to bridge these two features.
Below is what I have:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewGroup rootLayout;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private ImageView w1;
private boolean clicked1 = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CanvasView canvasView = new CanvasView(MainActivity.this);
w1 = (ImageView) findViewById(R.id.wand1);
pl = (RelativeLayout) findViewById(R.id.coordAct);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.coordAct);
rootLayout.addView(canvasView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
canvasView.setLayoutParams(layoutParams1w2);
w1.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
public class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1){
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
// detach the child from parent
rootLayout.removeView(w1);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
w1.setLayoutParams(layoutParams1);
clicked1 = true;
}
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
break;
}
rootLayout.invalidate();
return true;
}
}
CanvasView.java
public class CanvasView extends View{
Context context;
int width, height;
Bitmap bitmap;
Path path;
Canvas canvas;
Paint paint;
float mX, mY;
static final float TOLERANCE=4;
public CanvasView(Context context) {
super(context);
this.context=context;
path=new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(50);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w,h,oldw,oldh);
bitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
canvas=new Canvas(bitmap);
}
public void startTouch(float x, float y) {
path.moveTo(x, y);
mX = x;
mY = y;
}
public void moveTouch(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if(dx>=TOLERANCE || dy>= TOLERANCE) {
path.quadTo(mX, mY, (x+mX)/2, (y+mY)/2);
mX=x;
mY=y;
}
}
//To clear canvas
public void clearCanvas() {
path.reset();
invalidate();
}
public void upTouch() {
path.lineTo(mX,mY);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawPath(path,paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
startTouch(x,y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(x,y);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
default:
return false;
}
invalidate();
return true;
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/coordAct"
tools:context="com.simplepaintapp.MainActivity">
<RelativeLayout
android:id="#+id/parLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3"
android:background="#0000ff">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="28dp"
android:background="#BA9DF7"
android:gravity="bottom"
android:orientation="vertical">
<HorizontalScrollView
android:id="#+id/backgd"
android:layout_width="match_parent"
android:layout_height="100dp"
android:weightSum="1">
<LinearLayout
android:id="#+id/parentLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="5">
<ImageView
android:id="#+id/wand1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#drawable/pen" />
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</RelativeLayout>
Current bug after implementing the dispatchTouchEvent() method inside onTouch()
An update to MainActivity and CanvasView is required. See the new source code below:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewGroup rootLayout;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private ImageView w1;
private boolean clicked1 = false;
CanvasView canvasView;
public static int X;
public static int Y;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
canvasView = new CanvasView(MainActivity.this);
w1 = (ImageView) findViewById(R.id.wand1);
pl = (RelativeLayout) findViewById(R.id.coordAct);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.coordAct);
rootLayout.addView(canvasView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
canvasView.setLayoutParams(layoutParams1w2);
w1.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
public class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1){
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
// detach the child from parent
rootLayout.removeView(w1);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
w1.setLayoutParams(layoutParams1);
clicked1 = true;
}
X = (int) event.getRawX();
Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
canvasView.dispatchTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
canvasView.dispatchTouchEvent(event);
break;
}
rootLayout.invalidate();
return true;
}
}
CanvasView.java:
public class CanvasView extends View{
Context context;
int width, height;
Bitmap bitmap;
Path path;
public Canvas canvas;
Paint paint;
float mX, mY;
static final float TOLERANCE=4;
public static float x;
public static float y;
public CanvasView(Context context) {
super(context);
this.context=context;
path=new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(50);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w,h,oldw,oldh);
bitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
canvas=new Canvas(bitmap);
}
public void startTouch(float x, float y) {
path.moveTo(x, y);
mX = x;
mY = y;
}
public void moveTouch(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if(dx>=TOLERANCE || dy>= TOLERANCE) {
path.quadTo(mX, mY, (x+mX)/2, (y+mY)/2);
mX=x;
mY=y;
}
}
//To clear canvas
public void clearCanvas() {
path.reset();
invalidate();
}
public void upTouch() {
path.lineTo(mX,mY);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawPath(path,paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
startTouch(MainActivity.X,MainActivity.Y-380);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(MainActivity.X,MainActivity.Y-380);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
default:
return false;
}
invalidate();
return true;
}

Android getWidth, getHeight, getLeft, getRight not correct after setScaleX() , setScaleY()

I try to implement the zoom in/out by spread/pinch gesture and the drag and drop functions on a Relative Layout.
This is the code of my OnPinchListener to handle the zoom effect.
The mainView is the RelativeLayout defined in the layout xml file.
I implement the touch listener in the fakeview which should be in front of all view. The touch event will change the mainview according to the code.
I want to ask if it is possible to get the actual left, top, width and height after the scale? It always return 0,0 for left and top, and the original width and height after zoom.
Thanks very much!
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linear_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/zoomable_relative_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
>
<ImageView
android:id="#+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/background" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/relative_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:orientation="vertical" >
</RelativeLayout>
</RelativeLayout>
public class MainActivity extends Activity {
//ZoomableRelativeLayout mainView = null;
RelativeLayout mainView = null;
RelativeLayout rl = null;
public static final String TAG = "ZoomText."
+ MainActivity.class.getSimpleName();
private int offset_x;
private int offset_y;
private boolean dragMutex = false;
RelativeLayout fakeView = null;
float width = 0, height = 0;
private OnTouchListener listener = new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
// Log.e(TAG, event + "");
// Log.e(TAG, "Pointer Count = "+event.getPointerCount());
Log.e(TAG,
event.getX() + "," + event.getY() + "|" + mainView.getX()
+ "(" + mainView.getWidth() + "),"
+ mainView.getY() + "(" + mainView.getHeight()
+ ")");
if (event.getX() >= mainView.getLeft()
&& event.getX() <= mainView.getLeft() + mainView.getWidth()
&& event.getY() >= mainView.getTop()
&& event.getY() <=mainView.getTop() + mainView.getHeight())
if (event.getPointerCount() > 1) {
return scaleGestureDetector.onTouchEvent(event);
} else {
return llListener.onTouch(arg0, event);
}
return false;
}
};
private ScaleGestureDetector scaleGestureDetector;
private OnTouchListener llListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
// Log.d(TAG, event + ",LL");
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
offset_x = (int) event.getX();
offset_y = (int) event.getY();
// Log.e(TAG, offset_x + "," + offset_y);
dragMutex = true;
return true;
case MotionEvent.ACTION_MOVE:
// Log.e(TAG, "Finger down");
int x = (int) event.getX() - offset_x;
int y = (int) event.getY() - offset_y;
Log.e(TAG, event.getX() + "," + event.getY());
float _x = mainView.getX();
float _y = mainView.getY();
mainView.setX(_x + x);
mainView.setY(_y + y);
offset_x = (int) event.getX();
offset_y = (int) event.getY();
return true;
case MotionEvent.ACTION_UP:
dragMutex = false;
return true;
}
return false;
}
};
private OnDragListener dragListener = new View.OnDragListener() {
#Override
public boolean onDrag(View arg0, DragEvent arg1) {
Log.e(TAG, "DRAG Listener = " + arg1);
return false;
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainView = (RelativeLayout) findViewById(R.id.zoomable_relative_layout);
// mainView.setOnTouchListener(new OnPinchListener());
// mainView.setOnTouchListener(listener);
scaleGestureDetector = new ScaleGestureDetector(this,
new OnPinchListener());
rl = (RelativeLayout) findViewById(R.id.linear_layout);
mainView.setOnDragListener(dragListener);
// mainView.setOnTouchListener(llListener);
fakeView = (RelativeLayout) findViewById(R.id.relative_layout);
fakeView.setOnTouchListener(listener);
}
class OnPinchListener extends SimpleOnScaleGestureListener {
float startingSpan;
float endSpan;
float startFocusX;
float startFocusY;
public boolean onScaleBegin(ScaleGestureDetector detector) {
startingSpan = detector.getCurrentSpan();
startFocusX = detector.getFocusX();
startFocusY = detector.getFocusY();
return true;
}
public boolean onScale(ScaleGestureDetector detector) {
// mainView.scale(detector.getCurrentSpan() / startingSpan,
// startFocusX, startFocusY);
// if(width==0)
// width = mainView.getWidth();
// if(height==0)
// height = mainView.getHeight();
mainView.setPivotX(startFocusX);
mainView.setPivotY(startFocusY);
mainView.setScaleX(detector.getCurrentSpan() / startingSpan);
mainView.setScaleY(detector.getCurrentSpan() / startingSpan);
// LayoutParams para = mainView.getLayoutParams();
// width*=detector.getCurrentSpan() / startingSpan;
// height*=detector.getCurrentSpan() / startingSpan;
// para.width = (int)width;
// para.height = (int)height;
// mainView.setLayoutParams(para);
return true;
}
public void onScaleEnd(ScaleGestureDetector detector) {
//mainView.restore();
mainView.invalidate();
Log.e(TAG, mainView.getLeft()+","+mainView.getRight());
}
}
}
you need to get the transformation matrix and use that to transform your original points.
so something like this (after you do the scaling):
Matrix m = view.getMatrix(); //gives you the transform matrix
m.mapPoints(newPoints, oldPoints); //transform the original points.
This is how I solved it in my case (getViewRect should be called after view was laid out, for example through view.post(Runnable), so view.getWidth()/getHeight() returns actual values):
public static Rect getViewRect(View view) {
Rect outRect = new Rect();
outRect.right = (int)(view.getWidth() * getScalelX(view));
outRect.bottom = (int)(view.getHeight() * getScalelY(view));
int[] location = new int[2];
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
return outRect;
}
public static float getScalelX(View view) {
float scaleX = view.getScaleX();
view = getParent(view);
while (view != null) {
scaleX *= view.getScaleX();
view = getParent(view);
}
return scaleX;
}
public static float getScalelY(View view) {
float scaleX = view.getScaleY();
view = getParent(view);
while (view != null) {
scaleX *= view.getScaleY();
view = getParent(view);
}
return scaleX;
}
public static ViewGroup getParent(View view) {
if (view == null) {
return null;
}
ViewParent parent = view.getParent();
if (parent instanceof View) {
return (ViewGroup) parent;
}
return null;
}
however it just turned out that android 3.1 (probably 3.0 also) doesn't take in account scale factor while dealing with getLocationOnScreen method.
I'm gonna to manually scale the rect before returning it from my getViewRect(View) function in case of android 3.1 api like this:
public static void scaleRect(Rect rect, float scaleX, float scaleY, float pivotX, float pivotY) {
rect.left = (int) ((rect.left - pivotX) * scaleX + pivotX);
rect.right = (int) ((rect.right - pivotX) * scaleX + pivotX);
rect.top = (int) ((rect.top - pivotY) * scaleY + pivotY);
rect.bottom = (int) ((rect.bottom - pivotY) * scaleY + pivotY);
}
However one should know a pivot coordinates for every view in the hierarchy from the current view to the root and corresponding zoom levels to handle this transformation correctly.
If someone has any straightforward solution it will be appreciated
EDIT:
This is how I modified the getViewRect(View) method so it works on 3.1 also:
public static Rect getViewRect(View view) {
Rect outRect = new Rect();
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR2){
outRect.right = (int)(view.getWidth() * getScalelX(view));
outRect.bottom = (int)(view.getHeight() * getScalelY(view));
int[] location = new int[2];
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
} else {
outRect.right = view.getWidth();
outRect.bottom = view.getHeight();
int[] location = new int[2];
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
View parent = view;
while(parent != null){
parent.getLocationOnScreen(location);
scaleRect(outRect, parent.getScaleX(), parent.getScaleY(), parent.getPivotX() + location[0], parent.getPivotY() + location[1]);
parent = getParent(parent);
}
}
return outRect;
}
I think if- clause could be removed so that the second branch (else) should work for all versions. However I prefer to use straightforward solution (the first branch of the if) so that the second is just a workaround :)

Android: Dragging Multiple Views

I have a problem on dragging multiple Views in android. I have a two circle created using a Canvas. The problem is that I can only drag one Circle and I can't drag the other Circle. It seems that the first Circle covers the entire screen, and when I try to drag the 2nd Circle still the 1st Circle is moving.
Here is my code.
MainActivity.java
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}}
DragSource.java
public class DragSource extends View {
private Paint viewPaint;
private float startX;
private float startY;
private float touchOffsetX;
private float touchOffsetY;
private float x = 30;
private float y = 30;
private static final float RADIUS = 30;
//needed for finding drop target:
//the constructor:
public DragSource(Context context, AttributeSet attrs) {
super(context, attrs);
viewPaint = new Paint();
viewPaint.setColor(Color.RED);
viewPaint.setAntiAlias(true);
}
public boolean onTouchEvent(MotionEvent mEvent) {
int eventAction = mEvent.getAction();
switch(eventAction)
{
case MotionEvent.ACTION_DOWN:
startX = x;
startY = y;
touchOffsetX = mEvent.getX();
touchOffsetY = mEvent.getY();
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_CANCEL:
x = startX + mEvent.getX() - touchOffsetX;
y = startY + mEvent.getY() - touchOffsetY;
break;
}
return true;
}
public void draw(Canvas c) {
int w = c.getWidth();
int h = c.getHeight();
c.drawCircle(x, y, RADIUS, viewPaint);
this.invalidate();
}}
my activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" ><com.example.trialsdrag.DragSource
android:layout_width="wrap_content"
android:layout_height="wrap_content"/><com.example.trialsdrag.DragSource
android:layout_width="wrap_content"
android:layout_height="wrap_content"/></RelativeLayout>
What's happening is your views' size is the actually the whole screen size, and in onTouchEvent, your simply changing the drawing on them (moving the circle).
What you need to do is set android:layout_height and android:layout_width for the DragSource in your main_activity.xml, and then change the layout margins dynamically in onTouchEvent using:
RelativeLayout.LayoutParams params = (LayoutParams) getLayoutParams();
params.setMargins(x+params.leftMargin, y+params.topMargin, 0, 0);
setLayoutParams(params);

Zoom on all ImageViews which are in different layout

I have two layouts and ImageViews inside it. First layout Imageview will behave as a background and other layouts image view as different objects. Now I want to zoom imageViews of both but objects should only be selected and not the background. I mean background should just be used for zoom.
This is my xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView android:id="#+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/hh_gmw01"
android:scaleType="matrix"
android:tag="0"
/>
<RelativeLayout
android:id="#+id/LParentLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/imageView100"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="388px"
android:layout_marginTop="269px"
android:contentDescription="Image1"
android:src="#drawable/h1"
android:tag="a" />
<ImageView
android:id="#+id/imageView200"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="147px"
android:layout_marginTop="99px"
android:contentDescription="Image1"
android:src="#drawable/h2"
android:tag="b" />
</RelativeLayout>
</RelativeLayout>
and this is my code for the ImageVIew matrix but this gets applied only on one imageview
public class GamePlayActivity extends Activity implements OnTouchListener{
private static final String TAG = "Touch";
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = new Matrix();
float mx,my;
private static final int WIDTH = 0;
private static final int HEIGHT = 1;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
int mwidth;
int mheight;
static int ObjectsFound;
//ArrayList<ImageView> hiddenObjects;
Toast msg;
int click_Locn_x,click_Locn_y;
int objectCollected=0;
View level=null;
ShowPopUpWindow popup;
static View[]_hiddenObjects;
HiddenObject _ho;
ImageView im,img1,img2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameplay);
LinearLayout layouts = (LinearLayout) findViewById(R.id.GameplayRootLayout);
LayoutParams lp = layouts.getLayoutParams();
// ViewGroup where n number of view is going to added
ViewGroup layout= (ViewGroup) findViewById(R.id.GamePlayScreen);
// inflating the layout depending on the level
level = View.inflate(this, R.layout.main, null);
// level.setOnTouchListener(this);
Log.d("Print", "Search ID : " + R.id.test);
ImageView imf= (ImageView) level.findViewById(R.id.test);
imf.setOnTouchListener(this);
RelativeLayout rl=(RelativeLayout) level.findViewById(R.id.LParentLayout);
img1= (ImageView) rl.findViewById(R.id.imageView100);
img1.setOnTouchListener(this);
img2= (ImageView) rl.findViewById(R.id.imageView200);
img2.setOnTouchListener(this);
// adding level bg for the respective selected level
layout.addView(level);
}
#Override
public boolean onTouch(View objectClicked, MotionEvent event) {
// TODO Auto-generated method stub
//findViewById(objectClicked.getId());
Log.d("Check", " Image Tag " + objectClicked.getTag().toString());
if ((Integer.parseInt(objectClicked.getTag().toString())==0))
{
ImageView img = (ImageView) objectClicked;
float curX, curY;
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
mx = (int)event.getX();
my = (int)event.getY();
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
savedMatrix.set(matrix);
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
curX = event.getX();
curY = event.getY();
matrix.postTranslate(-(mx - curX), -(my - curY));
mx = curX;
my = curY;
break;
}
else if (mode == ZOOM) {
float newDist = spacing(event);
float arr1[]=new float[9];
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
savedMatrix2.set(matrix);
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.setScale(scale, scale,mid.x,mid.y);
matrix.getValues(arr1);
// keeping tab on Zooming ...Allowed only to 3.0 level
if((arr1[Matrix.MSCALE_X]) >2.0){
matrix.set(savedMatrix2);
// Log.d("Print", "Value Left" + img.getLeft()+ " Value Right "+ img.getRight());
}
}
}
break;
}
float arr[]=new float[9];
matrix.getValues(arr);
Log.d("Print", arr[0] + "," + arr[1] + "," + arr[2] + "," + arr[3] + "," + arr[4] + "," + arr[5] + "," + arr[6] + "," + arr[7] + "," + arr[8]);
img.setImageMatrix(matrix);
img1.setImageMatrix(savedMatrix2);
img2.setImageMatrix(savedMatrix2);
fixing(img);
return true;
}
else
{
ImageView img2 = (ImageView) objectClicked;
img2.setVisibility(View.INVISIBLE);
msg = Toast.makeText(GamePlayActivity.this, "Object Found",
100);
msg.setGravity(Gravity.CENTER, msg.getXOffset() / 2,
msg.getYOffset() / 2);
msg.show();
Log.d("Check", " I am Imageview Object FOund layout check");
return true;
}
}
/** Calculate the mid point of the first two fingers */
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private float spacing(MotionEvent event) {
if(event.getPointerCount() == 2){
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
return 0;
}
private void fixing(View v) {
// TODO Auto-generated method stub
if (SmallerThanIdentity(matrix)) {
resetView(v);
}
}
public static boolean SmallerThanIdentity(android.graphics.Matrix m) {
float[] values = new float[9];
m.getValues(values);
return ((values[0] < 1.0) || (values[4] < 1.0) || (values[8] < 1.0));
}
public void resetView(View v) {
ImageView view = (ImageView) v;
matrix = new Matrix();
view.setScaleType(ImageView.ScaleType.MATRIX);
view.setImageMatrix(matrix);
}
}
Thanks for the help ...
I have found answer by my own after some research. To apply the zooming or scaling to the children views, I need make custom Viewgroup. For more details check out this
Extending RelativeLayout, and overriding dispatchDraw() to create a zoomable ViewGroup

Categories

Resources