Here's a test project which shows the issue dropbox link:
https://www.dropbox.com/sh/8s3v9ydcj6jvpl8/AACZ2VRP2N9R1ec7pxrsAn0ga?dl=0
This is a continuation of the question I had here which was answered but now I am asking about the sensitivity/conflict of onTouch:
Android CardView with ListView inside - onTouchListener on CardView not working
I have a cardview with a listview inside. I will need the scroll and click item in list view to work too and I want to be able to move the entire cardview using the ontouchlistener too.
I have set a onTouchListener on the cardview but it doesn't work properly as the listview scroll is conflicting with the cardview movement.
I have been able to get similar thing to work on iOS perfectly so should be doable on android too.
Code:
Put this in build.gradle:
compile 'com.android.support:cardview-v7:22.0+'
MainActivity:
import android.animation.Animator;
import android.graphics.PointF;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView mylistview;
private CustomCardView mycardview;
PointF lastLocation;
static final int REFRESH_RATE = 10; //or 20, or 5, or 30, whatever works best
int counter = 0;
PointF viewCenter;
PointF cardOriginalLocation;
boolean checkIfPanning;
RelativeLayout layout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (RelativeLayout)findViewById(R.id.layout);
mycardview = (CustomCardView)findViewById(R.id.mycardview);
mylistview = (ListView) findViewById(R.id.myListView);
List<String> your_array_list = new ArrayList<String>();
your_array_list.add("foo");
your_array_list.add("bar");
your_array_list.add("foo");
your_array_list.add("bar");
your_array_list.add("foo");
your_array_list.add("bar");
your_array_list.add("foo");
your_array_list.add("bar");
your_array_list.add("foo");
your_array_list.add("bar");
your_array_list.add("foo");
your_array_list.add("bar");
your_array_list.add("foo");
your_array_list.add("bar");
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,your_array_list );
mylistview.setAdapter(arrayAdapter);
mycardview.setCardElevation(20);
mycardview.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mycardview.getViewTreeObserver().removeOnGlobalLayoutListener(this);
cardOriginalLocation = new PointF(mycardview.getX(), mycardview.getY());
viewCenter = new PointF(layout.getWidth() / 2, layout.getHeight() / 2);
}
});
View.OnTouchListener onTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(mylistview!=null){
//Route all touch event to listview without logic
System.out.println("AAAAAA Touched list");
mylistview.onTouchEvent(event);
}
if (event.getAction()==MotionEvent.ACTION_DOWN){
System.out.println("ACTION_DOWN");
checkIfPanning=true;
lastLocation = new PointF(event.getRawX(),event.getRawY());
return true;
} else if (checkIfPanning && event.getAction()==MotionEvent.ACTION_MOVE/* && (getFrontCard().getX() - (lastLocation.x - event.getRawX()))<=10*/){
System.out.println("ACTION_MOVE");
counter += 1;
if((REFRESH_RATE % counter) == 0) {
float newx = mycardview.getX() - (lastLocation.x - event.getRawX());
float newy = mycardview.getY() - (lastLocation.y - event.getRawY());
mycardview.setX(newx);
mycardview.setY(newy);
lastLocation.set(event.getRawX(), event.getRawY());
float completedPercent = Math.min(((mycardview.getX() + mycardview.getWidth() / 2) - viewCenter.x) / viewCenter.x, 1);
float angle = (completedPercent*15);
mycardview.setRotation(angle);
}
counter=0;
return true;
} else if (event.getAction()==MotionEvent.ACTION_UP){
System.out.println("ACTION_UP");
checkIfPanning=false;
float displaceentFromCenterX = ((mycardview.getX()+mycardview.getWidth()/2) - viewCenter.x);
if (Math.abs(displaceentFromCenterX)>225){
float toMove;
if (displaceentFromCenterX>0){
toMove = layout.getWidth()+mycardview.getHeight();
} else {
toMove = -mycardview.getWidth()-mycardview.getHeight();
}
mycardview.animate().rotationBy(30).translationX(toMove).setDuration(100).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
System.out.println("onAnimationStart");
}
@Override
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
System.out.println("DONNNNNE");
mycardview.setX(cardOriginalLocation.x);
mycardview.setY(cardOriginalLocation.y);
mycardview.setRotation(0);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
} else {
mycardview.animate().rotation(0).translationX(0).translationY(0).setDuration(100).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
return true;
} else {
checkIfPanning=false;
if(mylistview!=null){
//Route all touch event to listview without logic
System.out.println("BBBBB Touched list");
mylistview.onTouchEvent(event);
return true;
}
}
return true;
}
};
mycardview.setOnTouchListener(onTouchListener);
}
}
Both the cardview onTouch listener and the listview do detect the touch now. However, when I try to move the cardview, the listview keeps trying to scroll around. And when I try to scroll on the list, the card moves intead.
I understand why this is happening. Basically the onTouch listener seems to be conflicting the cardview movement with listview scroll but I am not sure how to figure out in code on whether I am trying to scroll or move the cardview around.
XML for MainActivity:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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: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.pranapps.testontouch.MainActivity"
android:id="@+id/layout"
>
<com.pranapps.testontouch.CustomCardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/mycardview"
card_view:cardUseCompatPadding="true">
<ListView
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:id="@+id/myListView"
android:dividerHeight="0.2dp"
android:overScrollMode="always"
android:smoothScrollbar="true"
android:groupIndicator="@null"
></ListView>
</com.pranapps.testontouch.CustomCardView>
</RelativeLayout>
CustomCardView code:
package com.pranapps.testontouch;
import android.content.Context;
import android.support.v7.widget.CardView;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* Created by pranoychowdhury on 5/9/16.
*/
public class CustomCardView extends CardView {
public CustomCardView(Context context) {
super(context);
}
public CustomCardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
/*
* This method determines whether we want to intercept the motion.
* If we return true, onTouchEvent will be called.
*/
System.out.println("Touched custom from card");
return true;
}
}
Please help with suggestions to try!
Thanks!
Edit: here's a video of how it works on iOS. I can scroll on the listview. Panning left or right makes the card move.
<a href="https://www.dropbox.com/s/5dm52vtjb1xgcl5/iOS.mov?dl=0" rel="nofollow