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!!
Related
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"
/>
I've been struggling for nearly a week now with the drag implementation. I've tried so many tutorials and sample codes from here but every implementation I tried so far had a flaw. This is the most simple one I found which ALMOST works is this one below. The problem here is with THIS one is that as soon as I touch the image it moved below the touch point. It can be dragged around but sort of hanging a few cm below the touch point. Thanks
package com.example.imagedrag;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout.LayoutParams;
public class DragImage extends Activity {
int windowwidth;
int windowheight;
private LayoutParams layoutParams;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
windowwidth = getWindowManager().getDefaultDisplay().getWidth();
windowheight = getWindowManager().getDefaultDisplay().getHeight();
final ImageView img = (ImageView) findViewById(R.id.imageView1);
img.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams layoutParams = (LayoutParams) img
.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
layoutParams.leftMargin = x_cord;
layoutParams.topMargin = y_cord;
img.setLayoutParams(layoutParams);
break;
default:
break;
}
return true;
}
});
}
}
My XML is as follows:
<LinearLayout 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/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="126dp"
android:layout_marginTop="168dp"
android:src="#drawable/c1" />
</LinearLayout>
what about replacing
layoutParams.leftMargin = x_cord;
layoutParams.topMargin = y_cord;
with
layoutParams.leftMargin = x_cord-img.getWidth()/2;
layoutParams.topMargin = y_cord-img.getHeight()/2;
, I think this should fix your problem.
Hope I helped :)
layoutParams.leftMargin = x_cord - img.getWidth();
layoutParams.topMargin = y_cord - img.getHeight()*2;
I guess this will work, it works for absolute layout. Don`t know exactaly why, but probably its counting the title bar or something else on the size/position.
When I drag the ImageView it is put not on the place where I let go the finger. It is placed just below and to the right. I do not understand what's wrong.
Tried various options for ImageView positioning result is the same
Layout
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF8989"
tools:context=".MainActivity" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/ic_launcher" />
</RelativeLayout>
code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.imageView1).setOnTouchListener(this);
findViewById(R.id.imageView1).getRootView().setOnDragListener(this);
}
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(null, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DROP:
float X = event.getX();
float Y = event.getY();
Log.d(LOGCAT, "X " + (int) X + "Y " + (int) Y);
View view = (View) event.getLocalState();
view.setX(X);
view.setY(Y);
view.setVisibility(View.VISIBLE);
default:
break;
}
return true;
}
LogCat
12-04 23:44:40.548: D/myLogs(32658): Width image 72 Height image 72
12-04 23:44:40.558: D/myLogs(32658): ACTION_DROP X 216Y 390
12-04 23:44:40.568: D/myLogs(32658): Real position: X 180.0Y 354.0
12-04 23:44:40.598: D/myLogs(32658): Drag ended
12-04 23:44:41.928: D/myLogs(32658): Width image 72 Height image 72
12-04 23:44:41.928: D/myLogs(32658): ACTION_DROP X 442Y 329
12-04 23:44:41.948: D/myLogs(32658): Real position: X 406.0Y 293.0
12-04 23:44:41.968: D/myLogs(32658): Drag ended
Replace
view.setX(X);
view.setY(Y);
with
view.setX(X-(view.getWidth()/2));
view.setY(Y-(view.getHeight()/2));
It's because it's placing the image's top left corner to where you realease.
To have it do what you want, basically you will need to subtract half of the image's width from X and half of it's height from Y.
So you should have something like this:
view.setX((X - (image.width / 2));
view.setY(Y - (image.width / 2));
v.setX(me.getRawX() - (v.getWidth() / 2));
v.setY(me.getRawY() - (float)(v.getHeight()* 1.5 / 2));
I found this solution as perfect answer where as dragging from the center of the object.
Just incase someone needs help with this:
I tried it and found that the problem is with the rootview, if you give your layout an id (the one you are moving the image in) and than relace
findViewById(R.id.imageView1).getRootView().setOnDragListener(this);
findViewById(R.id.imageView1).getRootView().findViewById(R.id.yourLayout).setOnDragListener(this);
That should do it.
for placing imageView in the middle try what others already said:
view.setX(X - iv.getWidth()/2);
view.setY(Y - iv.getHeight()/2) ;
This will place the imageView in the middle
Happy programming :)
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;
}
});
}