I am working on an app where user can move his image within the screen, and then save it.
The problem is positioning Bitmap in ImageView on start of the activity.
Here is the XML:
<RelativeLayout
android:id="#+id/image_content_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/top_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:scaleType="matrix"
android:gravity="center|center_vertical"
android:layout_gravity="center|center_vertical"/>
</RelativeLayout>
I am moving the ImageView (well, not ImageView, but its matrix) with onTouch, and it works well.
#Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
mode = DRAG;
start.set((int) event.getX(), (int) event.getY());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
}
break;
}
view.setImageMatrix(matrix);
return true;
}
The problem is the position of Bitmap on the start of Activity. It is aligned on Top|Left instead of Center. Like this:
Can anyone please help me center it on start in ImageView?
If you want to align bitmap to center then you ImageView layout should be:
<ImageView
android:id="#+id/top_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"/>
EDIT:
In case if you need scaleType "matrix" then use next solution:
<ImageView
android:id="#+id/top_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
/>
And then in code change offset of image:
final ImageView imageView = (ImageView) findViewById(R.id.top_image);
imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
imageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
Drawable drawable = imageView.getDrawable();
Rect rectDrawable = drawable.getBounds();
float leftOffset = (imageView.getMeasuredWidth() - rectDrawable.width()) / 2f;
float topOffset = (imageView.getMeasuredHeight() - rectDrawable.height()) / 2f;
Matrix matrix = imageView.getImageMatrix();
matrix.postTranslate(leftOffset, topOffset);
imageView.setImageMatrix(matrix);
imageView.invalidate();
}
});
This worked for me.
<ImageView
android:id="#+id/top_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="matrix"
/>
Related
i want to rotate a relative layout by a rotation button.
this is my code
main.java
imageContainer = (RelativeLayout)findViewById(R.id.imageContainer);
rotateBTN = (Button)findViewById(R.id.rotate);
rotateBTN.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final float xc = imageContainer.getWidth() / 2;
final float yc = imageContainer.getHeight() / 2;
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
imageContainer.clearAnimation();
mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
break;
}
case MotionEvent.ACTION_MOVE: {
mPrevAngle = mCurrAngle;
mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
animate(mPrevAngle, mCurrAngle, 0);
break;
}
case MotionEvent.ACTION_UP : {
rotate = false;
mPrevAngle = mCurrAngle = 0;
break;
}
}
return true;
}
});
private void animate(double fromDegrees, double toDegrees, long durationMillis) {
final RotateAnimation rotate = new RotateAnimation((float) fromDegrees, (float) toDegrees,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(durationMillis);
rotate.setFillEnabled(true);
rotate.setFillAfter(true);
imageContainer.startAnimation(rotate);
// imageView2.startAnimation(rotate);
System.out.println(mCurrAngle);
}
main.xml
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:id="#+id/onlyImage"
android:layout_marginTop="20dp">
<ImageView
android:id="#+id/imageView1"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_launcher"
/>
<ImageView
android:id="#+id/imageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_launcher"
android:visibility="gone"
/>
</RelativeLayout>
<Button
android:layout_width="30dp"
android:layout_height="30dp"
android:id="#+id/rotate"
/>
</RelativeLayout>
by this code, i am able to rotate the RelativeLayout. But the problem is that after rotating first time (rotate button also rotates because it is inside my RelativeLayout) ontouch event is not called on new position of my rotate button but if i touch the top left corner of my relative layout ( initial position of my button) onTouch listener works fine.
plz help me find the issue. any suggestion would be appreciated :)
this is my relative layout
P.S i want to do something like this
I have two ImageViews on a layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:id="#+id/root">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/zoom" />
<ImageView
android:layout_width="55dp"
android:layout_height="55dp"
android:id="#+id/drag"
android:layout_gravity="center_horizontal|top"
android:layout_alignParentTop="false" />
</RelativeLayout>
The ImageView with id zoom has implemented the PhotoViewAttacher which makes the ImageView zoomable.
The other ImageView with id = drag has a OnTouchListener:
drag.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
//Definition MotionEvent.ACTION_MASK: Bit mask of the parts of the action code that are the action itself.
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
int i = lParams.leftMargin;
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
v.setLayoutParams(layoutParams);
break;
}
viewGroup.invalidate();
return true;
}
});
So the drag ImageView is moveable around the screen.
What I want is: If I zoom in, the drag ImageView shall be zoomed in too. Same the other way while zooming out.
How can I place the drag ImageView in a way that it is "docked" on the zoom ImageView. So if I move the zoom image around the screen, the drag image have to stay on the position it left.
For example:
drag is moved to center of the screen.
zoom is zoomed in
zoom moved to right so the drag image is moved outside the screen
zoom moved back to the center where the drag image is docked
I hope you understand what I want to do
Kind Regards!!
In my application I want to get image view height and width after zoom the image.This is the code for zoom the image view. This is onCreate method..
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnGet=(Button) findViewById(R.id.get);
relImage=(RelativeLayout) findViewById(R.id.image);
imgMarker = (ImageView) findViewById(R.id.imagemarker);
btnGet.setOnClickListener(this);
dragImage=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
imgMarker.setImageBitmap(dragImage);
imgMarker.setOnTouchListener(this);
}
And this is ontouch method..
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
// 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
mode1 = DRAG1;
break;
case MotionEvent.ACTION_UP: // first finger lifted
x_cordinate=event.getX();
y_cordinate=event.getY();
Log.e("height====",""+dragImage.getHeight());
Log.e("width=====",""+dragImage.getWidth());
Log.e("x_cordinate==",""+x_cordinate);
Log.e("y_cordinate==",""+y_cordinate);
break;
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode1 = NONE1;
Log.d(TAG, "mode1=NONE1");
break;
case MotionEvent.ACTION_MOVE:
if (mode1 == DRAG1){
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}
else if (mode1 == ZOOM1){
// 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.postScale(scale, scale, mid.x, mid.y);
}
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode1 = ZOOM1;
Log.d(TAG, "mode=ZOOM" );
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
return true; // indicate event was handled
}
And this is xml file..
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="get"
android:id="#+id/get"/>
<RelativeLayout
android:id="#+id/image"
android:layout_marginTop="10dp"
android:layout_below="#+id/get"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<ImageView
android:scaleType="matrix"
android:visibility="gone"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:id="#+id/imagemarker"/>
</RelativeLayout>
</RelativeLayout>
In this switch case MotionEvent.ACTION_UP, I am getting the image view height and width. But these values are same after zoom the image also.So please suggest me how to do? Thanks In advance to all..
I want to move a view on touch and when the user unholds this view, it is started an animation which moves my view to the end of its parent.
This is my layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/time_view"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<AbsoluteLayout
android:id="#+id/slide_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_margin="20dp"
android:background="#0000FF" >
<View
android:id="#+id/slide_to_pause"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#00FFFF" />
</AbsoluteLayout>
</RelativeLayout>
This is how I set the view to move in my onCreate:
slideView = ((View) findViewById(R.id.slide_to_pause));
slideView.setOnTouchListener(this);
This is how I move the view and starts the animation:
#Override
public boolean onTouch(View view, MotionEvent event) {
AbsoluteLayout.LayoutParams layoutParams = (AbsoluteLayout.LayoutParams) view.getLayoutParams();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mX = event.getRawX();
break;
case MotionEvent.ACTION_UP:
int endOfAnimation = findViewById(R.id.slide_layout).getWidth() - view.getWidth();
mSlideAnimation = new TranslateAnimation(0, endOfAnimation - layoutParams.x, 0, 0);
mSlideAnimation.setDuration(1000);
view.startAnimation(mSlideAnimation);
Log.d(TAG, "endOfAnimation = " + layoutParams.x + " | " + endOfAnimation);
break;
case MotionEvent.ACTION_MOVE:
layoutParams.x = (int) event.getRawX();
view.setLayoutParams(layoutParams);
break;
}
return true;
}
The problem is that when the view arrives at the end it comes back to a point in the midle of the screen, which is the point where the user unholds the view.
How can I fix this?
Thank you!
You need to use
mSlideAnimation.setFillAfter(true);
to make it not revert back to the start.
If that doesn't work you might have to follow the suggestion on Animation.setFillAfter/Before - Do they work/What are they for?
You can simulate animation manually (move views yourself, without animation framework) by using
View.offsetLeftAndRight(int offset)
View.offsetTopAndBottom(int offset)
I want to implement an activity where the only thing you see is a big image, which can be scrolled horizontally and vertically.On Top of that image I want to display buttons, that can be clicked and trigger certain actions (like creating an intent to start a new activity).
First I was thinking about a ScrollView, that has a FrameLayout as a child. The FrameLayout could have the image as a background and can have the buttons as childs. Because I know the position of my buttons exactly I could place them with absolute coordinates. Here is my first code:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:layout_width="1298px"
android:layout_height="945px"
android:background="#drawable/myimage">
<Button
android:id="#+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="115px"
android:layout_y="128px"/>
</FrameLayout>
</ScrollView>
The Problem is, that you can only scroll a ScrollView vertically. HorizontalScrollView doesn't solve the Problem, cause it only scrolls in one direction either. Can I mix them somehow? Is there another solution?
I found some similar threads on stackoverflow, where people put the image into a WebView and get horizonzal/vertical scrolling for free (here). Or someone put the image in an imageview and gave the imageview an onTouchListener to handle scrolling (here). The Problem with both ways is, that I either way I dont think you can put Buttons on top of the image, which is what I need to do.
I would very appreciate if someone help me out.
Using the (deprecated!!!) AbsoluteLayout and giving it and onTouchListener solved my problem:
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:src="#drawable/myImage"
android:layout_width="1298px"
android:layout_height="945px"
android:layout_x="0px"
android:layout_y="0px" />
<Button
android:id="#+id/myButton"
android:text="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="50px"
android:layout_y="300px"
android:tag="1"/>
</AbsoluteLayout>
private float mx;
private float my;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
final Button button = (Button)findViewById(R.id.myButton);
button.setOnClickListener (new View.OnClickListener(){
// OnClickAction
});
final AbsoluteLayout switcherView = (AbsoluteLayout) this.findViewById(R.id.myLayout);
switcherView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent event) {
float curX, curY;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mx = event.getX();
my = event.getY();
break;
case MotionEvent.ACTION_MOVE:
curX = event.getX();
curY = event.getY();
switcherView.scrollBy((int) (mx - curX), (int) (my - curY));
mx = curX;
my = curY;
break;
case MotionEvent.ACTION_UP:
curX = event.getX();
curY = event.getY();
switcherView.scrollBy((int) (mx - curX), (int) (my - curY));
break;
}
return true;
}
});
}