اشاره لمسی زمانی اتفاق میافتد که کاربر یک یا چند انگشت خود را روی صفحه لمسی قرار میدهد و برنامه شما این الگوی لمس را بهعنوان اشاره تفسیر میکند. تشخیص اشاره دو مرحله دارد:
- درحال جمعآوری دادههای رویداد لمسی.
- تفسیر دادهها برای تعیین اینکه آیا با معیارهای اشارههایی که برنامهتان پشتیبانی میکند مطابقت دارد یا نه.
کلاسهای AndroidX
مثالهای این سند از کلاسهای
GestureDetectorCompat
و
MotionEventCompat
استفاده میکنند. این کلاسها در AndroidX
Library قرار دارند. درصورت امکان از کلاسهای 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 تشخیص حرکات رایج را بدون نیاز به پردازش رویدادهای لمسی جداگانه برایتان آسانتر میکند. این موضوع در تشخیص اشارهها بیشتر بحث شده است.
رویدادهای لمسی را برای نمای تکی ضبط کنید
بهعنوان جایگزین onTouchEvent()، میتوانید بااستفاده از روش setOnTouchListener()،
View.OnTouchListener
شیئی را به هر 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; } });
مراقب باشید شنوندهای ایجاد نکنید که false را برای رویداد ACTION_DOWN برگرداند.
اگر این کار را انجام دهید، شنونده برای توالی بعدی
ACTION_MOVE و
ACTION_UP
رویدادها فراخوانده نمیشود. دلیلش این است که ACTION_DOWN نقطه شروع همه رویدادهای
لمسی است.
اگر نمای سفارشی ایجاد میکنید، میتوانید
onTouchEvent() را، همانطور که قبلاً توضیح داده شد، ملغی کنید.
تشخیص اشارهها
Android کلاس GestureDetector را برای تشخیص
اشارههای رایج ارائه میدهد. برخیاز اشارههایی که پشتیبانی میکند عبارتاند از
onDown()،
onLongPress()،
و
onFling().
میتوانید از GestureDetector در ارتباط با
روش onTouchEvent() که قبلاً شرح داده شد استفاده کنید.
شناسایی همه اشارههای پشتیبانیشده
وقتی شیء GestureDetectorCompat را نمونهسازی میکنید، یکی از
پارامترهایی که میگیرد کلاسی است که
واسط GestureDetector.OnGestureListener
را پیادهسازی میکند. وقتی رویداد لمس خاصی روی میدهد، GestureDetector.OnGestureListener به کاربران اطلاع میدهد. برای اینکه GestureDetector شیء شما بتواند رویدادها را دریافت کند، روش onTouchEvent() نمای یا فعالیت را ملغی کنید و همه رویدادهای مشاهدهشده را به نمونه آشکارساز ارسال کنید.
در گزیده زیر، مقدار برگشتی true از
روشهای on<TouchEvent> فردی نشان میدهد که
رویداد لمسی مدیریت شده است. مقدار برگشتی false رویدادها را به پایین
پشته نما منتقل میکند تا زمانی که لمس با موفقیت مدیریت شود.
اگر قطعه کد زیر را در برنامه آزمایشی اجرا کنید، میتوانید متوجه شوید که
کنشها چگونه هنگام تعامل با صفحه لمسی راهاندازی میشوند و
محتوای 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() شروع میشود. اگر از onDown() به false برگردید، همانطور که GestureDetector.SimpleOnGestureListener بهطور پیشفرض این کار را انجام میدهد، سیستم فرض میکند که میخواهید بقیه اشاره را نادیده بگیرید و روشهای دیگر GestureDetector.OnGestureListener فراخوانی نمیشوند. این کار ممکن است باعث بروز مشکلات
غیرمنتظره در برنامهتان شود. فقط درصورتی false را از
onDown() برگردانید که واقعاً بخواهید کل اشاره را نادیده بگیرید.
کاتلین
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; } } }