Pinch to zoom IN or OUT imageview added dynamically to Layout - android

I working on an application where in the ImageView is created dynamically and added to the layout, after the user selects image from the gallery of the device.
With the code what I have written, am able to move and rotate the ImageView. But, I also want to implement Pinch zoom in/out for the ImageView.
The bug which exists in the code is when after the ImageView is added to the layout, the ImageView when taken to the extreme right shrinks so that what I want to do, but that should happen on the pinch.
EDIT: After debugging my code I found that i want to increase the size of the ImageView by increasing the width and height.
When i changed the following line :
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
To:
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
240,
200);
I got what i wanted. So can I do this inside the class DragImageView on pinch.
Here's the code for the custom Imageview.
public class DragImageView extends ImageView {
private float mLastTouchX;
private float mLastTouchY;
private float mDeltaX;
private float mDeltaY;
private Bitmap bmpImg;
Context mContext;
public DragImageView(Context context, Bitmap bmpImg) {
super(context);
this.bmpImg = bmpImg;
this.mContext = context;
init();
}
public DragImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// TODO Auto-generated method stub
Bitmap resized = Bitmap.createScaledBitmap(bmpImg, 180, 200, true);
Bitmap conv_bm = getRoundedShape(resized); //function to get the imageview as rounded shape
setImageBitmap(conv_bm);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View v, MotionEvent event) {
PopupMenu popup = new PopupMenu(mContext, v);
// Inflating the Popup using xml file
popup.getMenuInflater().inflate(R.menu.popup_menu,
popup.getMenu());
popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
int itemId = item.getItemId();
if (itemId == R.id.delete_DragImgView) {
ViewGroup parentView = (ViewGroup) v.getParent();
parentView.removeView(v);
} else if (itemId == R.id.rotate_DraagImgView) {
final RotateAnimation rotateAnim = new RotateAnimation(
0.0f, 90, RotateAnimation.RELATIVE_TO_SELF,
0.5f, RotateAnimation.RELATIVE_TO_SELF,
0.5f);
rotateAnim.setDuration(0);
rotateAnim.setFillAfter(true);
v.startAnimation(rotateAnim);
}
return false;
}
});
final int action = event.getAction();
mLastTouchX = event.getRawX();
mLastTouchY = event.getRawY();
switch (action) {
case MotionEvent.ACTION_DOWN: {
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) getLayoutParams();
mDeltaX = mLastTouchX - lParams.leftMargin;
mDeltaY = mLastTouchY - lParams.topMargin;
popup.show();
break;
}
case MotionEvent.ACTION_MOVE: {
mLastTouchX = event.getRawX();
mLastTouchY = event.getRawY();
final RelativeLayout.LayoutParams params = (LayoutParams) getLayoutParams();
params.leftMargin = (int) (mLastTouchX - mDeltaX);
params.topMargin = (int) (mLastTouchY - mDeltaY);
setLayoutParams(params);
break;
}
}
invalidate();
return true;
}
});
}
The imageview is added as follows from the activity.
final DragImageView dynamicImgView = new DragImageView(
getApplicationContext(), yourSelectedImage);
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
dynamicImgView.setLayoutParams(params);
relativeLayout.addView(dynamicImgView);
I know the pinch to zoom is possible but after trying lots of codes and Help from stackover flow, thought of finally putting it on so.
Please help me. Thanks in advance.

Solved my problem.. I simply increased the height & width of the imageview. Code
} else if (itemId == R.id.zoom_in) {
if (height > 100) {
height = height - ZoomCounter;
width = width - ZoomCounter;
final RelativeLayout.LayoutParams params = (LayoutParams) getLayoutParams();
getLayoutParams().height = height;
getLayoutParams().width = width;
setLayoutParams(params);
invalidate();
}
} else if (itemId == R.id.zoom_out) {
if (height < 600) {
height = height + ZoomCounter;
width = width + ZoomCounter;
final RelativeLayout.LayoutParams params = (LayoutParams) getLayoutParams();
getLayoutParams().height = height;
getLayoutParams().width = width;
setLayoutParams(params);
invalidate();
}
}

Related

Android: animate a view with setY()

I want to animate a simple view, say for example a simple textview. I want to use translate animate the view.
Now what my requirement is, I want to make a method, say for example slide(View v, float position). Which will take the view to animate and position till where it should be animated. And I will call that method from desired place in my code.
To accomplish this, I have tried something. I have made MyTranslateAnimation class as follow.
public class MyTranslateAnimation extends Animation {
private View mView;
private final float position;
public MyTranslateAnimation(View view, float position){
mView = view;
this.position = position;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mView.setY(position);
mView.requestLayout();
}
}
Then I made a textview in MainActivity.java and set onTouchListener and then created this method slide() to do the task I described above.
Below is the code:
onCreate():
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_root = (ViewGroup)findViewById(R.id.root);
_view = new TextView(this);
_view.setText("TextView!!!!!!!!");
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(150, 50);
layoutParams.leftMargin = 50;
layoutParams.topMargin = 50;
layoutParams.bottomMargin = -250;
layoutParams.rightMargin = -250;
_view.setLayoutParams(layoutParams);
_view.setOnTouchListener(this);
_root.addView(_view);
}
slide():
private void slide(View view, float position){
Animation animation = new MyTranslateAnimation(view, position);
animation.setInterpolator(new DecelerateInterpolator());
animation.setDuration(200);
animation.start();
}
And as below I used slide() method:
public boolean onTouch(View view, MotionEvent event) {
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_UP:
slide(view, 100);
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
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;
}
_root.invalidate();
return true;
}
Also I don't want to use nineoldandroid library for this.
Any help regarding this is highly appreciated.
slide():
public void slide(float position){
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(overflow.get(), "translationY", position);
objectAnimator.setInterpolator(new DecelerateInterpolator());
objectAnimator.setDuration(200);
objectAnimator.start();
}

Moving only bitmap inside an ImageView

I have an ImageView with a black background set in xml, and in code I'm placing bitmap with imageView.setImageBitmap(bitmap);
You can select between ScaleType.CENTER_CROP and ScaleType.CENTER_INSIDE.
If ScaleType.CENTER_INSIDE is selected, bitmap is smaller than the ImageView, and the black background is visible.
I would like to move only bitmap across the screen. I tried with this code, but it moves whole ImageView, not only bitmap inside ImageView.
imageView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int eid = event.getAction();
switch (eid) {
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
int x = (int) event.getRawX();
int y = (int) event.getRawY();
layoutParams.leftMargin = x - 50;
layoutParams.topMargin = y - 100;
imageView.setLayoutParams(layoutParams);
break;
default:
break;
}
return true;
}
});
Is there a way to only move bitmap that's inside ImageView?
Also I would like to increase and decrease width and height of a bitmap and maintain the bitmap's aspect ratio.
I tried with this, but it's not working:
buttonIncrease.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
layoutParams.width = (int) ((layoutParams.width + 10) * scale + 0.5f);
layoutParams.height = (int) ((layoutParams.height + 10) * scale + 0.5f);
}
});

How to redraw a layout using canvas and matrix in android?

I want to move and scale the view on the right while dragging it to left side.I tried to set the layout parameters of this view on touch.It moved and scaled the view.But rendering is not correct when moving our finger fastly to both left and right sides.
This view on the right side is a custom layout extends LinearLayout having a ListView as child.And the left side is also another layout and integrated both layouts into a Framelayout(similar to slidingmenu).
Is there any way to render the layout (move and scale) the view without updating LayoutParams?
Is it possible to update the layout using canvas and matrix?
Here is the code for custom layout for view on the right side(the small view).
public class SlidingLayout extends LinearLayout {
private static String LOG_TAG = "SlidingLayout";
private boolean isTranformed = false;
private PanGestureListener gestureListener;
private GestureDetector gestureDetector;
private boolean isAnimating = false;
private boolean isScrolling = false;
private DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
private Matrix matrix = new Matrix();
private float posX = 0;
private float posY = 0;
public CustomSlidingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
gestureListener = new PanGestureListener();
gestureDetector = new GestureDetector(context, gestureListener);
matrix.setTranslate(0, 0);
matrix.setScale(1.0f, 1.0f);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.save();
/*canvas.drawColor(Color.RED);
canvas.translate(posX, posY);
super.onDraw(canvas);*/
/*canvas.restore();
matrix.reset();
matrix = canvas.getMatrix();*/
/*if (isTranformed) {
matrix.postTranslate(posX, posY);
canvas.setMatrix(matrix);
}
super.onDraw(canvas);*/
}
private void makeViewSmall() {
if (!isAnimating) {
isAnimating = true;
Rect rect = new Rect();
getLocalVisibleRect(rect);
ResizeMoveAnimation anim = new ResizeMoveAnimation(this,
(int) (displayMetrics.widthPixels * 0.8), displayMetrics.heightPixels / 4,
displayMetrics.widthPixels * 2, rect.bottom - displayMetrics.heightPixels
/ 4);
anim.setAnimationListener(animationListener);
anim.setDuration(1000);
anim.setInterpolator(new BounceInterpolator());
startAnimation(anim);
}
}
public void makeViewOriginal() {
if(isTranformed){
if (!isAnimating) {
isAnimating = true;
ResizeMoveAnimation anim = new ResizeMoveAnimation(this, 0, 0,
displayMetrics.widthPixels, displayMetrics.heightPixels);
anim.setAnimationListener(animationListener);
anim.setInterpolator(new BounceInterpolator());
anim.setDuration(1000);
startAnimation(anim);
}
}else{
makeViewSmall();
}
}
private AnimationListener animationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) CustomSlidingLayout.this .getLayoutParams();
if (isTranformed) {
isTranformed = false;
params.leftMargin = 0;
params.topMargin = 0;
params.width = displayMetrics.widthPixels;
params.height = displayMetrics.heightPixels;
requestLayout();
} else {
isTranformed = true;
}
isAnimating = false;
}
};
class PanGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
if (isTranformed) {
makeViewOriginal();
return true;
}
return false;
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isTranformed) {
return true;
} else {
return false;
}
}
private int _xDelta = 0;
private int _yDelta = 0;
#Override
public boolean onTouchEvent(MotionEvent event) {
//gestureDetector.onTouchEvent(event);
if (isTranformed) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
this.requestLayout();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this .getLayoutParams();
if (layoutParams.leftMargin == 0 && layoutParams.topMargin == 0) {
//this.requestLayout();
isTranformed = false;
isScrolling = false;
break;
}
isScrolling = true;
int xDiff = layoutParams.leftMargin - (X - _xDelta);
layoutParams.leftMargin = X - _xDelta;
int scaleFactor = layoutParams.leftMargin > 0 ? layoutParams.leftMargin : 1;
layoutParams.topMargin = layoutParams.topMargin - ((layoutParams.topMargin / scaleFactor) * xDiff);
if (layoutParams.leftMargin < 0) {
layoutParams.leftMargin = 0;
}
if (layoutParams.topMargin < 0) {
layoutParams.topMargin = 0;
}
layoutParams.width = (displayMetrics.widthPixels - layoutParams.leftMargin);
layoutParams.height = (displayMetrics.heightPixels - (layoutParams.topMargin * 2));
this.requestLayout();
/*final float dx = X - _xDelta;
final float dy = Y - _yDelta;
posX += dx;
posY += dy;
//matrix.postScale(scaleFactor, scaleFactor,0.0f,0.5f);
Bitmap bitmap = Bitmap.createBitmap((int)(displayMetrics.widthPixels - posX), (int)(displayMetrics.heightPixels - posY), Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
matrix.postTranslate(posX, posY);
canvas.setMatrix(matrix);
this.draw(canvas);
_xDelta = X;
_yDelta = Y;
invalidate();*/
break;
case MotionEvent.ACTION_UP:
isScrolling = false;
break;
case MotionEvent.ACTION_DOWN:
FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) this
.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = X - lParams.topMargin;
posX = 0;
posY = 0;
break;
}
return true;
}
return true;
}
}
You can call invalidate() in onTouch() to execute the code in onDraw() to redraw the view.
invalidate() will force a view to draw.

Android: Is this not how drawing a canvas works?

Am I misunderstanding how translating and scaling a canvas should work? I created a custom view that I can drag and zoom, but it's inside the bounds I set. I thought translating the canvas would redraw the bounds? I want to be able to drag and zoom the image on the whole screen, not in a viewport! I assumed translating the canvas would adjust the viewport.
Am I thinking about this the wrong way?
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
mIcon.draw(canvas);
canvas.restore();
}
This is how I created the view. So basically it is stuck in this 250 x 250 box. I need the view to actually drag around.. I get the feeling I'm doing something stupid but I can't produce the behavior I'm looking for.
MultiTouchImageView view = new MultiTouchImageView(this);
view.setLayoutParams(new RelativeLayout.LayoutParams(250, 250));
You can set margins to move view in layout. I've created test project to show the idea, it looks like that:
public class DragView extends View {
private float mLastTouchX;
private float mLastTouchY;
private float mDeltaX;
private float mDeltaY;
public DragView(Context context) {
super(context);
init();
}
public DragView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
mLastTouchX = event.getRawX();
mLastTouchY = event.getRawY();
switch (action) {
case MotionEvent.ACTION_DOWN: {
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) getLayoutParams();
mDeltaX = mLastTouchX - lParams.leftMargin;
mDeltaY = mLastTouchY - lParams.topMargin;
break;
}
case MotionEvent.ACTION_MOVE: {
mLastTouchX = event.getRawX();
mLastTouchY = event.getRawY();
final RelativeLayout.LayoutParams params = (LayoutParams) getLayoutParams();
params.leftMargin = (int) (mLastTouchX - mDeltaX);
params.topMargin = (int) (mLastTouchY - mDeltaY);
setLayoutParams(params);
break;
}
}
return true;
}
});
}
}

How to Bring layout back to its original position in android after drag

I have working on a project. where I need to drag the layout, I manage to move (drag) the layout but when I release the touch it is not coming at its original position.
Please anyone tell me what should I do in MotionEvent.ACTION_UP so that I can get layout back to its original position.
Following is my code.
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
public class HomeActivity extends Activity implements OnTouchListener {
RelativeLayout _view;
RelativeLayout _view1;
// TextView _view;
ViewGroup _root;
private int _xDelta;
RelativeLayout.LayoutParams lParams;
RelativeLayout.LayoutParams mainlParams;
private int _yDelta;
// private int X1, Y1, width;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_root = (ViewGroup) findViewById(R.id.root);
_view = (RelativeLayout) findViewById(R.id.relativeLayout);
_view.setOnTouchListener(this);
lParams = (RelativeLayout.LayoutParams) _view.getLayoutParams();
mainlParams = (RelativeLayout.LayoutParams) _view.getLayoutParams();
// _root.addView(_view1);
}
public boolean onTouch(View view, MotionEvent event) {
int X = (int) event.getRawX();
int Y = (int) event.getRawY();
RelativeLayout.LayoutParams layoutParams;
lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
Log.e("", "inside ACTION_DOWN");
lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
Log.e("", "inside ACTION_UP");
if ((X - _xDelta) < -150) {
_root.removeView(_view);
} else {
view.setLayoutParams(mainlParams);
}
break;
case MotionEvent.ACTION_MOVE:
Log.e("", "inside ACTION_MOVE");
layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
break;
}
_root.invalidate();
return true;
}
}
NEW EDIT
here I show you a very simple (and by the way not very clean code) how to do what you want to do. I have a relativeLayout with a green LinearLayout inside:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/relative_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<LinearLayout
android:id="#+id/moving_layout"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#00ff00"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</LinearLayout>
</RelativeLayout>
Then in Your MainActivity, set the topLayout, where the view You want to move is inside, to onTouchListener. Set originalX and originalY at ACTION_DOWN and moveX and moveY at ACTION_MOVE. When user release fingers, go back to original position:
public class MainActivity extends Activity implements OnTouchListener {
private LinearLayout mLinearLayout;
private RelativeLayout mRelativeLayout;
private RelativeLayout.LayoutParams params;
private float originalX = 0;
private float originalY = 0;
private float moveX = 0;
private float moveY = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLinearLayout = (LinearLayout) findViewById(R.id.moving_layout);
mRelativeLayout = (RelativeLayout) findViewById(R.id.relative_layout);
mRelativeLayout.setOnTouchListener(this);
int width = getMetrics(100);
int height = getMetrics(100);
params = new RelativeLayout.LayoutParams(width, height);
}
/**
* converts dp to px
*
* #param dp
* #return
*/
private int getMetrics(int dp) {
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
return (int) ((dp * displayMetrics.density) + 0.5);
}
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case (MotionEvent.ACTION_DOWN):
originalX = event.getX(); //set X start position
originalY = event.getY();//set Y start position
moveX = event.getX();//first move x
moveY = event.getY();//first move y
break;
case (MotionEvent.ACTION_MOVE):
moveX = event.getX();//set move x
moveY = event.getY();//set move y
//set LayoutParams to mLinearLayout
params.leftMargin = (int) moveX;
params.topMargin = (int) moveY;
mLinearLayout.setLayoutParams(params);
break;
case (MotionEvent.ACTION_UP):
//set mLinearLayout back to original position
params.leftMargin = (int) originalX;
params.topMargin = (int) originalY;
mLinearLayout.setLayoutParams(params);
break;
}
return true;
}
}
DonĀ“t wonder about the getMetrics() Method, this is because setting same width and height to mLinearLayout like defined in xml. In xml, you set this values as dp, at LayoutParams, it is px. But this is not relevant for Your question.
What I am doin here is, set original X and Y at ACTION_DOWN and get back to this at ACTION_UP. So, everytime the user press down again, these values will be "renewed", the layout will going back to the last points of ACTION_DOWN if fingers will release. This should give You an idea how to handle your problem.

Categories

Resources