Why bottomMargin/topMargin/rightMargin is acting like leftMargin? - java

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.

Related

Android move slide down to slide up view

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

Cant update item in custom adapter

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.

How to get Gridview child view by using touch coordinates (x,y) in Android Studio

I want to get the child view of the Gridview by knowing the touch position (x,y) coordinates.
case MotionEvent.ACTION_MOVE:
for(int i = 0; i < gridView.getChildCount(); i++)
{
//check if finger position is above any child
ImageView gridChild = (ImageView) gridView.getChildAt(i);
if(checkIntersection((int) event.getX(), (int) event.getY(), gridChild.getLeft(), gridChild.getRight(), gridChild.getTop(), gridChild.getBottom()))
{
gridChild.setImageResource(R.drawable.red_square);
break;
}
}
break;
I have the above code but this happens many times per second and I believe it is too intense. I thought that if I could get the child View object that the user is touching just by using the touch x,y coordinates I won't need to loop through all the childs to find which one they are touching.
checkIntersection() just gives true or false depending on whether the finger position is lying in the rectangle of the Gridview child object.
Image showing how the checkIntersection function works.
Update:
This is the whole block of code
//find the gridview view and assing it to a variable
final GridView gridView = (GridView) findViewById(R.id.gridView_boxes);
gridView.setAdapter(new ImageAdapter(this));
//when user lifts finger off the screen, reset all boxes
gridView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
//when finger is lifted off the gridView object
case MotionEvent.ACTION_UP:
//TODO after user lifts finger check if the path they chose has no obstacles
for (int i = 0; i < gridView.getChildCount(); i++)
{
ImageView gridChild = (ImageView) gridView.getChildAt(i);
gridChild.setImageResource(R.drawable.blue_square);
}
Log.d("SMEMS", "UP " + String.valueOf(action));
break;
//when finger touches the gridView
case MotionEvent.ACTION_DOWN:
//loop through all childs
for(int i = 0; i < gridView.getChildCount(); i++)
{
//check if finger position is above any child
ImageView gridChild = (ImageView) gridView.getChildAt(i);
if(checkIntersection((int) event.getX(), (int) event.getY(), gridChild.getLeft(), gridChild.getRight(), gridChild.getTop(), gridChild.getBottom())) {
gridChild.setImageResource(R.drawable.red_square);
break;
}
}
Log.d("SMEMS", "DOWN. Y value: " + String.valueOf(event.getY()) + ", X value: " + String.valueOf(event.getX()));
break;
case MotionEvent.ACTION_MOVE:
//TODO check if there is a more efficient way of doing this without a loop
//loop through all childs
for(int i = 0; i < gridView.getChildCount(); i++)
{
//check if finger position is above any child
ImageView gridChild = (ImageView) gridView.getChildAt(i);
if(checkIntersection((int) event.getX(), (int) event.getY(), gridChild.getLeft(), gridChild.getRight(), gridChild.getTop(), gridChild.getBottom())) {
gridChild.setImageResource(R.drawable.red_square);
break;
}
}
break;
}
return true;
}
});

Android scaling/transforming canvas doesn't modify clickable area

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.

Programmatically reorder RelativeLayout

I'm trying to create a word jumble game where you drag a letter right or left in the jumbled word and the letters swap. What is the best way to reorder items in a RelativeLayout programmatically so when the letter is dragged left the letters that the tile passes are positioned to the right of the dragged letter.
I've tried something like this as a basic test.
public static void moveTile(Tile tile, int x, RelativeLayout parent) {
if (x < tile.getWidth()) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF, tile.getId() - 1);
tile.setLayoutParams(params);
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
p.addRule(RelativeLayout.RIGHT_OF, tile.getId());
Tile t = (Tile) parent.findViewById(tile.getId() - 1);
t.setLayoutParams(p);
}
parent.invalidate();
}
But this causes the app to crash with an error about "Circular dependancies cannot exist in a RelativeLayout" which I understand but I'm just not sure what other way to do this.
Any help will be much appreciated.
Yes, this error means that you must not have an object1 be toRightOf object2 and object2 toLeftOf object 1
I think in your case you should not use toRightOf and toLeftOf to position your views but try to use just margin left and margin top setting for all of them. In this way your child views would be independed of each other and you can move them around by changing their margins.
I ended up using a LinearLayout and just removing the tile before or after and replacing it with the currently selected tile something like this.
public static void moveTile(Tile tile, int x, LinearLayout parent) {
if (x < 0) {
int t = Math.abs(x) / tile.getWidth() + 1;
if (tile.getId() - t >= 0) {
Tile new_tile = (Tile) parent.findViewById(tile.getId() - t);
parent.removeViewAt(new_tile.getId());
parent.addView(new_tile, tile.getId());
int id = tile.getId();
tile.setId(new_tile.getId());
new_tile.setId(id);
}
} else if (x > tile.getWidth()) {
int t = x / tile.getWidth();
if (tile.getId() + t < word.length()) {
Tile new_tile = (Tile) parent.findViewById(tile.getId() + t);
parent.removeViewAt(new_tile.getId());
parent.addView(new_tile, tile.getId());
int id = tile.getId();
tile.setId(new_tile.getId());
new_tile.setId(id);
}
}
}

Categories

Resources