im trying to add touchlistener for every item in listview.
here my code in my CustomAdapter for currentView (as i think)
rowView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x1 = event.getX();
return true;
case MotionEvent.ACTION_UP:
x2 = event.getX();
float deltaX = x2 - x1;
if (Math.abs(deltaX) > MIN_DISTANCE) {
if (x2 > x1) {
LEFT = false;
Logger.e("FALSE ");
txtTitle.setText("LEFT TO RIGHT");
moveLefttoRight = new TranslateAnimation(0, -150, 0, 0);
moveLefttoRight.setDuration(1500);
moveLefttoRight.setFillAfter(true);
swipeLayout.setAnimation(moveLefttoRight);
HomeChatAdapter.super.notifyDataSetChanged();
}
else {
LEFT = true;
Logger.e("TRUE");
txtTitle.setText("RIGHT TO LEFT");
moveLefttoRight = new TranslateAnimation(0, -150, 0, 0);
moveLefttoRight.setDuration(1500);
moveLefttoRight.setFillAfter(true);
swipeLayout.setAnimation(moveLefttoRight);
}
} else {
CLICKITEM = true;
return false;
}
break;
}
return false;
}
});
problem with animation and view.setText("blabla")
When my swipe is done "from left to right or from right to left"
no changes on screen
If i move out
txtTitle.setText("LEFT TO RIGHT");
moveLefttoRight = new TranslateAnimation(0, -150, 0, 0);
moveLefttoRight.setDuration(1500);
moveLefttoRight.setFillAfter(true);
swipeLayout.setAnimation(moveLefttoRight);
this part of code from TouchListener - than all ok but its work one time when created.
Can any help me how to do solution in this situation ?
Just want to move item in listview to left or right . Regard Peter.
If I am understanding your question correctly, you want to use
swipeLayout.startAnimation(...);
instead.
According to setAnimation vs startAnimation in android :
setAnimation
Sets the next animation to play for this view.But view animation does
not start yet.
startAnimation
If you want the animation to play immediately, use startAnimation.
This method provides allows fine-grained control over the start time
and invalidation, but you must make sure that
1) the animation has a start time set,
2) the view will be invalidated when the animation is supposed to
start.
Related
I'm trying to develop my own game. But I have an issue with the onTouchEvent-Method. Little explanation before showing my code. I want to be able to control a flight with my finger. It Should always follow my finger. For that I implemented the MotionEvent.ACTION_MOVE case. The flight only can move on the left side of the screen. When I touch on the right side of the screen, it should shoot a bullet. And it should be possible to fly around and shoot simultaneously. Here is my Code:
public boolean onTouchEvent(MotionEvent event) {
int maskedaction= event.getActionMasked();
switch (maskedaction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getX() > screenX / 2 && flight.toShoot == 0) {
flight.toShoot++;
}
break;
case MotionEvent.ACTION_MOVE: {
if (event.getX() < screenX / 2 - 100) {
flight.x = (int) event.getX() - 100;
flight.y = (int) event.getY() - 50;
}
break;
}
}
return true;
}
So that's the code. When I touch the left half of the screen, I can fly around with the plane. When I Touch the right side, I can shoot. But I cannot do it at the same time. I want to touch first the left half and fly around. By clicking on the right side, at the same time as i'm moving my finger on the left side, it should shoot a bullet.
I found out that when I click at the same time on both sides with one finger, then the plane shoots one bullet. If i release now the right finger(the finger that shoots when it touches the screen) I can fly around and while I'm flying around I can shoot simultaneously.
You can detect your touch by detecting IDs, https://developer.android.com/training/gestures/multi
You can do something like this :
int leftSideId = 0;
int rightSideId = 1;
public boolean onTouchEvent(MotionEvent event) {
int maskedaction= event.getActionMasked();
// Get the pointer ID
int mActivePointerId = event.getPointerId(0);
switch (maskedaction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getX() > screenX / 2) {
rightSideId = mActivePointerId;
if(flight.toShoot == 0){
flight.toShoot++;
}
}else{
leftSideId = mActivePointerId;
}
break;
case MotionEvent.ACTION_MOVE: {
if (event.getX() < screenX / 2 - 100) {
if (mActivePointerId == leftSideId) {
flight.x = (int) event.getX() - 100;
flight.y = (int) event.getY() - 50;
}
}
break;
}
}
return true;
}
So I found a solution by myself.
public boolean onTouchEvent(MotionEvent event){
int amount=event.getPointerCount();
for (int i=0; i<amount; i++) {
float x = event.getX(i);
float y = event.getY(i);
if (x>screenX/2 && flight.toShoot==0){
flight.toShoot++;
}
if (x<screenX/2 -100 && flyingenabled)
{
flight.x = (int) x - 100;
flight.y = (int) y - 50;
}
}
return true;
}
Thats working for my problem. Easier than I thought.
I'm using this library to use slide down menu, the problem is when I want to move the handle from top to bottom and want to change from slide down to slide up, I try to change the variable but can't make it right
This is the original code
/* User tapped down on screen. */
case MotionEvent.ACTION_DOWN:
// User has tapped the screen
yStart = event.getRawY();
lastY = event.getRawY();
currentHeight = slideDownView.getHeight();
break;
/* User is dragging finger. */
case MotionEvent.ACTION_MOVE:
// Calculate the total height change thus far.
float totalHeightDiff = event.getRawY() - yStart;
// Adjust the slide down height immediately with touch movements.
LayoutParams params = slideDownView.getLayoutParams();
params.height = (int)(currentHeight + totalHeightDiff);
slideDownView.setLayoutParams(params);
// Check and set which direction drag is moving.
if (event.getRawY() > lastY) {
directionDown = true;
} else {
directionDown = false;
}
// Set the lastY for comparison in the next ACTION_MOVE event.
lastY = event.getRawY();
break;
/* User lifted up finger. */
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
/*
* Need to snap either up or down. Using ValueAnimator to "finish" the action.
* HeightEvaluator is a custom class.
*
* NOTE: I'm using the nineoldandroids library for
*/
if (directionDown) {
// Open the sliding view.
int startHeight = slideDownView.getHeight();
ValueAnimator animation = ValueAnimator.ofObject(
new HeightEvaluator(slideDownView),
startHeight,
(int) openHeight).setDuration(300);
// See Table 3 for other interpolator options
// - http://developer.android.com/guide/topics/graphics/prop-animation.html
animation.setInterpolator(new OvershootInterpolator(1));
animation.start();
} else {
// Close the sliding view.
int startHeight = slideDownView.getHeight();
ValueAnimator animation = ValueAnimator.ofObject(
new HeightEvaluator(slideDownView),
startHeight,
(int) closedHeight).setDuration(300);
animation.setInterpolator(new OvershootInterpolator(1));
animation.start();
}
break;
How to make it reverse ? so I can slide up from bottom to top ? is it have to change also in HeightEvaluator.java ?
At the end I use BottomSheet and set PeekHeight to make a slideUp with button at the bottom that still visible to trigger the slideView
final RelativeLayout rl = (RelativeLayout) findViewById(R.id.rel);
final ImageView circle = (ImageView) findViewById(R.id.circle);
final ViewGroup.MarginLayoutParams screen = (ViewGroup.MarginLayoutParams) rl.getLayoutParams();
and..
View v;
v = arrayofImages[i];
v.setOnTouchListener(new View.OnTouchListener() {
PointF DownPT = new PointF();
PointF StartPT = new PointF();
#Override
public boolean onTouch(View v, MotionEvent event) {
int eid = event.getAction();
switch (eid) {
case MotionEvent.ACTION_MOVE:
PointF mv = new PointF(event.getX() - DownPT.x, event.getY() - DownPT.y);
v.setX((StartPT.x + mv.x));
v.setY( (StartPT.y + mv.y));
StartPT = new PointF(v.getX(), v.getY());
if (circle.getRight() > v.getX() && circle.getTop() <= v.getY()
&& circle.getBottom() > v.getY() && circle.getLeft() <= v.getX()) {
v.setVisibility(View.INVISIBLE);
}
if (v.getX() > screen.bottomMargin) {
v.setX(screen.bottomMargin);
}
break;
case MotionEvent.ACTION_DOWN:
DownPT.x = event.getX();
DownPT.y = event.getY();
StartPT = new PointF(v.getX(), v.getY());
break;
case MotionEvent.ACTION_UP:
// Nothing have to do
break;
default:
break;
}
return true;
}
});
So basically I'm trying to not allow an imageView to go ofscreen. if the view v is going too far left position it on the left side.
if (v.getX() > screen.leftMargin) {
v.setX(screen.leftMargin);
}
This should do to trick and it does but only for the left margin. If i try something like this
if (v.getX() > screen.rightMargin) {
v.setX(screen.rightMargin);
}
It acts like it's the leftMargin (it moves my image when i touch it on the left side.)
I don't know what i've done wrong...Please help..If you need more code i will paste but this is all that matters i think.
Well, you are not supposed to be using bottomMargin or topMargin fields. These are the Margins that you set for the RelativeLayout. If you want to check if the View doesn't go OUTSIDE the RelativeLayout, you need to be checking with width and height.
But if all you are going to do is to keep the View inside the RelativeLayout, you need to use View.getLeft() and View.getRight() instead of getX(). This will give the position of the View relative to the parent. You can use this in your logic, rather than using getX() (which returns the visual x position of this view, in pixels.)
It is possible to retrieve the location of a view by invoking the
methods getLeft() and getTop(). The former returns the left, or X,
coordinate of the rectangle representing the view. The latter returns
the top, or Y, coordinate of the rectangle representing the view.
These methods both return the location of the view relative to its
parent. For instance, when getLeft() returns 20, that means the view
is located 20 pixels to the right of the left edge of its direct
parent.
I'm having a very similar issue described here, except instead of using ScaleAnimation, I'm allowing pinch zoom/pan in my RelativeLayout.
The zoom/panning works perfectly, but regardless of how my view is panned/zoomed, the clickable area does not change along with the visual representation. Here's what my dispatchTouchEvent looks like:
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mScaleGestureDetector != null && mGestureDetector != null) {
mScaleGestureDetector.onTouchEvent(ev);
mGestureDetector.onTouchEvent(ev);
}
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleGestureDetector.isInProgress() && mScaleFactor > 1f) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
float newPosX = mPosX + dx;
float newPosY = mPosY + dy;
if (isCoordinateInBound(newPosX, mScreenSize.x))
mPosX = newPosX;
if (isCoordinateInBound(newPosY, mScreenSize.y))
mPosY = newPosY;
invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return super.dispatchTouchEvent(ev);
}
and my dispatchDraw:
protected void dispatchDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
super.dispatchDraw(canvas);
canvas.restore();
}
How do you modify the clickable area accordingly to modified scale/transformation of canvas?
Since you are already onverriding dispatchTouchEvent, you can try this:
manually evaluate each MotionEvent by considering the current zoom/pan transformation; you can create a new MotionEvent (let's call it FakeMotionEvent) by applying the reverse zoom/pan transformation to the original MotionEvent m.
Check if the FakeMotionEvent intercepts a specific View v; this means the user is touching in a position which represents the user-visibile position of v.
If FakeMotionEvent intercepts v, consume the current MotionEvent and invoke v.dispatchTouchEvent(m);
TIP: You can use the method below to evaluate if a MotionEvent intercepts a View with a certain degree of tolerance:
private boolean intercept(MotionEvent ev, View view, float boundingBoxTolerance){
if (boundingBoxTolerance < 1.0f) {
boundingBoxTolerance = 1.0f;
}
try {
if (ev != null && view != null) {
int coords[] = new int[2];
view.getLocationOnScreen(coords);
if (ev.getRawX() >= ((float)coords[0]) / boundingBoxTolerance && ev.getRawX() <= coords[0] + ((float) view.getWidth()) * boundingBoxTolerance) {
if(ev.getRawY() >= ((float)coords[1]) / boundingBoxTolerance && ev.getRawY() <= coords[1] + ((float) view.getHeight()) * boundingBoxTolerance)
return true;
}
}
}
catch (Exception e) {}
return false;
}
I guess you are using View Animations, i will prefer to use Property animations instead
excerpt from Android documentation (see highlighted)
The view animation system provides the capability to only animate View
objects, so if you wanted to animate non-View objects, you have to
implement your own code to do so. The view animation system is also
constrained in the fact that it only exposes a few aspects of a View
object to animate, such as the scaling and rotation of a View but not
the background color, for instance.
Another disadvantage of the view animation system is that it only
modified where the View was drawn, and not the actual View itself. For
instance, if you animated a button to move across the screen, the
button draws correctly, but the actual location where you can click
the button does not change, so you have to implement your own logic to
handle this.
With the property animation system, these constraints are completely
removed, and you can animate any property of any object (Views and
non-Views) and the object itself is actually modified. The property
animation system is also more robust in the way it carries out
animation. At a high level, you assign animators to the properties
that you want to animate, such as color, position, or size and can
define aspects of the animation such as interpolation and
synchronization of multiple animators.
The view animation system, however, takes less time to setup and
requires less code to write. If view animation accomplishes everything
that you need to do, or if your existing code already works the way
you want, there is no need to use the property animation system. It
also might make sense to use both animation systems for different
situations if the use case arises.
this problem is driving me up the wall. I'm sure I'm doing something wrong but I can't figure it out.
I have a static OnTouchListener which I attach to the TextView of a number of identical compound view objects contained within a linearlayout. This listener is in a helper class.
public static View.OnTouchListener getValueTouchListener() {
return new View.OnTouchListener() {
private int lastY;
private int lastX;
#Override
public boolean onTouch(View v, MotionEvent event) {
TextView view = (TextView)v;
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
view.setBackgroundResource(R.drawable.cog_pressed);
lastY = (int)event.getY();
lastX = (int)event.getX();
return true;
case MotionEvent.ACTION_MOVE:
//calc size of movement
int deltaY = lastY - (int)event.getY();
int deltaX = lastX - (int)event.getX();
// pass gesture up to parent if it's a big x movement - assumes user wishes to scroll parent
if (Math.abs(deltaX) > TOUCH_SLOP *2) {
return false;
}
lastX = (int)event.getX();
//process movement if larger than a touch slop
if (StrictMath.abs(deltaY) > TOUCH_SLOP) {
// reset last touch position
lastY = (int)event.getY();
//get direction of movement
int dir = (deltaY < 0)? -1 : 1;
//change index if within min and max limits
int min = (view.getTag() == Chainring.KEY)? Chainring.MIN_COG : Sprocket.MIN_COG;
int max = (view.getTag() == Chainring.KEY)? Chainring.MAX_COG : Sprocket.MAX_COG;
int value = Integer.valueOf(view.getText().toString());
if ((dir == -1 && value > min) || (dir == 1 && value < max)) {
value = value + dir;
view.setText(String.valueOf(value));
view.playSoundEffect(SoundEffectConstants.CLICK);
}
}
return true;
case MotionEvent.ACTION_UP:
view.setBackgroundResource(R.drawable.cog_unpressed);
return true;
case MotionEvent.ACTION_CANCEL:
view.setBackgroundResource(R.drawable.cog_unpressed);
return false;
default:
return false;
}
}
};
}
I hook up this listener to my TextView in a class that extends linear layout
mValueTextView.setOnTouchListener(CogPickerHelper.getValueTouchListener());
My problem is the method doesn't seem to execute the return command in the ACTION_DOWN, ACTION_UP and ACTION-MOVE cases. For example, with an ACTION_DOWN, the code executes as far as the return command but then steps directly to the default case and returns false - even though Logcat still reports the action as being ACTION-DOWN.
If I try to set a breakpoint on the return commands, IntelliJ says: "No executable code found at line X in class com.amb.GearBuddyV2.views.CogPickerHelper$2"
Does anyone know what I'm doing wrong here?
Your code seems to be working fine, the OnTouch return value is being returned correctly.
And yes, adding a break at a return statement will lead the debugger to complain about missing executable code.