ژست های رایج را تشخیص دهید

روش Compose را امتحان کنید
Jetpack Compose جعبه ابزار UI توصیه شده برای اندروید است. با نحوه استفاده از لمس و ورودی در Compose آشنا شوید.

یک حرکت لمسی زمانی اتفاق می‌افتد که کاربر یک یا چند انگشت خود را روی صفحه لمسی قرار می‌دهد و برنامه شما این الگوی لمس را به عنوان یک حرکت تفسیر می‌کند. دو مرحله برای تشخیص ژست وجود دارد:

  1. در حال جمع‌آوری داده‌های رویداد لمسی.
  2. تفسیر داده ها برای تعیین اینکه آیا با معیارهای حرکاتی که برنامه شما پشتیبانی می کند مطابقت دارد یا خیر.

کلاس های اندروید ایکس

مثال‌های این سند از کلاس‌های GestureDetectorCompat و MotionEventCompat استفاده می‌کنند. این کلاس ها در کتابخانه AndroidX هستند. در صورت امکان از کلاس های AndroidX برای ارائه سازگاری با دستگاه های قبلی استفاده کنید. MotionEventCompat جایگزینی برای کلاس MotionEvent نیست . در عوض، روش‌های ابزار ثابتی را ارائه می‌کند که شی MotionEvent خود را برای دریافت اکشن مرتبط با آن رویداد به آن پاس می‌دهید.

داده ها را جمع آوری کنید

هنگامی که یک کاربر یک یا چند انگشت خود را روی صفحه قرار می‌دهد، این کار باعث می‌شود که در نمائی که رویدادهای لمسی را دریافت می‌کند، روی onTouchEvent() پاسخ تماس بگیرد. برای هر دنباله ای از رویدادهای لمسی - مانند موقعیت، فشار، اندازه، و اضافه کردن یک انگشت دیگر - که به عنوان یک حرکت مشخص می شود، onTouchEvent() چندین بار شلیک می شود.

ژست زمانی شروع می شود که کاربر برای اولین بار صفحه را لمس می کند، تا زمانی که سیستم موقعیت انگشت یا انگشتان کاربر را ردیابی می کند ادامه می یابد و با ثبت آخرین رویداد خروج آخرین انگشت کاربر از صفحه به پایان می رسد. در طول این تعامل، MotionEvent ارائه شده به onTouchEvent() جزئیات هر تعامل را ارائه می دهد. برنامه شما می‌تواند از داده‌های ارائه‌شده توسط MotionEvent استفاده کند تا تشخیص دهد آیا حرکتی که برایش مهم است رخ می‌دهد یا خیر.

از رویدادهای لمسی برای یک فعالیت یا نمایش عکس بگیرید

برای رهگیری رویدادهای لمسی در یک Activity یا View ، پاسخ تماس onTouchEvent() لغو کنید.

قطعه کد زیر از getAction() برای استخراج عملی که کاربر از پارامتر event انجام می دهد استفاده می کند. این داده‌های خامی را به شما می‌دهد که برای تعیین اینکه آیا حرکتی که برایتان مهم است رخ می‌دهد یا خیر.

کاتلین

class MainActivity : Activity() {
    ...
    // This example shows an Activity. You can use the same approach if you are 
    // subclassing a View.
    override fun onTouchEvent(event: MotionEvent): Boolean {
        return when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d(DEBUG_TAG, "Action was DOWN")
                true
            }
            MotionEvent.ACTION_MOVE -> {
                Log.d(DEBUG_TAG, "Action was MOVE")
                true
            }
            MotionEvent.ACTION_UP -> {
                Log.d(DEBUG_TAG, "Action was UP")
                true
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.d(DEBUG_TAG, "Action was CANCEL")
                true
            }
            MotionEvent.ACTION_OUTSIDE -> {
                Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element")
                true
            }
            else -> super.onTouchEvent(event)
        }
    }
}

جاوا

public class MainActivity extends Activity {
...
// This example shows an Activity. You can use the same approach if you are
// subclassing a View.
@Override
public boolean onTouchEvent(MotionEvent event){
    switch(event.getAction()) {
        case (MotionEvent.ACTION_DOWN) :
            Log.d(DEBUG_TAG,"Action was DOWN");
            return true;
        case (MotionEvent.ACTION_MOVE) :
            Log.d(DEBUG_TAG,"Action was MOVE");
            return true;
        case (MotionEvent.ACTION_UP) :
            Log.d(DEBUG_TAG,"Action was UP");
            return true;
        case (MotionEvent.ACTION_CANCEL) :
            Log.d(DEBUG_TAG,"Action was CANCEL");
            return true;
        case (MotionEvent.ACTION_OUTSIDE) :
            Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element");
            return true;
        default :
            return super.onTouchEvent(event);
    }
}

این کد با ضربه زدن، لمس و نگه داشتن و کشیدن کاربر، پیام هایی مانند زیر را در Logcat تولید می کند:

GESTURES D   Action was DOWN
GESTURES D   Action was UP
GESTURES D   Action was MOVE

برای ژست‌های سفارشی، می‌توانید پردازش خود را روی این رویدادها انجام دهید تا تعیین کنید آیا آنها نشان‌دهنده حرکتی هستند که باید انجام دهید. با این حال، اگر برنامه شما از حرکات متداول مانند دو ضربه سریع، لمس و نگه داشتن، پرت کردن و غیره استفاده می کند، می توانید از کلاس GestureDetector استفاده کنید. GestureDetector تشخیص حرکات معمول را بدون پردازش رویدادهای لمسی فردی برای شما آسان‌تر می‌کند. این بیشتر در Detect gestures مورد بحث قرار گرفته است.

رویدادهای لمسی را برای یک نمای واحد ثبت کنید

به عنوان جایگزینی برای onTouchEvent() ، می توانید یک شی View.OnTouchListener را با استفاده از متد setOnTouchListener() به هر شی View متصل کنید. این کار امکان گوش دادن به رویدادهای لمسی را بدون طبقه‌بندی یک View موجود، همانطور که در مثال زیر نشان داده شده است:

کاتلین

findViewById<View>(R.id.my_view).setOnTouchListener { v, event ->
    // Respond to touch events.
    true
}

جاوا

View myView = findViewById(R.id.my_view);
myView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        // Respond to touch events.
        return true;
    }
});

مراقب ایجاد شنونده ای باشید که برای رویداد ACTION_DOWN false را برمی گرداند. اگر این کار را انجام دهید، شنونده برای توالی رویدادهای بعدی ACTION_MOVE و ACTION_UP فراخوانی نمی شود. این به این دلیل است که ACTION_DOWN نقطه شروع همه رویدادهای لمسی است.

اگر یک نمای سفارشی ایجاد می‌کنید، می‌توانید onTouchEvent() همانطور که قبلا توضیح داده شد لغو کنید.

تشخیص حرکات

اندروید کلاس GestureDetector را برای تشخیص ژست های متداول ارائه می دهد. برخی از ژست‌هایی که پشتیبانی می‌کند عبارتند از onDown() ، onLongPress() و onFling() . می توانید از GestureDetector در ارتباط با متد onTouchEvent() که قبلا توضیح داده شد استفاده کنید.

همه حرکات پشتیبانی شده را شناسایی کنید

وقتی یک شی GestureDetectorCompat نمونه سازی می کنید، یکی از پارامترهایی که می گیرد کلاسی است که رابط GestureDetector.OnGestureListener را پیاده سازی می کند. GestureDetector.OnGestureListener هنگامی که یک رویداد لمسی خاص رخ می دهد به کاربران اطلاع می دهد. برای اینکه آبجکت GestureDetector شما بتواند رویدادها را دریافت کند، روش onTouchEvent() view یا اکتیویتی را لغو کنید و همه رویدادهای مشاهده شده را به نمونه آشکارساز منتقل کنید.

در قطعه زیر، مقدار بازگشتی true از فردی on <TouchEvent> نشان می‌دهد که رویداد لمسی مدیریت می‌شود. مقدار بازگشتی false رویدادها را از طریق پشته view به پایین منتقل می کند تا زمانی که لمس با موفقیت انجام شود.

اگر قطعه زیر را در یک برنامه آزمایشی اجرا کنید، می توانید احساس کنید که هنگام تعامل با صفحه لمسی چگونه اقدامات انجام می شود و محتوای MotionEvent برای هر رویداد لمسی چیست. سپس می بینید که چه مقدار داده برای تعاملات ساده تولید می شود.

کاتلین

private const val DEBUG_TAG = "Gestures"

class MainActivity :
        Activity(),
        GestureDetector.OnGestureListener,
        GestureDetector.OnDoubleTapListener {

    private lateinit var mDetector: GestureDetectorCompat

    // Called when the activity is first created.
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Instantiate the gesture detector with the
        // application context and an implementation of
        // GestureDetector.OnGestureListener.
        mDetector = GestureDetectorCompat(this, this)
        // Set the gesture detector as the double-tap
        // listener.
        mDetector.setOnDoubleTapListener(this)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return if (mDetector.onTouchEvent(event)) {
            true
        } else {
            super.onTouchEvent(event)
        }
    }

    override fun onDown(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDown: $event")
        return true
    }

    override fun onFling(
            event1: MotionEvent,
            event2: MotionEvent,
            velocityX: Float,
            velocityY: Float
    ): Boolean {
        Log.d(DEBUG_TAG, "onFling: $event1 $event2")
        return true
    }

    override fun onLongPress(event: MotionEvent) {
        Log.d(DEBUG_TAG, "onLongPress: $event")
    }

    override fun onScroll(
            event1: MotionEvent,
            event2: MotionEvent,
            distanceX: Float,
            distanceY: Float
    ): Boolean {
        Log.d(DEBUG_TAG, "onScroll: $event1 $event2")
        return true
    }

    override fun onShowPress(event: MotionEvent) {
        Log.d(DEBUG_TAG, "onShowPress: $event")
    }

    override fun onSingleTapUp(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onSingleTapUp: $event")
        return true
    }

    override fun onDoubleTap(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDoubleTap: $event")
        return true
    }

    override fun onDoubleTapEvent(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDoubleTapEvent: $event")
        return true
    }

    override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event")
        return true
    }

}

جاوا

public class MainActivity extends Activity implements
        GestureDetector.OnGestureListener,
        GestureDetector.OnDoubleTapListener{

    private static final String DEBUG_TAG = "Gestures";
    private GestureDetectorCompat mDetector;

    // Called when the activity is first created.
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Instantiate the gesture detector with the
        // application context and an implementation of
        // GestureDetector.OnGestureListener.
        mDetector = new GestureDetectorCompat(this,this);
        // Set the gesture detector as the double-tap
        // listener.
        mDetector.setOnDoubleTapListener(this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        if (this.mDetector.onTouchEvent(event)) {
            return true;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent event) {
        Log.d(DEBUG_TAG,"onDown: " + event.toString());
        return true;
    }

    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2,
            float velocityX, float velocityY) {
        Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
        return true;
    }

    @Override
    public void onLongPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onLongPress: " + event.toString());
    }

    @Override
    public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
            float distanceY) {
        Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString());
        return true;
    }

    @Override
    public void onShowPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onShowPress: " + event.toString());
    }

    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());
        return true;
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
        return true;
    }
}

زیر مجموعه ای از حرکات پشتیبانی شده را شناسایی کنید

اگر می‌خواهید فقط چند حرکت را پردازش کنید، می‌توانید به جای اجرای رابط GestureDetector.OnGestureListener GestureDetector.SimpleOnGestureListener را گسترش دهید.

GestureDetector.SimpleOnGestureListener یک پیاده سازی برای همه متدهای on <TouchEvent> با برگرداندن false برای همه آنها فراهم می کند. این به شما امکان می دهد فقط روش هایی را که به آنها اهمیت می دهید نادیده بگیرید. به عنوان مثال، قطعه کد زیر کلاسی را ایجاد می کند که GestureDetector.SimpleOnGestureListener را گسترش می دهد و onFling() و onDown() را لغو می کند.

چه از GestureDetector.OnGestureListener یا GestureDetector.SimpleOnGestureListener استفاده کنید، این بهترین تمرین برای پیاده سازی متد onDown() است که true را برمی گرداند. این به این دلیل است که همه ژست‌ها با یک پیام onDown() شروع می‌شوند. اگر false از onDown() برگردانید، همانطور که GestureDetector.SimpleOnGestureListener به طور پیش فرض انجام می دهد، سیستم فرض می کند که می خواهید بقیه ژست را نادیده بگیرید و سایر روش های GestureDetector.OnGestureListener نامیده نمی شوند. این ممکن است باعث ایجاد مشکلات غیرمنتظره در برنامه شما شود. فقط اگر واقعاً می‌خواهید یک ژست کامل را نادیده بگیرید، از onDown() false را برگردانید.

کاتلین

private const val DEBUG_TAG = "Gestures"

class MainActivity : Activity() {

    private lateinit var mDetector: GestureDetectorCompat

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mDetector = GestureDetectorCompat(this, MyGestureListener())
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        mDetector.onTouchEvent(event)
        return super.onTouchEvent(event)
    }

    private class MyGestureListener : GestureDetector.SimpleOnGestureListener() {

        override fun onDown(event: MotionEvent): Boolean {
            Log.d(DEBUG_TAG, "onDown: $event")
            return true
        }

        override fun onFling(
                event1: MotionEvent,
                event2: MotionEvent,
                velocityX: Float,
                velocityY: Float
        ): Boolean {
            Log.d(DEBUG_TAG, "onFling: $event1 $event2")
            return true
        }
    }
}

جاوا

public class MainActivity extends Activity {

    private GestureDetectorCompat mDetector;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDetector = new GestureDetectorCompat(this, new MyGestureListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        if (this.mDetector.onTouchEvent(event)) {
              return true;
        }
        return super.onTouchEvent(event);
    }

    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        private static final String DEBUG_TAG = "Gestures";

        @Override
        public boolean onDown(MotionEvent event) {
            Log.d(DEBUG_TAG,"onDown: " + event.toString());
            return true;
        }

        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2,
                float velocityX, float velocityY) {
            Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
            return true;
        }
    }
}

منابع اضافی