I have an ImageView in an activity, When you click on a part of the image the fragment is updated and is made visible. This works as required, however the fragment is appearing behind the imageView. So I cannot see it. I wish for the fragment to appear in the bottom third of the view. Can anyone suggest why this is happening?
.xml file
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:design="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="#+id/limerickMapImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/limerickmap" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/centreButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:src="#drawable/centre"
app:backgroundTint="#color/linkBlue" />
<LinearLayout
android:id="#+id/infoFragmentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
>
<fragment
android:id="#+id/infoFragment"
class="com.codingwithmitch.googlemaps2018.ui.LocationInfoFragment"
android:layout_width="fill_parent"
android:layout_height="300dp"
android:layout_gravity="bottom"
app:layout_anchorGravity="center_vertical" />
</LinearLayout>
This is the snippet from my onCreate from the activity where I make the fragment visible
photoview2.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
touchX = (int) event.getX();
touchY = (int) event.getY();
LocationInfoFragment fragobject2 = (LocationInfoFragment) getSupportFragmentManager().findFragmentById(R.id.infoFragment) ;
LinearLayout infoFragementLayout = (LinearLayout) findViewById(R.id.infoFragmentLayout);
//LinearLayout infoFragementLayout = (LinearLayout) findViewById(R.id.infoFragmentLayout);
infoFragementLayout.setVisibility(View.INVISIBLE);
for (InfoLocationInformation locationArrayVariable : mInfoLocationInformations) {
if(touchX > locationArrayVariable.getXy().get(0) & touchX < locationArrayVariable.getXy().get(2) & touchY > locationArrayVariable.getXy().get(1) & touchY < locationArrayVariable.getXy().get(3)){
//Log.e(TAG, "Location information for " + locationArrayVariable.getName() );
if(locationArrayVariable.getType()<1 && infoButton.getBackgroundTintList().getDefaultColor()==-49023+100){
bundleString = locationArrayVariable.getText();
fragobject2.updateFragment(bundleString);
infoFragementLayout.setVisibility(View.VISIBLE);
}else if(locationArrayVariable.getType()>0 && locationArrayVariable.getType()<3 && (barButton.getBackgroundTintList().getDefaultColor()==-524991+100 || restaurentButton.getBackgroundTintList().getDefaultColor()==-10879633+100)){
bundleString =locationArrayVariable.getText();
fragobject2.updateFragment(bundleString);
infoFragementLayout.setVisibility(View.VISIBLE);
}else if(locationArrayVariable.getType()>2 && locationArrayVariable.getType()<5 && (cafeButton.getBackgroundTintList().getDefaultColor()==-31949+100 || restaurentButton.getBackgroundTintList().getDefaultColor()==-10879633+100)){
fragobject2.updateFragment(bundleString);
infoFragementLayout.setVisibility(View.VISIBLE);
}else if(locationArrayVariable.getType()>4 && cafeButton.getBackgroundTintList().getDefaultColor()==-31949+100){
fragobject2.updateFragment(bundleString);
infoFragementLayout.setVisibility(View.VISIBLE);
}
}
}
Log.e(TAG, "touch coordinates X" + touchX +" Y "+ touchY );
ImageView view = (ImageView) v;
view.bringToFront();
viewTransformation(view, event);
return true;
}
});
I have this motion event function which allows me to zoom in and out and move around the imageview in the activity.
private void viewTransformation(View view, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
centreCheck =false;
xCoOrdinate = view.getX() - event.getRawX();
yCoOrdinate = view.getY() - event.getRawY();
start.set(event.getX(), event.getY());
isOutSide = false;
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
centreCheck =false;
oldDist = spacing(event);
if (oldDist > 10f) {
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
centreCheck =false;
isZoomAndRotate = false;
if (mode == DRAG) {
float x = event.getX();
float y = event.getY();
}
case MotionEvent.ACTION_OUTSIDE:
centreCheck =false;
isOutSide = true;
mode = NONE;
lastEvent = null;
case MotionEvent.ACTION_POINTER_UP:
centreCheck =false;
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
centreCheck =false;
if (!isOutSide) {
if (mode == DRAG) {
isZoomAndRotate = false;
view.animate().x(event.getRawX() + xCoOrdinate).y(event.getRawY() + yCoOrdinate).setDuration(0).start();
}
if (mode == ZOOM && event.getPointerCount() == 2) {
float newDist1 = spacing(event);
if (newDist1 > 10f) {
float scale = newDist1 / oldDist * view.getScaleX();
view.setScaleX(scale);
view.setScaleY(scale);
}
if (lastEvent != null) {
newRot = rotation(event);
view.setRotation((float) (view.getRotation() + (newRot - d)));
}
}
}
break;
}
}
Seeing your requirement you should go for BottomSheetFragment , that will be perfect solution for your requirement.
Check following link
https://www.androidhive.info/2017/12/android-working-with-bottom-sheet/
There is a way you can Overcome this In the main coordinate view set its background color as white and make it clickable
Related
I have drag and drop imageView(multiple imageView with same object) in layout and after that ImageView onTouch it move around layout. but after move imageView it overlapping with each other, how do prevent overalapping image?
also every image object is same. here is my code :
public boolean onDrag(View view, DragEvent event) {
recyclerViewFloorTiles = findViewById(R.id.rvfloortiles);
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_ENDED:
break;
case DragEvent.ACTION_DROP:
dropX = event.getX();
dropY = event.getY();
final ObjectAdapter.DragData state = (ObjectAdapter.DragData) event.getLocalState();
final ImageView shape = (ImageView) LayoutInflater.from(this).inflate(
R.layout.layout_drag_image, dropContainer, false);
shape.setImageResource(state.item.getDrawableRes());
shape.setX(dropX - (float) state.width / 2);
shape.setY(dropY - (float) state.height / 2);
shape.getLayoutParams().width = state.width;
shape.getLayoutParams().height = state.height;
dropContainer.addView(shape);
shape.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
ImageView objectDropImage = new ImageView(DashboardActivity.this);
objectDropImage.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
dropContainer.addView(objectDropImage);
float newX, newY;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
newX = event.getRawX() + dX;
newY = event.getRawY() + dY;
if ((newX <= 0 || newX >= screenWidth-view.getWidth()) || (newY <= 0 || newY >= screenHight-view.getHeight()))
{
break;
}
view.setX(newX);
view.setY(newY);
break;
}
return false;
}
});
}
break;
default:
break;
}
return true;
}
Edited: Adding the XML layout of my view (How to achieve flip animation android (GIF Added))
TopLayout : ivImage
BottomLayout : layoutL
I want to implement Vertical ViewPager as shown in the GIF image below. Implemented Vertical ViewPager but can't implement Flip Animation
Any Code snippet or Library
My Customized VerticalViewPager Class Implemented Vertical ViewPager with normal animation Motionevent in VerticalPageTransformer
public class VViewPager2 extends ViewPager {
String TAG = "VViewPager";
float x = 0;
float mStartDragX = 0;
private static final float SWIPE_X_MIN_THRESHOLD = 15; // Decide this magical number as per your requirement
private boolean disableSwipe = false;
public VViewPager2(#NonNull Context context) {
super(context);
init();
}
public VViewPager2(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
// setPageTransformer(true, new PagerTransformer());
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (getAdapter() != null) {
if (getCurrentItem() >= 0 || getCurrentItem() < getAdapter().getCount()) {
swapXY(event);
final int action = event.getAction();
switch (action & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
mStartDragX = event.getX();
if (x < mStartDragX
&& (mStartDragX - x > SWIPE_X_MIN_THRESHOLD)
&& getCurrentItem() > 0) {
Log.i(TAG, "down " + x + " : " + mStartDragX + " : " + (mStartDragX - x));
setCurrentItem(getCurrentItem() - 1, true);
return true;
} else if (x > mStartDragX
&& (x - mStartDragX > SWIPE_X_MIN_THRESHOLD)
&& getCurrentItem() < getAdapter().getCount() - 1) {
Log.i(TAG, "up " + x + " : " + mStartDragX + " : " + (x - mStartDragX));
mStartDragX = 0;
setCurrentItem(getCurrentItem() + 1, true);
return true;
}
break;
}
} else {
mStartDragX = 0;
}
swapXY(event);
return !disableSwipe && super.onTouchEvent(swapXY(event));
}
return false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = !disableSwipe && super.onInterceptTouchEvent(swapXY(event));
if ((event.getAction() & MotionEventCompat.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
x = event.getX();
}
swapXY(event); // return touch coordinates to original reference frame for any child views
return intercepted;
}
public void disableScroll(Boolean disableSwipe) {
//When disable = true not work the scroll and when disble = false work the scroll
this.disableSwipe = disableSwipe;
Log.d(TAG, "disableSwipe " + disableSwipe);
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
private class VerticalPageTransformer implements PageTransformer {
private static final float MIN_SCALE = 0.75f;
#Override
public void transformPage(#NonNull View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(-position * view.getWidth());
// set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
ScaleAnimation flipDown = new ScaleAnimation(1.0f, 1.0f, -1.0f, 0.0f, 1, 1);
flipDown.setDuration(500);
flipDown.setFillAfter(true); // If fillAfter is true, the transformation that this animation performed will persist when it is finished.
// view.startAnimation(flipDown);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
view.setScaleX(1);
view.setScaleY(1);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
}
I want to flip the screen between these Layouts From TOP & Bottom
<androidx.cardview.widget.CardView
app:cardCornerRadius="6dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true"
app:cardBackgroundColor="#color/White"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/ivImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/activity_images"
android:scaleType="fitXY" />
<LinearLayout
android:id="#+id/layoutL"
android:layout_weight="5.5"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="8dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp">
<TextView
android:id="#+id/tvTTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="4dp"
android:textStyle="bold"
android:text="#string/Topic_Title"
android:textColor="#color/Black"
android:textSize="20sp" />
<TextView
android:id="#+id/postDetails"
android:textAllCaps="false"
android:text="text"
android:textSize="12sp"
android:layout_marginStart="4dp"
android:textStyle="normal"
android:textColor="#color/Silver"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/tvTopicDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:lineSpacingExtra="2dp"
android:text="#string/invalid_email_contactno"
android:textAllCaps="false"
android:textColor="#6D6D6D"
android:textSize="15sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
I want to create a layout like a given GIF, I tried so many animations but not worked perfectly for me.
Try below solution and set yourSecondView as gone in Xml.
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final ObjectAnimator oa1 = ObjectAnimator.ofFloat(yourFirstView, "scaleY", 1f, 0f);
final ObjectAnimator oa2 = ObjectAnimator.ofFloat(yourSecondView, "scaleY", 0f, 1f);
oa1.setInterpolator(new DecelerateInterpolator());
oa1.setDuration(1000);
oa2.setInterpolator(new AccelerateDecelerateInterpolator());
oa2.setDuration(1000);
oa1.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
yourFirstView.setVisibility(View.GONE);
yourSecondView.setVisibility(View.VISIBLE);
oa2.start();
}
});
oa1.start();
}
});
Output
I hope this can help you!
I was searching for a way to display a very large scrollable image (3700x2400) at full size with ZoomIn/ZoomOut functionality.
The following question gave me a perfect solution:
Android imageView Zoom-in and Zoom-Out
package com.oryx.hanenberg;
/**
* Created by Jordy on 9-2-2017.
*/
import android.app.Activity;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class ZoomInZoomOut extends Activity implements OnTouchListener
{
private static final String TAG = "Touch";
#SuppressWarnings("unused")
private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
// These matrices will be used to scale points of the image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// The 3 states (events) which the user is trying to perform
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// these PointF objects are used to record the point(s) the user is touching
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private ImageView imageView;
private int fieldImgXY[] = new int[2];
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
imageView = (ImageView) findViewById(R.id.map);
int[] posXY = new int[2];
imageView.getLocationOnScreen(posXY);
int x = posXY[0];
int y = posXY[1];
Log.d(TAG, TAG + " " + String.valueOf(x));
Log.d(TAG, TAG + " " + String.valueOf(y));
imageView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
dumpEvent(event);
// 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
mode = DRAG;
break;
case MotionEvent.ACTION_UP: // first finger lifted
System.out.println(event.getX());
System.out.println(event.getY());
break;
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}
else if (mode == ZOOM)
{
// 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...if scale > 1 means
// zoom in...if scale < 1 means
// zoom out
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
return true; // indicate event was handled
}
/*
* --------------------------------------------------------------------------
* Method: spacing Parameters: MotionEvent Returns: float Description:
* checks the spacing between the two fingers on touch
* ----------------------------------------------------
*/
private float spacing(MotionEvent event)
{
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
/*
* --------------------------------------------------------------------------
* Method: midPoint Parameters: PointF object, MotionEvent Returns: void
* Description: calculates the midpoint between the two fingers
* ------------------------------------------------------------
*/
private void midPoint(PointF point, MotionEvent event)
{
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/** Show an event in the LogCat view, for debugging */
private void dumpEvent(MotionEvent event)
{
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE","POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP)
{
sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++)
{
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d("Touch Events ---------", sb.toString());
}
}
activity_map.xml
<LinearLayout android:orientation="vertical" 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:layout_gravity = "center_vertical|center_horizontal|center"
android:layout_weight="1"
>
<ImageView
android:id="#+id/map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/bt_587f3ef7ccafa_bt_origineel"/>
</LinearLayout>
However, I want the touch events to register the X/Y-coordinates relative to the image. Now it's creating white space around the image when I'm zooming resulting false X/Y-coordinates. The X/Y-coordinates are also of the viewport, not of the entire content. How can I accomplish this?
You can get the top left corner of your Imageview as mentioned below:
int[] posXY = new int[2];
imageView.getLocationOnScreen(posXY);
With this and the touch coordinates you can calculate the point inside the ImageView as follows:
int touchX = (int) event.getX();
int touchY = (int) event.getY();
int imageX = touchX - posXY[0]; // posXY[0] is the X coordinate
int imageY = touchY - posXY[1]; // posXY[1] is the y coordinate
I am working on a project in which user can move view with finger touch . It works but not accurate to the finger position. I am not asking the good code you have, but rather to wondering why my code make the view not fit to the finger. It's like the view have more margin about 20dp.Here's the code :
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/lyRoot"
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="com.zihadrizkyef.dragviewwithfinger.MainActivity">
<TextView
android:id="#+id/tvText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:text="Hello World!"/>
</LinearLayout>
MainActivity.java
package com.zihadrizkyef.dragviewwithfinger;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
ViewGroup lyRoot;
TextView tvText;
LinearLayout.LayoutParams layoutParams;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lyRoot = (ViewGroup)findViewById(R.id.lyRoot);
tvText = (TextView)findViewById(R.id.tvText);
layoutParams = (LinearLayout.LayoutParams)tvText.getLayoutParams();
lyRoot.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int)event.getRawX();
int y = (int)event.getRawY();
if (event.getAction() == MotionEvent.ACTION_MOVE) {
layoutParams.leftMargin = x;
layoutParams.topMargin = y;
tvText.setLayoutParams(layoutParams);
}
lyRoot.invalidate();
if (event.getAction() == MotionEvent.ACTION_UP) {
System.out.println("mouseX:"+x+" ; mouseY:"+y);
System.out.println("viewX:"+layoutParams.leftMargin+" ; viewY:"+layoutParams.topMargin);
}
return true;
}
}
You should use the dragged distance instead of the coordinates on screen.
layoutParams.leftMargin = layoutParams.leftMargin + deltaX;
layoutParams.topMargin = layoutParams.leftMargin + deltaY;
You can get the full solution from Android developers site
https://developer.android.com/training/gestures/scale.html#drag
You will have to adapt it to your needs. I adapted it a little.
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = MotionEventCompat.getActionMasked(ev);
switch (action) {
case MotionEvent.ACTION_DOWN: {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);
// Remember where we started (for dragging)
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer (for dragging)
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex =
MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);
// Calculate the distance moved
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
layoutParams.leftMargin += dx;
layoutParams.topMargin += dy;
tvText.setLayoutParams(layoutParams);
lyRoot.invalidate();
// Remember this touch position for the next move event
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 = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex);
mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex);
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
}
break;
}
}
return true;
}
I am using a FrameLayout to carry out the swipe gesture of each of my cardviews, but the cards do not always dismiss. And sometimes they just hang on the left or the right until the user swipes the card a second time.
How can I fix this?
MyFrameLayout:
public class MyFrameLayout extends FrameLayout {
private static int mWidth = 200;
MyFrameLayout touchFrameLayout;
// Constructors
// i call "initialize(context)" in all of them
private void initialize(Context context) {
setOnTouchListener(mTouchListener);
touchFrameLayout = this;
}
private float mDisplacementX;
private float mDisplacementY;
private float mInitialTx;
private boolean mTracking;
private OnTouchListener mTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mWidth = (int) touchFrameLayout.getLayoutParams().width;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mDisplacementX = event.getRawX();
mDisplacementY = event.getRawY();
mInitialTx = getTranslationX();
return true;
case MotionEvent.ACTION_MOVE:
// get the delta distance in X and Y direction
float deltaX = event.getRawX() - mDisplacementX;
float deltaY = event.getRawY() - mDisplacementY;
// updatePressedState(false);
// set the touch and cancel event
if ((Math.abs(deltaX) > ViewConfiguration.get(getContext())
.getScaledTouchSlop() * 2 && Math.abs(deltaY) < Math
.abs(deltaX) / 2)
|| mTracking) {
mTracking = true;
if (getTranslationX() <= mWidth / 2
&& getTranslationX() >= -(mWidth / 2)) {
setTranslationX(mInitialTx + deltaX);
return true;
}
}
break;
case MotionEvent.ACTION_UP:
if (mTracking) {
mTracking = false;
float currentTranslateX = getTranslationX();
if (currentTranslateX > (mWidth/10)) {
rightSwipe();
} else if (currentTranslateX < -(mWidth*10)) {
leftSwipe();
}
// comment this line if you don't want your frame layout to
// take its original position after releasing the touch
setTranslationX(0);
return true;
} else {
// handle click event
setTranslationX(0);
}
break;
}
return false;
}
};
private void rightSwipe() {
Toast.makeText(this.getContext(), "Swipe to the right",
Toast.LENGTH_SHORT).show();
DeleteCard();
}
private void leftSwipe() {
Toast.makeText(this.getContext(), "Swipe to the left",
Toast.LENGTH_SHORT).show();
DeleteCard();
}
}
Xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.testing.android.layout.MyFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/taskViewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardElevation="8dp"
app:cardPreventCornerOverlap="false"
card_view:cardCornerRadius="8dp">
</android.support.v7.widget.CardView>
</com.example.testing.android.layout.MyFrameLayout>
</RelativeLayout>
I adapted romannurik's Android-SwipeToDismiss to do exactly that.
The code is on github with a woking sample application, and consists of:
A subclass of RecyclerView.OnItemTouchListener that listens to touch events and detects when an item is being swiped, animating it accordingly.
A SwipeListener that is called in order to know if an item can be dismissed and called again when items are dismissed.
To use it, copy the class SwipeableRecyclerViewTouchListener to your project and use it like this
mAdapter = new CardViewAdapter(mItems);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mAdapter);
SwipeableRecyclerViewTouchListener swipeTouchListener =
new SwipeableRecyclerViewTouchListener(mRecyclerView,
new SwipeableRecyclerViewTouchListener.SwipeListener() {
#Override
public boolean canSwipe(int position) {
return true;
}
#Override
public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
mItems.remove(position);
mAdapter.notifyItemRemoved(position);
}
mAdapter.notifyDataSetChanged();
}
#Override
public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
mItems.remove(position);
mAdapter.notifyItemRemoved(position);
}
mAdapter.notifyDataSetChanged();
}
});
mRecyclerView.addOnItemTouchListener(swipeTouchListener);
}
This can also be useful : http://www.getgoodcode.com/2013/06/swipe-to-dismiss-google-style/
Hope it works for you !