android - Invalid bitmap movement - android

I have a problem with moving a bitmap.
The bitmap is larger than the screen.
Code xml:
<?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/lay_mapa"
android:clipChildren="false" >
<ImageView
android:id="#+id/iv_mapa_swiata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/mapa_swiata"
android:scaleType="center"
android:padding="0dp"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"/>
</RelativeLayout>
Code in java file:
int xCoOrdinate;
int yCoOrdinate;
ImageView mapa_swiata;
On onCreate:
mapa_swiata.setOnTouchListener(this);
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
xCoOrdinate = (int) (v.getX() - event.getRawX());
yCoOrdinate = (int) (v.getY() - event.getRawY());
break;
case MotionEvent.ACTION_MOVE:
v.animate().x(event.getRawX() + xCoOrdinate).y(event.getRawY() + yCoOrdinate).setDuration(0).start();
break;
}
return true;
}
The picture moves in a rather unpredictable way. This is illustrated by the following movie:
https://youtu.be/BJyQjNmj-J4

From experience, dealing with these kinds of issues is a great pain when doing a custom view. I would recommend using a ready-made library like:
https://github.com/chrisbanes/PhotoView
They've solved most of the problems you are gonna come across already.
However, coming back to the code. You are returning true for all the events. This can potentially leave the view in a strange state, especially with the ACTION_UP events marked as consumed.
Something like this may work:
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
xCoOrdinate = (int) (v.getX() - event.getRawX());
yCoOrdinate = (int) (v.getY() - event.getRawY());
return true;
case MotionEvent.ACTION_MOVE:
v.animate().x(event.getRawX() + xCoOrdinate).y(event.getRawY() + yCoOrdinate).setDuration(0).start();
return true;
default:
return false;
}
}
Update:
Ok, here are some other thoughts. Lose the animation. Not sure if it is what's happening. You can set the translation of the view using: setTranslationX() and setTranslationY() and the events from the touch sensor should be enough to make it feel smooth.
Try using a FrameLayout as the parent. There is no need here to use RelativeLayout.
Also, I would recommend leaving the coordinate values as floats since they are always needed on that type. Saves having to change number precision.

Related

Moving a View with ACTION_MOVE in Scaled Layout

Hello! Thank you for reading.
Based upon this answer, I integrated View dragging like so:
float dX, dY;
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
setX(event.getRawX() + dX);
setY(event.getRawY() + dY);
break;
default:
return false;
} return true;
}
However, the View's position relative to my finger is proportionally offset with the scale of the parent layout. In other words, when I start zooming in the layout, View dragging breaks.
I've been debugging for quite a bit and it seems that even knowing the parent layout scale (as, say, dScale), I can't use that value in a way that fixes the offset completely.
I cannot even reach a point where the distance between my finger and the View is constant.
To note that the issue is only observable when the parent's scale is not equal to 1.
.
Thank you very much for your help!
For further reference, this situation can be solved by applying the parent's scale to the getRawX() methods in both occurrences. I somehow hadn't tried that...
float dX, dY;
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dX = view.getX() - event.getRawX() / dScale;
dY = view.getY() - event.getRawY() / dScale;
break;
case MotionEvent.ACTION_MOVE:
setX(event.getRawX() / dScale + dX);
setY(event.getRawY() / dScale + dY);
break;
default:
return false;
} return true;
}
I'd also recommend putting the MOVE case first in the switch.
I suppose the reasoning behind this solution can be vaguely explained by "view positioning methods know how to handle scaling, touch callback methods don't".
Hope this will help some!

Hide view when draggin up

I have a layout with 2 LinearLayout. The first one is used as a container to contain a graph, and the second one contains few buttons.
When the app starts, at first instance the LinearLayout1 which contains the graph is hidden View.GONE.
Then when I touch a button from LinearLayout2, this layout goes back to its original place using a translate animation.
Finally, I should have the capability to hide again the LinearLayout1. I would like to achieve this by draggin up the LinearLayout2, so when the user has moved a bit upwards the LinearLayout2, the LinearLayouy1 would become again hidden by View.GONE.
This final part is the one with I need some help. I have tried something using an OnTochListener() but I haven't worked too much with this and i'm not sure about how to do it. This is code snnipet where I do this:
/*Layout views*/
private View graphContainer; //This is the LinearLayout1
private View valuesContainer; //This is the LinearLayout2
private float oldY;
private float newY;
...
valuesContainer.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float y = event.getY();
oldY = y;
break;
case MotionEvent.ACTION_MOVE:
float y2 = event.getRawY();
newY = y2;
if (oldY < newY) {
graphContainer.setVisibility(View.GONE);
}
break;
}
return true;
}
});
Depending on where I touch to do the movement I get to set the visibility to GONE, but the movement is not as I would like, I don't get to move the LinearLayout2.
What you did above is hiding layout2 when the user moves it's finger up.
You say that "you don't get to move the LinearLayout2" -> in order to move a view you need to update it's LayoutParams. You can see an example to this here : How to move a view in Android?
This way you can "push" layout2 up and at some point hide layout1 (using animation, or pushing layout1 as well). Hope this helps.
Edit (a requested code sample) :
BTW - animations transitions is the better way to go when view's params needs changing. It's not the answer to your question since you want a real "drag" feel (when going up).
Also - android L has some beautiful animations (I haven't used yet) that we should keep an eye on.
So... using a layout as follows :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MyActivity">
<LinearLayout
android:id="#+id/first_layout"
android:background="#android:color/darker_gray"
android:layout_width="match_parent"
android:layout_height="100dp" >
</LinearLayout>
<LinearLayout
android:id="#+id/second_layout"
android:background="#android:color/holo_green_dark"
android:layout_width="match_parent"
android:layout_height="100dp" >
</LinearLayout>
</LinearLayout>
and a corresponding activity as follows :
public class MyActivity extends Activity {
int yDown = 0;
int initialTopMargin = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
LinearLayout layout2 = (LinearLayout)findViewById(R.id.second_layout);
layout2.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event)
{
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
switch (event.getAction())
{
case MotionEvent.ACTION_MOVE:
params.topMargin = initialTopMargin - (yDown - (int)event.getRawY());
view.setLayoutParams(params);
break;
case MotionEvent.ACTION_DOWN:
yDown = (int)event.getRawY();
initialTopMargin = params.topMargin;
break;
}
return true;
}
});
}
}
how about using onDragListener ?
valuesContainer.setOnDragListener(new OnDragListener() {
#Override
public boolean onDrag(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float y = event.getY();
oldY = y;
break;
case MotionEvent.ACTION_MOVE:
float y2 = event.getRawY();
newY = y2;
if (oldY < newY) {
graphContainer.setVisibility(View.GONE);
}
break;
}
return true;
}
});

How do you make an onTouchListener keep going as long as the view is being pressed?

I am using a small square RelativeLayout as a game pad for movement in a neighboring GLSurfaceView.
I set it up so that in the onTouch method of the RelativeLayout's onTouchListenner I call a method built into the GLSurfaceView that updates the translation and rotation coordinates for my drawing.
I have everything working fine, except for the fact that touch events are only triggered if the user moves his or her finger on the RelativeLayout.
I would like it to feel a little bit like a joystick: if you leave your finger pressed on the top of the RelativeLayout, then you will keep going "up" ( or more programatically: the event.getX() and event.getY() that were sent last should get looped, or re-sent, in the GLSurfaceView until the user either moves his finger inside the RelativeLayout, or stops touching the RelativeLayout altogether.)
What should I use to detect whether or not the RelativeLayout is currently being touched (even if there is no motion in the said touch)?
Thanks!
So this is what I came up pretty much simultaneously with csmcklvey
if(event.getAction()==MotionEvent.ACTION_UP)
gM.isTouchedL = false;
else
gM.isTouchedL = true;
return true;
Where .isTouchedL is the "control boolean" I use in the GLSurfaceView
Green lit csmc's answer anyways! :)
I have used rotation animation in one of my apps, which is using the onTouchEven of view. Major function has been performed in event "ACTION_MOVE". It will help you, to get through.
public boolean onTouch(View v, MotionEvent event)
{
final float xc = volumeButton.getWidth() / 2;
final float yc = volumeButton.getHeight() / 2;
final float x = event.getX();
final float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
// volumeButton.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, 100);
break;
}
case MotionEvent.ACTION_UP :
{
mPrevAngle = mCurrAngle = 0;
break;
}
}
return true;
}
You might be able to use the event.getAction() method of the MotionEvent parameter of your onTouch() method. You can check to see if it is MotionEvent.ACTION_DOWN or MotionEvent.ACTION_UP.
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//start something
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
//stop something
}
My thought is that you might be able to start or stop a thread in this manner but either way this might at least give you some more information about when the user actually presses and lifts his/her finger.

How to set position for image matrix?

I have a GridView with images. On long click the screen gets dark (with black half transparent image that gets visible) and another image become visible that has the same resource of the image long clicked from the grid.
What i want is to be able to drag that image (which i have succeeded), but the image shows at the top corner (as i designed the layout in the XML) and I want it to show up where I clicked (To be precised, i want the center of the dragable picture to be where I perfumed the long click).
My image is fill_parent on FrameLayout and is set on matrix scale to control position...
this is the image part of the XML:
<ImageView
android:id="#+id/imgMainSelectedMovie"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="matrix"
android:visibility="invisible"
android:src="#drawable/escape" />
and this is the OnTouch() part:
public boolean onTouch(View v, MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
X = ev.getX();
Y = ev.getY();
if (longClicked) return true;
break;
case MotionEvent.ACTION_MOVE:
if (longClicked) {
if (!dragStarted) {
dragStarted = true;
myImageView.setX(X);
myImageView.setY(Y);
}
matrix.postTranslate((ev.getX() - X), (ev.getY() - Y));
X = ev.getX();
Y = ev.getY();
myImageView.setImageMatrix(matrix);
return true;
}
break;
case MotionEvent.ACTION_UP:
if (longClicked) {
dark.setVisibility(View.INVISIBLE);
myImageView.setVisibility(View.INVISIBLE);
longClicked = false;
return true;
}
}
return false;
}
thist is what I tried to solve the problem:
if (!dragStarted) {
dragStarted = true; //Changed to true when OnItemLongClick called
myImageView.setX(X);
myImageView.setY(Y);
}
But it only changes the "start point" of the image layout to the entered X and Y.
Problem solved :)
What I did is when onItemLongClick calls I took the X and Y measured from the ACTION_DOWN case in the onTouch, took the matrix current location and did postTranslate to the coordinates from the ACTION_DOWN minus the location of the image.
this is the solution part from the onItemLongCliick:
matrix.getValues(values);
matrixX = values[Matrix.MTRANS_X];
matrixY = values[Matrix.MTRANS_Y];
matrix.postTranslate(X-matrixX, Y-matrixY);
myImageView.setImageMatrix(matrix);
I'm wondering why they didn't put some kind of "setPlace" method for matrix...

How do I detect if a user has touched any part of the screen other than the inside of an EditText?

I am guessing this means making the whole screen touchable. How exactly is that done?
and secondly calculating if an X,Y is within the EditText.
override the onTouchEvent in the activity you want to implement this....and get the X, Y co-ordinates using event.getX() and event.getY()
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
}
return false;
}
but i suggest you must search thoroughly before posting a question.

Categories

Resources