Reputation: 3971
I am using an onTouchEvent
for in my MainActivity.class
. It's working fine : if the user make a double L with the fingers, I call a fragment.
I would like to use this onTouchEvent
in an other Activity
but I think it's dirty if I copy all my code.
Now for that I have created an implement TouchListenerImpl
for that :
class TouchListenerImpl implements View.OnTouchListener {
private boolean movingDownL, movingDownR, movingLeft, movingRight, movingSuccessL, movingSuccessR = false;
private Point oldCoordsL, oldCoordsR, startPointL, startPointR = new Point(0, 0);
private boolean admin_touch = false;
private OnLTouch callback;
void setCallback(OnLTouch c) {
callback = c;
}
interface OnLTouch {
void lTouchSuccess();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("debugTouch", "onTouch");
int pIndexL = event.findPointerIndex(event.getPointerId(0));
int pIndexR = 0;
if(event.getPointerCount() > 1) pIndexR = event.findPointerIndex(event.getPointerId(1));
if(event.getPointerCount() > 1 && event.getX(pIndexL) > event.getX(pIndexR)) {
int tmp = pIndexR;
pIndexR = pIndexL;
pIndexL = tmp;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
movingDownL = true;
movingDownR = true;
movingSuccessL = false;
movingSuccessR = false;
if(event.getPointerCount() > 1) {
startPointR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
oldCoordsR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
}
startPointL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
oldCoordsL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
break;
case MotionEvent.ACTION_MOVE:
int downMinDistance = 300;
int lnrInaccuracy = 10;
int downInaccuracy = 30;
if(event.getPointerCount() > 1) {
if(!movingDownR) {
if(Math.abs(oldCoordsR.x - event.getX(pIndexR)) < downInaccuracy &&
oldCoordsR.y < event.getY(pIndexR)) break;
if(Math.abs(oldCoordsR.y - event.getY(pIndexR)) < lnrInaccuracy &&
oldCoordsR.x > event.getX(pIndexR) && !movingRight) {
movingRight = true;
startPointR = new Point(new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR)));
}
} else {
if (Math.abs(oldCoordsR.x - event.getX(pIndexR)) > downInaccuracy ||
oldCoordsR.y < event.getY(pIndexR)) {
movingDownR = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= downMinDistance){
movingDownR = false;
}
}
}
if(!movingDownL) {
if(Math.abs(oldCoordsL.x - event.getX(pIndexL)) < downInaccuracy &&
oldCoordsL.y < event.getY(pIndexL)) break;
if(Math.abs(oldCoordsL.y - event.getY(pIndexL)) < lnrInaccuracy &&
oldCoordsL.x < event.getX(pIndexL) && !movingLeft) {
movingLeft = true;
startPointL = new Point(new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL)));
}
}else {
if (Math.abs(oldCoordsL.x - event.getX(pIndexL)) > downInaccuracy ||
oldCoordsL.y > event.getY(pIndexL)) {
movingDownL = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= downMinDistance){
movingDownL = false;
}
}
int lnrMinDistance = 50;
if(movingLeft) {
if (Math.abs(oldCoordsL.y - event.getY(pIndexL)) > lnrInaccuracy ||
oldCoordsL.x > event.getX(pIndexL)) {
movingLeft = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= lnrMinDistance) {
movingLeft = false;
movingSuccessL = true;
}
}
if(movingRight) {
if (Math.abs(oldCoordsR.y - event.getY(pIndexR)) > lnrInaccuracy ||
oldCoordsR.x < event.getX(pIndexR)) {
movingRight = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= lnrMinDistance) {
movingRight = false;
movingSuccessR = true;
}
}
if(movingSuccessL && movingSuccessR) {
if (!admin_touch)
{
admin_touch = true;
if (callback != null)
callback.lTouchSuccess();
}
}
oldCoordsL = new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL));
oldCoordsR = new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR));
break;
case MotionEvent.ACTION_UP:
movingDownL = false;
movingDownR = false;
movingLeft = false;
movingRight = false;
break;
default:
return false;
}
return true;
}
private double findDistance(Point p1, Point p2) {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
}
In my Activity, I call the implement like this :
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
TouchListenerImpl imp = new TouchListenerImpl();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imp.setCallback(new TouchListenerImpl.OnLTouch() {
@Override
public void lTouchSuccess() {
Log.d("debugTouch", "WORKING !");
}
});
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("debugTouch", "onTouch");
return imp.onTouch(v, event);
}
}
The problem is I never enter in my logs. It's not working at all...
Upvotes: 14
Views: 1089
Reputation: 2691
You need to set the listener in the activity's root, and you need to keep attention to your view hierarchy. Touch events can be consumed by other views in the hierarchy, which can be the reason you aren't getting any logs.
I tested your listener with minimal changes, and I got the logs. I got the double L touch once.
public class TouchListenerImpl implements View.OnTouchListener {
private boolean movingDownL, movingDownR, movingLeft, movingRight, movingSuccessL, movingSuccessR = false;
private Point oldCoordsL, oldCoordsR, startPointL, startPointR = new Point(0, 0);
private boolean admin_touch = false;
private OnLTouch callback;
public TouchListenerImpl(OnLTouch callback){
setCallback(callback);
}
void setCallback(OnLTouch c) {
callback = c;
}
public interface OnLTouch {
void lTouchSuccess();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("debugTouch", "onTouch");
int pIndexL = event.findPointerIndex(event.getPointerId(0));
int pIndexR = 0;
if(event.getPointerCount() > 1) pIndexR = event.findPointerIndex(event.getPointerId(1));
if(event.getPointerCount() > 1 && event.getX(pIndexL) > event.getX(pIndexR)) {
int tmp = pIndexR;
pIndexR = pIndexL;
pIndexL = tmp;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
movingDownL = true;
movingDownR = true;
movingSuccessL = false;
movingSuccessR = false;
if(event.getPointerCount() > 1) {
startPointR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
oldCoordsR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
}
startPointL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
oldCoordsL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
break;
case MotionEvent.ACTION_MOVE:
int downMinDistance = 300;
int lnrInaccuracy = 10;
int downInaccuracy = 30;
if(event.getPointerCount() > 1) {
if(!movingDownR) {
if(Math.abs(oldCoordsR.x - event.getX(pIndexR)) < downInaccuracy &&
oldCoordsR.y < event.getY(pIndexR)) break;
if(Math.abs(oldCoordsR.y - event.getY(pIndexR)) < lnrInaccuracy &&
oldCoordsR.x > event.getX(pIndexR) && !movingRight) {
movingRight = true;
startPointR = new Point(new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR)));
}
} else {
if (Math.abs(oldCoordsR.x - event.getX(pIndexR)) > downInaccuracy ||
oldCoordsR.y < event.getY(pIndexR)) {
movingDownR = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= downMinDistance){
movingDownR = false;
}
}
}
if(!movingDownL) {
if(Math.abs(oldCoordsL.x - event.getX(pIndexL)) < downInaccuracy &&
oldCoordsL.y < event.getY(pIndexL)) break;
if(Math.abs(oldCoordsL.y - event.getY(pIndexL)) < lnrInaccuracy &&
oldCoordsL.x < event.getX(pIndexL) && !movingLeft) {
movingLeft = true;
startPointL = new Point(new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL)));
}
}else {
if (Math.abs(oldCoordsL.x - event.getX(pIndexL)) > downInaccuracy ||
oldCoordsL.y > event.getY(pIndexL)) {
movingDownL = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= downMinDistance){
movingDownL = false;
}
}
int lnrMinDistance = 50;
if(movingLeft) {
if (Math.abs(oldCoordsL.y - event.getY(pIndexL)) > lnrInaccuracy ||
oldCoordsL.x > event.getX(pIndexL)) {
movingLeft = false;
break;
} else if(findDistance(startPointL,
new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= lnrMinDistance) {
movingLeft = false;
movingSuccessL = true;
}
}
if(movingRight) {
if (Math.abs(oldCoordsR.y - event.getY(pIndexR)) > lnrInaccuracy ||
oldCoordsR.x < event.getX(pIndexR)) {
movingRight = false;
break;
} else if(findDistance(startPointR,
new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= lnrMinDistance) {
movingRight = false;
movingSuccessR = true;
}
}
if(movingSuccessL && movingSuccessR) {
if (!admin_touch)
{
admin_touch = true;
if (callback != null)
callback.lTouchSuccess();
}
}
oldCoordsL = new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL));
oldCoordsR = new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR));
break;
case MotionEvent.ACTION_UP:
movingDownL = false;
movingDownR = false;
movingLeft = false;
movingRight = false;
break;
default:
return false;
}
return true;
}
private double findDistance(Point p1, Point p2) {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
}
And the use of that:
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.activity_splash);
layout.setOnTouchListener(new TouchListenerImpl(new TouchListenerImpl.OnLTouch() {
@Override
public void lTouchSuccess() {
Toast.makeText(getThis(), "L touched!", Toast.LENGTH_SHORT).show();
}
}));
}
public AppCompatActivity getThis(){
return this;
}
}
Like I said before, the reason you aren't getting any logs may be your hierarchy. Make sure your touch events aren't being consumed by other views on top of yours. To be in the safest side, you should use a FrameLayout as the root element for this kind of behavior, and a boolean variable which allows you to decide if the L listener should be used or not.
Check this for further reference: https://github.com/fcopardo/EnhancedMapView If you check the EnhancedMapView file, you'll find this:
public void setOnEnhancedCameraChangeListener(OnEnhancedCameraChangeListener listener){
if(map!=null){
map.setOnCameraChangeListener(camera -> {
if(!isContentTouched() && !isCaptureTouches()){
listener.onCameraChange(camera);
}
});
}
}
This is very similar to what you are doing. I suggest you to use a similar approach, a frame layout subclass implementing your L touch listener, and then, use such layout as the root class for your views and activities. Let me know if this helps.
Upvotes: 0
Reputation: 2335
You could use @DrilonBlakqori solution with little modification.
Make a separate class containing common code but use a callback to make View
visible.
class TouchListenerImpl implements OnTouchListener {
private OnLTouch callback;
@Override
public boolean onTouch(View v, MotionEvent event) {
// all your code
...
if (callback != null)
callback.lTouchSuccess();
...
}
void setCallback(OnLTouch c) {
callback = c;
}
interface OnLTouch {
void lTouchSuccess();
}
}
In your MainActivity
, create a new instance of TouchListenerImpl
and setCallback
like
TouchListenerImpl imp = new TouchListenerImpl();
imp.setCallback(new OnLTouch() {
public void lTouchSuccess() {
frameLayoutAdmin.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction()
.replace(R.id.framelayout_admin,new AdminLoginFragment())
.commit();
img_close.setVisibility(View.VISIBLE);
}
});
And in MainActivity
, the View
on which you want to detect the double L on that View
set this listener on that View
.
view.setOnTouchListener(imp);
I assume you want to detect double L on the main layout. For that you can do
findViewById(R.id.mylayout).setOnTouchListener(imp);
I hope this solves your problem.
Upvotes: 6
Reputation: 410
You could create a super class Activity, override onTouchEvent there and extend from it. Something like this:
public abstract class BaseActivity extends AppCompatActivity {
@Override
public boolean onTouchEvent(MotionEvent event) {
// Your implementation.
}
}
And then your MainActivity:
public class MainActivity extends BaseActivity {
}
Upvotes: 2
Reputation: 2826
Copy all your code together with the field variables to a class which implements the OnTouchListener
. Then just pass a new TouchListenerImpl
whenever you need it.
class TouchListenerImpl implements OnTouchListener {
// your field variables
@Override
public boolean onTouch(View v, MotionEvent event) {
// all your code
return false;
}
// getters for the variables that you need
}
Upvotes: 1
Reputation: 112
You can make a superclass that extends activity and implements your onTouchEvent method and in any activity you want to use the onTouchEvent method extend your superclass. MainActivity would have to extend it as well. Or just extend MainActivity in other activities where you want to use your onTouchEvent method.
Upvotes: 1