I am trying to make simple Sticker View for Pictures Editing Project, but i am facing problem when I switch the sticker between the Views using:-
sticker.select(view);
when I select View for the first time its working good, but for the second time its change its position but the height and width still the width and height of the first View like the picture:-
full code:-
```class Sticker extends LinearLayout {
public Sticker(Context ctx) {
super(ctx);
LayoutInflater thisLL = getLayoutInflater();
View thisVV = thisLL.inflate(R.layout.sticker, null);
this.removeAllViews();
((LinearLayout) this).addView(thisVV);
this.setLayoutParams(new FrameLayout.LayoutParams((int) (ViewGroup.LayoutParams.WRAP_CONTENT),(int) (ViewGroup.LayoutParams.WRAP_CONTENT)));
selector = (LinearLayout)
thisVV.findViewById(R.id.selector);
/*rightP = (FrameLayout)
thisVV.findViewById(R.id.rightP);
bottomP = (FrameLayout)
thisVV.findViewById(R.id.bottomP);
pr = (LinearLayout)
thisVV.findViewById(R.id.pr);
pb = (LinearLayout)
thisVV.findViewById(R.id.pb);
*/
rotate = (ImageView)
thisVV.findViewById(R.id.rotate);
scale = (ImageView)
thisVV.findViewById(R.id.scale);
final Sticker stick = this;
rotate.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
int ev = event.getAction();
switch (ev) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
double r = (90 + (Math.atan2(event.getRawY() - (stick.getY()+(stick.getMeasuredHeight()/2)),event.getRawX() - (stick.getX()+(stick.getMeasuredWidth()/2))) * 180 / Math.PI));
if (-360 > r) {
r+=360;
}
r+=45;//to get smooth rotate
stick.setRotation((float)r);
selected.setRotation((float)r);
break;
} return true;
}
});
selector.setBackground(new GradientDrawable() { public GradientDrawable getIns(int a, int b, int c, int d) { this.setCornerRadius(a); this.setStroke(b, c); this.setColor(d); return this; } }.getIns((int)0, (int)2, 0xFF607D8B, Color.TRANSPARENT));
scale.setOnTouchListener(new OnTouchListener() {
PointF DivPT = new PointF(0,0);
PointF StartPT = new PointF();
private float initialTouchX;
float initialTouchY;
private int initialX;
private int initialY;
private int initialX2;
private int initialY2;
private int ex;
private int ey;
private int dw;
private int dh;
private float xx;
private float yy;
#Override public boolean onTouch(View _view, MotionEvent event) {
int n=event.getAction();
if(n==MotionEvent.ACTION_UP) drag=false;
if(n==MotionEvent.ACTION_DOWN){
drag=true;
xx=selected.getX();
yy=selected.getY();
//dw=stick.selected.getMeasuredWidth()-frame.getMeasuredWidth();
//dh=stick.selected.getMeasuredHeight()-frame.getMeasuredHeight()-rotate.getMeasuredHeight();
}
if (n != 0) {
if (n != 2) {
return true;
}
float cx = this.initialX + (float)(event.getRawX() - this.initialTouchX);
float cy = this.initialY + (float)(event.getRawY() - this.initialTouchY);
float cx2 = this.initialX + (float)(event.getRawX() - this.initialTouchX);
float cy2 = this.initialY + (float)(event.getRawY() - this.initialTouchY);
selected.setLayoutParams(new FrameLayout.LayoutParams((int) (cx),(int) (cy)));
select(selected);
//selector.setLayoutParams(new LinearLayout.LayoutParams((int) (cx2),(int) (cy2)));
}
this.initialX = selected.getMeasuredWidth();
this.initialY = selected.getMeasuredHeight();
this.initialX2= selector.getMeasuredWidth();
this.initialY2= selector.getMeasuredHeight();
this.initialTouchX = event.getRawX();
this.initialTouchY = event.getRawY();
return true;
}});
}
LinearLayout selector;
FrameLayout rightP;
FrameLayout bottomP;
ImageView rotate;
ImageView scale;
LinearLayout pr;
LinearLayout pb;
public View selected;
public View previous;
boolean drag = false;
public void select(View v){
this.selected=v;
try {
if (!(v.equals(previous))){
try {
((ViewGroup)this.getParent()).removeView(this);
} catch (Exception exp65676) {
}
((ViewGroup) ((ViewGroup)v.getParent())).addView(this);
}
this.selector.getLayoutParams().width = ((int)(v.getMeasuredWidth()));
this.selector.getLayoutParams().height = ((int)(v.getMeasuredHeight()));
/**/
/*
this.selector.setLayoutParams(new LinearLayout.LayoutParams((int) (0),(int) (0)));
*/
previous=v;
((View)(v.getParent())).invalidate();
float top=((LinearLayout.LayoutParams)(this.selector.getLayoutParams())).topMargin;
float left =((LinearLayout.LayoutParams)(this.selector.getLayoutParams())).leftMargin;
setX(v.getX()-rotate.getMeasuredWidth());
setY(v.getY()-top);
setRotation((float)(v.getRotation()));
} catch (Exception e) {
SketchwareUtil.showMessage(getApplicationContext(), (e.toString()));
}
}
private PointF DownPT = new PointF();
private PointF StartPT = new PointF();
private float SX;
private float SY;
private float rotation;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
//setRotation(0);
//selected.setRotation(0);
PointF mv = new PointF(event.getX() - DownPT.x, event.getY() - DownPT.y);
setX((int)(StartPT.x+mv.x));
setY((int)(StartPT.y+mv.y));
selected.setX((int)((StartPT.x+mv.x)));
selected.setY((int)(StartPT.y+mv.y+SY));
StartPT = new PointF(getX(),getY());
select(selected);
break;
case MotionEvent.ACTION_DOWN :
DownPT.x = event.getX();
DownPT.y = event.getY();
rotation=getRotation();
//setRotation(0);
//setAlpha(0);
//drag=true;
StartPT = new PointF(getX(),getY());
//SX=getX()-selected.getX();
SX=rotate.getMeasuredWidth();
SY=getY()-selected.getY();
break;
case MotionEvent.ACTION_UP :
setRotation(rotation);
setAlpha(1);
selected.setRotation(rotation);
select(selected);
drag=false;
break;
default : break;
} return true;
}
}```
xml file:
``` <LinearLayout
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:orientation="vertical">
<LinearLayout
android:id="#+id/linear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right|bottom"
android:orientation="horizontal">
<ImageView
android:id="#+id/rotate"
android:focusable="false"
android:layout_width="20dp"
android:layout_height="match_parent"
android:src="#drawable/rotate"
android:scaleType="fitStart" />
<LinearLayout
android:id="#+id/selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" />
<ImageView
android:id="#+id/scale"
android:focusable="false"
android:layout_width="20dp"
android:layout_height="match_parent"
android:src="#drawable/scale"
android:scaleType="fitEnd"
android:layout_gravity="bottom" />
</LinearLayout>
</LinearLayout>```
}
LinearLayout selector;
FrameLayout rightP;
FrameLayout bottomP;
ImageView rotate;
ImageView scale;
LinearLayout pr;
LinearLayout pb;
public View selected;
public View previous;
boolean drag = false;
public void select(View v){
this.selected=v;
try {
if (!(v.equals(previous))){
try {
((ViewGroup)this.getParent()).removeView(this);
} catch (Exception exp65676) {
}
((ViewGroup) ((ViewGroup)v.getParent())).addView(this);
}
this.selector.getLayoutParams().width = ((int)(v.getMeasuredWidth()));
this.selector.getLayoutParams().height = ((int)(v.getMeasuredHeight()));
/**/
/*
this.selector.setLayoutParams(new LinearLayout.LayoutParams((int) (0),(int) (0)));
*/
previous=v;
((View)(v.getParent())).invalidate();
float top=((LinearLayout.LayoutParams)(this.selector.getLayoutParams())).topMargin;
float left =((LinearLayout.LayoutParams)(this.selector.getLayoutParams())).leftMargin;
setX(v.getX()-rotate.getMeasuredWidth());
setY(v.getY()-top);
setRotation((float)(v.getRotation()));
} catch (Exception e) {
SketchwareUtil.showMessage(getApplicationContext(), (e.toString()));
}
}
private PointF DownPT = new PointF();
private PointF StartPT = new PointF();
private float SX;
private float SY;
private float rotation;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
//setRotation(0);
//selected.setRotation(0);
PointF mv = new PointF(event.getX() - DownPT.x, event.getY() - DownPT.y);
setX((int)(StartPT.x+mv.x));
setY((int)(StartPT.y+mv.y));
selected.setX((int)((StartPT.x+mv.x)));
selected.setY((int)(StartPT.y+mv.y+SY));
StartPT = new PointF(getX(),getY());
select(selected);
break;
case MotionEvent.ACTION_DOWN :
DownPT.x = event.getX();
DownPT.y = event.getY();
rotation=getRotation();
//setRotation(0);
//setAlpha(0);
//drag=true;
StartPT = new PointF(getX(),getY());
//SX=getX()-selected.getX();
SX=rotate.getMeasuredWidth();
SY=getY()-selected.getY();
break;
case MotionEvent.ACTION_UP :
setRotation(rotation);
setAlpha(1);
selected.setRotation(rotation);
select(selected);
drag=false;
break;
default : break;
} return true;
}
}
Related
I am a newbie in android development. I am trying to create an image gallery . While implementing viewpager, I put imageview outside viewpager but because of that I am not able to make zoom and pinch and viewpager work at same time. How can I put imageview inside viewpager ?
FullImageActivity.java:
public class FullImageActivity extends AppCompatActivity {
ImageView images;
int position;
int folderPosition;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_full_image);
Intent i = getIntent();
PhotoView photoView = (PhotoView) findViewById(R.id.photo_view);
photoView.setVisibility(View.GONE);
// Selected image id
position = i.getExtras().getInt("id");
folderPosition = i.getExtras().getInt("folderPosition");
Bundle extras = getIntent().getExtras();
String value = extras.getString("abc");
Glide.with(FullImageActivity.this)
.load(value)
.skipMemoryCache(false)
.into(photoView);
ViewPager mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setAdapter(new TouchImageAdapter(this,al_images, folderPosition));
mViewPager.setCurrentItem(position);
}
}
activity_full_image.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/jazzy_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.chrisbanes.photoview.PhotoView
android:id="#+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="centerCrop"/>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
TouchImageAdapter.java
class TouchImageAdapter extends PagerAdapter {
Context context;
String filename;
ArrayList<Model_images> al_menu = new ArrayList<>();
int position,int_position;
public TouchImageAdapter(Context context,ArrayList<Model_images> al_menu, int position){
this.al_menu = al_menu;
this.context = context;
this.int_position = position;
}
#Override
public int getCount() {
return al_menu.get(int_position).getAl_imagepath().size();
}
#Override
public View instantiateItem(ViewGroup container, int position) {
ImageView img = new ImageView(container.getContext());
ViewGroup.LayoutParams lp= new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
img.setLayoutParams(lp);
img.setImageDrawable(getImageFromSdCard(filename,position));
container.addView(img, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
return img;
}
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
public Drawable getImageFromSdCard(String imageName,int position) {
Drawable d = null;
try {
String path = al_menu.get(int_position).getAl_imagepath().get(position)
+ "/";
Bitmap bitmap = BitmapFactory.decodeFile(path);
d = new BitmapDrawable(context.getResources(),bitmap);
} catch (IllegalArgumentException e) {
// TODO: handle exception
}
return d;
}
}
Use this custom TouchImageView instead of imageview
public class TouchImageView extends ImageView {
private void stopInterceptEvent()
{
getParent().requestDisallowInterceptTouchEvent(true);
}
private void startInterceptEvent()
{
getParent().requestDisallowInterceptTouchEvent(false);
}
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
stopInterceptEvent();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < height) {
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
} else {
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
if(deltaX == 0)
startInterceptEvent();
else
stopInterceptEvent();
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
startInterceptEvent();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
}
Also change your activity_full_xml like this
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TouchImageView
android:id="#+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="centerCrop"/>
</android.support.v4.view.ViewPager>
I have seen a lots of code here which is helpful to zoom your textview but none of them work with my text because it is within scrollview. How can I get rid of this problem?
import android.app.Activity;
import android.os.Bundle;
import android.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
public class Introduce extends Activity implements OnTouchListener{
final static float STEP = 200;
TextView mtxtRatio1,mtxtRatio2,mtxtRatio3,mtxtRatio4;
float mRatio = 1.0f;
int mBaseDist;
float mBaseRatio;
float fontsize = 13;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.introduce);
mtxtRatio1 = (TextView)findViewById(R.id.intro1);
mtxtRatio1.setTextSize(mRatio+13);
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getPointerCount() == 2) {
int action = event.getAction();
int pureaction = action & MotionEvent.ACTION_MASK;
if (pureaction == MotionEvent.ACTION_POINTER_DOWN) {
mBaseDist = getDistance(event);
mBaseRatio = mRatio;
} else {
float delta = (getDistance(event) - mBaseDist) / STEP;
float multi = (float)Math.pow(2, delta);
mRatio = Math.min(1024.0f, Math.max(0.1f, mBaseRatio * multi));
mtxtRatio1.setTextSize(mRatio+13);
}
}
return true;
}
int getDistance(MotionEvent event) {
int dx = (int)(event.getX(0) - event.getX(1));
int dy = (int)(event.getY(0) - event.getY(1));
return (int)(Math.sqrt(dx * dx + dy * dy));
}
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return false;
}
}
Following is the way for implementing Pinch Zoom in TextView with/without ScrollView
MainActivity.java
public class MainActivity extends AppCompatActivity{
final static float STEP = 200;
float mRatio = 1.0f;
int mBaseDist;
float mBaseRatio;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
textViewData = (TextView).findViewById(R.id.tvContributeData);
textViewData.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
if (event.getPointerCount() == 2) {
int action = event.getAction();
int pureaction = action & MotionEvent.ACTION_MASK;
if (pureaction == MotionEvent.ACTION_POINTER_DOWN) {
mBaseDist = getDistance(event);
mBaseRatio = mRatio;
} else {
float delta = (getDistance(event) - mBaseDist) / STEP;
float multi = (float) Math.pow(2, delta);
mRatio = Math.min(1024.0f, Math.max(0.1f, mBaseRatio * multi));
textViewData.setTextSize(mRatio + 13);
}
}
return true;
});
int getDistance(MotionEvent event) {
int dx = (int) (event.getX(0) - event.getX(1));
int dy = (int) (event.getY(0) - event.getY(1));
return (int) (Math.sqrt(dx * dx + dy * dy));
}
}
}
Use Polidea's zoomview, it works in a scrollview and has pinch zoom and double tap to zoom, one thing thought, I ended up disabling the pinch zoom and just using the double tap
https://github.com/Polidea/android-zoom-view
Put your TextView andany other Views you are using into a LinearLayout that lives on a ZoomView which lives on the ScrollView, e.g.:
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.polidea.ZoomView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/myLinearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</com.polidea.ZoomView>
</ScrollView>
Hopefully this will help others. This answer is from here and here.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
tv.setText(getString(R.string.hello_world));
scaleGestureDetector = new ScaleGestureDetector(this, new simpleOnScaleGestureListener());
tv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getPointerCount() == 1){
//stuff for 1 pointer
}else{ //when 2 pointers are present
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(true);
scaleGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
// Disallow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(true);
scaleGestureDetector.onTouchEvent(event);
break;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
}
return true;
}
});
}
The answer from here has the problem when text is resized even fingers are static (two fingers on the screen). What I did is add a check so that the textSize do not make any changes instantly.
private float safe;
public class simpleOnScaleGestureListener extends SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
// TODO Auto-generated method stub
float size = tv.getTextSize();
Log.d("TextSizeStart", String.valueOf(size));
//float factor = detector.getScaleFactor();
float factor = Math.max(0.5f, Math.min(detector.getScaleFactor(), 2f));
Log.d("Factor", String.valueOf(factor));
float product = size*factor;
Log.d("TextSize", String.valueOf(product));
safe = Math.abs(product - size);
if(product <= 100 && product >= 20 && safe < 3){
//tv.setText("factor= " +factor + "\n" + "product = \n" + size + " * " + factor + " \n= " + product +"\n" + getString(R.string.hello_world));
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, product);
}
size = tv.getTextSize();
Log.d("TextSizeEnd", String.valueOf(size));
return true;
}
}
You can play around with safe < 3 to your desired changes value.
I'm using this solution.
Crédits for Zoom Algorithm in this vídeo
Use a TextView without ScrollView, just use android:scrollbars="vertical"
<TextView
android:id="#+id/activity_content_text_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_weight="1"
android:gravity="fill"
android:textSize="8pt"
android:scrollbars="vertical"
/>
Java:
public class MainActivity extends Activity implements View.OnTouchListener {
private TextView textContent = null;
private final static float move = 200;
private float ratio = 1.0f;
private int baseDist;
private float baseRatio;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.teste_layout);
textContent = findViewById(R.id.activity_content_text_content);
textContent.setText("Lorem ipsum dolor sit amet......");
textContent.setMovementMethod(new ScrollingMovementMethod());
textContent.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return onTouchEvent(event);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getPointerCount() == 2){
int action = event.getAction();
int mainAction = action&MotionEvent.ACTION_MASK;
if(mainAction == MotionEvent .ACTION_POINTER_DOWN){
baseDist = getDisTance(event);
baseRatio = ratio;
} else {
float scale = (getDisTance(event)-baseDist)/move;
float factor = (float)Math.pow(2, scale);
ratio = Math.min(1024.0f, Math.max(0.1f, baseRatio*factor));
textContent.setTextSize(ratio+15);
}
} else {
return false;
}
return true;
}
private int getDisTance(MotionEvent event) {
int dx = (int) (event.getX(0)-event.getX(1));
int dy = (int) (event.getY(0)-event.getY(1));
return (int) (Math.sqrt(dx*dx+dy*dy));
}
}
I have two seperate (x, y) points that I want to use to apply rotation to a view.
The first point is fixed, and I find the values of it fairly easily (for example 200,200). My second point is where a TOUCH is present, so I grab the RawX and RawY points easily as well. I feed these two points into this method that I found on another stack overflow question.
private float findRotation(int firstPointX, int firstPointY, int secondPointX, int secondPointY) {
double delta_x = (firstPointX - secondPointX);
double delta_y = (firstPointY - secondPointY);
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
and I use the return of that to set the rotation of a View. Like so myView.setRotation(...). The result ends up being a crazy spinning view while I move the cursor/finger on the screen. Any ideas?
The two points I'm grabbing seem to be correct, leaving me guessing that maybe the findRotation method is incorrect.
My activity:
public class MainActivity extends Activity {
ImageView imageView;
ImageView dragHandle;
RelativeLayout layout;
int rememberAngle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.imageView1);
dragHandle = (ImageView) findViewById(R.id.imageView2);
layout = (RelativeLayout) findViewById(R.id.relativeLayout2);
resize(dragHandle);
}
public void resize(ImageView resizeButton) {
resizeButton.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
int[] locationOfLayout = new int[2];
int[] locationOfDrag = new int[2];
layout.getLocationOnScreen(locationOfLayout);
dragHandle.getLocationOnScreen(locationOfDrag);
int firstPointX = locationOfLayout[0];
int firstPointY = locationOfLayout[1];
int secondPointX = dragHandle.getWidth() / 2 + locationOfDrag[0];
int secondPointY = dragHandle.getHeight() / 2 + locationOfDrag[1];
rememberAngle = (int) findRotation(firstPointX, firstPointY, secondPointX, secondPointY) + layout.getRotation();
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
int[] locationOfLayout = new int[2];
int[] locationOfDrag = new int[2];
layout.getLocationOnScreen(locationOfLayout);
dragHandle.getLocationOnScreen(locationOfDrag);
int centerXOnLayout = layout.getWidth() / 2 + locationOfLayout[0];
int centerYOnLayout = layout.getHeight() / 2 + locationOfLayout[1];
int centerXOnDrag = dragHandle.getWidth() / 2 + locationOfDrag[0];
int centerYOnDrag = dragHandle.getHeight() / 2 + locationOfDrag[1];
layout.setRotation(findRotation(centerXOnLayout, centerYOnLayout, centerXOnDrag, centerYOnDrag) - rememberAngle);
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
}
return true;
}
});
}
private float findRotation(int firstPointX, int firstPointY, int secondPointX, int secondPointY) {
double delta_x = (secondPointX - firstPointX);
double delta_y = (secondPointY - firstPointY);
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
}
My 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" >
<RelativeLayout
android:id="#+id/relativeLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/ic_launcher" />
<ImageView
android:id="#+id/imageView2"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_below="#+id/imageView1"
android:layout_toRightOf="#+id/imageView1"
android:src="#drawable/meanicons" />
</RelativeLayout>
</RelativeLayout>
public void resize(ImageView resizeButton) {
resizeButton.setOnTouchListener(new View.OnTouchListener() {
float startAngle;
float zeroAngle;
int firstPointX;
int firstPointY;
public boolean onTouch(View v, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
int[] locationOfLayout = new int[2];
int[] locationOfDrag = new int[2];
layout.getLocationOnScreen(locationOfLayout);
dragHandle.getLocationOnScreen(locationOfDrag);
firstPointX = locationOfLayout[0];
firstPointY = locationOfLayout[1];
int secondPointX = motionEvent.getRawX();
int secondPointY = motionEvent.getRawY();
zeroAngle = findRotation(firstPointX, firstPointY, secondPointX, secondPointY) // remember "zero" angle
startAngle = layout.getRotation(); // remember angle at which layout is rotated at the start
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
layout.setRotation(findRotation(firstPointX, firstPointY, motionEvent.getRawX(), motionEvent.getRawY()) - zeroAngle + startAngle); // rotate relative to start and zero angle
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
}
return true;
}
});
}
private float findRotation(int firstPointX, int firstPointY, int secondPointX, int secondPointY) {
double delta_x = (secondPointX - firstPointX);
double delta_y = (secondPointY - firstPointY);
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
i have a bus route map as an image.
using the zoom controller the image is zooming out but not zooming in
please look at my code and let me know the change to be done make it working..
i am developing my app on Gingerbread i.e API 10
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.ZoomControls;
public class Busmaps extends Activity {
ImageView img;
ZoomControls zoom;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.busmaps);
img = (ImageView) findViewById(R.id.imageViewmaps1);
zoom = (ZoomControls) findViewById(R.id.zoomControls1);
zoom.setOnZoomInClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
int w = img.getWidth();
int h = img.getHeight();
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(w + 50, h + 50);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
img.setLayoutParams(params);
}
});
zoom.setOnZoomOutClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
int w = img.getWidth();
int h = img.getHeight();
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(w - 50, h - 50);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
img.setLayoutParams(params);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.bus_map_zoom, menu);
return true;
}
}
my xml says for bus route image:-
<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" >
<ImageView
android:id="#+id/imageViewmaps1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/map" />
<ZoomControls
android:id="#+id/zoomControls1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
how should i make my zoom control working for both Zoom in and Zoom out.
Please replace your Zoom in and ZoomOut listener with the following:
zoom.setOnZoomInClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
float x = img.getScaleX();
float y = img.getScaleY();
img.setScaleX((float) (x+1));
img.setScaleY((float) (y+1));
}
});
zoom.setOnZoomOutClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
float x = img.getScaleX();
float y = img.getScaleY();
img.setScaleX((float) (x-1));
img.setScaleY((float) (y-1));
}
});
}
Alternate option is to load the image in the Web view which has build in zoom controller.
As follows:
String page = "<html><body><center><img src=\""+path to your image+"\"/></center></body></html>";
webView.loadDataWithBaseURL("fake",page, "text/html", "UTF-8","");
If you dont want to use the build in web view zoom controller then you can just place your own buttons and apply zoom in and zoom out on web view as follows:
webView.setInitialScale(ZOOM_LEVEL);
public class Busmap extends Activity implements OnTouchListener
{
private static final String TAG = "Touch";
#SuppressWarnings("unused")
private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
// These matrices will be used to scale points of the image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// The 3 states (events) which the user is trying to perform
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// these PointF objects are used to record the point(s) the user is touching
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.busmaps);
ImageView view = (ImageView) findViewById(R.id.imageViewmaps1);
view.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN: // first finger down only
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG"); // write to LogCat
mode = DRAG;
break;
case MotionEvent.ACTION_UP: // first finger lifted
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}
else if (mode == ZOOM)
{
// pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f)
{
matrix.set(savedMatrix);
scale = newDist / oldDist; // setting the scaling of the
// matrix...if scale > 1 means
// zoom in...if scale < 1 means
// zoom out
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
return true; // indicate event was handled
}
private float spacing(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 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);
}
In my android app, I have a crop image. So, I programming a CropBox that extends ImageView. I want to move and resize the crop box. I use OnTouchListener, But MotionEvent.ACTION_MOVE not work. I google it but I don't catch anything.
Attr Class:
public class Attr {
public static final float CROP_BOX_START_X = 5;
public static final float CROP_BOX_START_Y = 5;
public static final float CROP_BOX_END_X = 305;
public static final float CROP_BOX_END_Y = 105;
}
CropBox Class:
public class CropBox extends ImageView {
private Paint paint = new Paint();
public CropBox(Context context) {
super(context);
}
public CropBox(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
#Override
public void onDraw(Canvas canvas) {
float[][] circleXY = {
{Attr.CROP_BOX_START_X, Attr.CROP_BOX_START_Y},
{(Attr.CROP_BOX_START_X + Attr.CROP_BOX_END_X) / 2, Attr.CROP_BOX_START_Y},
{Attr.CROP_BOX_END_X, Attr.CROP_BOX_START_Y},
{Attr.CROP_BOX_START_X, Attr.CROP_BOX_END_Y},
{(Attr.CROP_BOX_START_X + Attr.CROP_BOX_END_X) / 2, Attr.CROP_BOX_END_Y},
{Attr.CROP_BOX_END_X, Attr.CROP_BOX_END_Y},
{Attr.CROP_BOX_START_X, (Attr.CROP_BOX_START_Y + Attr.CROP_BOX_END_Y) / 2},
{Attr.CROP_BOX_END_X, (Attr.CROP_BOX_START_Y + Attr.CROP_BOX_END_Y) / 2}
};
float[][] lineXY = {
{Attr.CROP_BOX_START_X, Attr.CROP_BOX_START_Y, Attr.CROP_BOX_END_X, Attr.CROP_BOX_START_Y},
{Attr.CROP_BOX_START_X, Attr.CROP_BOX_END_Y, Attr.CROP_BOX_END_X, Attr.CROP_BOX_END_Y},
{Attr.CROP_BOX_START_X, Attr.CROP_BOX_START_Y, Attr.CROP_BOX_START_X, Attr.CROP_BOX_END_Y},
{Attr.CROP_BOX_END_X, Attr.CROP_BOX_START_Y, Attr.CROP_BOX_END_X, Attr.CROP_BOX_END_Y}
};
paint.setColor(Color.CYAN);
paint.setStrokeWidth(1);
for(int i = 0 ; i < circleXY.length ; i++)
canvas.drawCircle(circleXY[i][0], circleXY[i][1], 5, paint);
paint.setStrokeWidth(2);
for(int i = 0 ; i < lineXY.length ; i++)
canvas.drawLine(lineXY[i][0], lineXY[i][1], lineXY[i][2], lineXY[i][3], paint);
}
}
CropTestActivity Class:
public class CropTestActivity extends Activity {
private ImageView imageView;
private CropBox cropBorder;
private RelativeLayout relativeLayout;
private RelativeLayout.LayoutParams layoutParams;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.crop_test_layout);
imageView = (ImageView)findViewById(R.id.android_image);
cropBorder = new CropBox(this);
relativeLayout = (RelativeLayout)findViewById(R.id.crop_test_layout);
layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
ViewTreeObserver viewTreeObserver = imageView.getViewTreeObserver();
if(viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
layoutParams.leftMargin = imageView.getWidth() / 2 - (int)((Attr.CROP_BOX_START_X + Attr.CROP_BOX_END_X) / 2) + imageView.getLeft();
layoutParams.topMargin = imageView.getHeight() / 2 - (int)((Attr.CROP_BOX_START_Y + Attr.CROP_BOX_END_Y) / 2) + imageView.getTop();
}
});
}
relativeLayout.addView(cropBorder, layoutParams);
cropBorder.setOnTouchListener(new Crop());
}
}
Crop Class:
public class Crop implements OnTouchListener {
private static final int NONE = 0;
private static final int BOX_DRAG = 1;
private static final int BORDER_DRAG = 2;
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private PointF start = new PointF();
private int mode = NONE;
private float cropBoxStartX = Attr.CROP_BOX_START_X;
private float cropBoxStartY = Attr.CROP_BOX_START_Y;
private float cropBoxEndX = Attr.CROP_BOX_END_X;
private float cropBoxEndY = Attr.CROP_BOX_END_Y;
public boolean onTouch(View view, MotionEvent event) {
CropBox cropBox = (CropBox)view;
switch(event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
if(event.getX() > cropBoxStartX && event.getX() < cropBoxEndX && event.getY() > cropBoxStartY && event.getY() < cropBoxEndY)
mode = BOX_DRAG;
else if(event.getX() == cropBoxStartX || event.getX() == cropBoxEndX || event.getY() == cropBoxStartY || event.getY() == cropBoxEndY)
mode = BORDER_DRAG;
else
mode = NONE;
break;
case MotionEvent.ACTION_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if(mode == BOX_DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
}
else if(mode == BORDER_DRAG) {
}
break;
}
cropBox.setImageMatrix(matrix);
return true;
}
}
Layout XML:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/crop_test_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="#+id/android_image"
android:src="#drawable/android"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_gravity="center"
android:scaleType="fitXY"
android:contentDescription="#string/android_image_description" >
</ImageView>
</RelativeLayout>
Thanks for your help.
I believe that your implementation is right, the only thing that I didn't see is you setting the scale type of your CropBox to MATRIX to be able to use setImageMatrix.