* Android * Detects pinch-in / pinch-out

Introduction

Hello. This time, I will try to detect the pinch operation on Android. I will explain how to distinguish between pinch-in and pinch-out.

Premise

The development environment is as follows. *Android Studio 4.0.1 *targetSdkVersion 28 *Google Nexus 5x

Discrimination between pinch-in and pinch-out

Use `` `ScaleGestureDetectorto detect the pinch operation. In the first argument, specify Context, and in the second argument, specify the object of the class that implements theOnScaleGestureListener``` interface. This time, we will implement the interface using an anonymous class.

this.scaleGestureDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.OnScaleGestureListener() {
    //Called repeatedly during pinch operation
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        return true;
    }
    //Called when the pinch operation is started
    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }
    //Called when the pinch operation is finished
    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
    }
});

Next, prepare a onTouchEvent method so that `` `ScaleGestureDetector.onTouchEventis called when theonTouchEvent``` method is called, so that you can pinch the operation. It can be detected.

@Override
public boolean onTouchEvent(MotionEvent motionEvent){
    this.scaleGestureDetector.onTouchEvent(motionEvent);
    return true;

If a pinch operation can be detected, then pinch-in / pinch-out is determined. In the pinch operation, two fingers are touching the screen. Since `getCurrentSpan ()` is prepared as a method to measure the distance between fingers, use it. Pinch-in / pinch-out can be determined by using the change in the distance between the fingers. In order to prevent erroneous judgment of pinch-in / pinch-out, the distance x between fingers is specified as a threshold value, and pinch-in / pinch-out judgment is performed when the distance changes by x or more.

@Override
public boolean onScale(ScaleGestureDetector detector) {          
    distance_current = detector.getCurrentSpan();
    return true;
}

Accuracy of the distance between fingers during pinch operation

Use `getCurrentSpan ()` to get the distance between fingers during a pinch operation. The acquired finger-to-finger distance should be smaller than the diagonal length of the smartphone screen. In order to remove the wrong distance if it is acquired, only the distance smaller than the diagonal length of the smartphone is used as the distance between the fingers. Here, the diagonal length is calculated from the screen area excluding the navigation bar. To get the diagonal length of the screen, do the following.

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Point size = new Point();
Display disp = wm.getDefaultDisplay();
disp.getSize(size);
screen_width = this.size.x;
screen_height = this.size.y;
//Find the length of the diagonal
int screen_diagonal = (int) Math.sqrt((int)(Math.pow(screen_width, 2)) + (int)(Math.pow(screen_height, 2)));

Sample code

AndroidManifest.xml


?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java


package com.example.myapplication3;

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.WindowManager;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private ScaleGestureDetector scaleGestureDetector;
    private long time_elapsed;
    private long time_start;
    private long time_current;
    private float distance_current;
    private float distance_start;
    private Boolean flg_pinch_out;
    private Boolean flg_pinch_in;
    private WindowManager wm;
    private Display disp;
    private Point size;
    private int screen_width;
    private int screen_height;
    //Diagonal length of the screen
    private int screen_diagonal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        this.size = new Point();
        this.disp = wm.getDefaultDisplay();
        this.disp.getSize(size);
        screen_width = this.size.x;
        screen_height = this.size.y;
        //Find the length of the diagonal
        screen_diagonal = (int) Math.sqrt((int)(Math.pow(screen_width, 2)) + (int)(Math.pow(screen_height, 2)));
        this.scaleGestureDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.OnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                time_current = detector.getEventTime();
                time_elapsed = time_current - time_start;
                if (time_elapsed >= 0.5){
                    distance_current = detector.getCurrentSpan();
                    if (distance_start == 0){
                        distance_start = distance_current;
                    }
                    flg_pinch_out = (distance_current - distance_start) > 300;
                    flg_pinch_in = (distance_start - distance_current) > 300;
                    if (flg_pinch_out){
                        Toast.makeText(getApplicationContext(), "Pinch out", Toast.LENGTH_LONG).show();
                        time_start = time_current;
                        distance_start = distance_current;
                    }
                    else if (flg_pinch_in){
                        Toast.makeText(getApplicationContext(), "Pinch in", Toast.LENGTH_LONG).show();
                        time_start = time_current;
                        distance_start = distance_current;
                    }
                    else {
                        //pass
                    }
                }
                return true;
            }


            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                distance_start = detector.getEventTime();
                if (distance_start > screen_diagonal){
                    distance_start = 0;
                }
                time_start = detector.getEventTime();
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent motionEvent){
        this.scaleGestureDetector.onTouchEvent(motionEvent);
        return true;
    }
}

Recommended Posts

* Android * Detects pinch-in / pinch-out