Jéwôm'
Jéwôm'

Reputation: 3971

Using the same onTouchEvent in various Activity

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

Answers (5)

Fco P.
Fco P.

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

Shreyash S Sarnayak
Shreyash S Sarnayak

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

cpienovi
cpienovi

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

Drilon Blakqori
Drilon Blakqori

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

SBC
SBC

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

Related Questions