در Android، بیش از یک راه برای رهگیری رویدادهای تعامل کاربر با برنامه شما وجود دارد. هنگامی که رویدادها را در رابط کاربری خود در نظر می گیرید، رویکرد این است که رویدادها را از شی View خاصی که کاربر با آن تعامل دارد، ضبط کنید. کلاس View ابزاری برای این کار فراهم می کند.
در کلاسهای View مختلف که برای نوشتن طرحبندی خود استفاده میکنید، ممکن است چندین روش تماس عمومی را مشاهده کنید که برای رویدادهای رابط کاربری مفید به نظر میرسند. این متدها توسط فریمورک اندروید زمانی فراخوانی می شوند که عمل مربوطه روی آن شیء انجام شود. به عنوان مثال، هنگامی که یک View (مانند یک دکمه) لمس می شود، متد onTouchEvent()
روی آن شی فراخوانی می شود. با این حال، برای رهگیری این، باید کلاس را گسترش دهید و متد را لغو کنید. با این حال، گسترش هر شی View به منظور رسیدگی به چنین رویدادی عملی نخواهد بود. به همین دلیل است که کلاس View همچنین شامل مجموعهای از رابطهای تودرتو با callback است که میتوانید خیلی راحتتر آنها را تعریف کنید. این رابطها که شنوندگان رویداد نامیده میشوند، بلیط شما برای ثبت تعامل کاربر با رابط کاربری شما هستند.
در حالی که معمولاً از شنوندگان رویداد برای گوش دادن به تعامل با کاربر استفاده می کنید، ممکن است زمانی فرا برسد که بخواهید یک کلاس View را گسترش دهید تا یک جزء سفارشی بسازید. شاید بخواهید کلاس Button
را گسترش دهید تا چیزی فانتزی تر بسازید. در این حالت، میتوانید با استفاده از کنترلکنندههای رویداد کلاس، رفتارهای رویداد پیشفرض را برای کلاس خود تعریف کنید.
شنوندگان رویداد
شنونده رویداد یک رابط در کلاس View
است که شامل یک متد پاسخ به تماس است. این روشها توسط چارچوب Android زمانی فراخوانی میشوند که نمایی که شنونده در آن ثبت شده است توسط تعامل کاربر با آیتم در UI فعال شود.
در رابط های شنونده رویداد، روش های پاسخ به تماس زیر گنجانده شده است:
-
onClick()
- از
View.OnClickListener
. زمانی که کاربر مورد را لمس میکند (در حالت لمسی)، یا با کلیدهای ناوبری یا گوی گوی روی آیتم تمرکز میکند و کلید "ورود" مناسب را فشار میدهد یا توپ را فشار میدهد. -
onLongClick()
- از
View.OnLongClickListener
. زمانی که کاربر مورد را لمس کرده و نگه میدارد (هنگامی که در حالت لمسی است)، یا با کلیدهای ناوبری یا گوی گوی بر روی مورد تمرکز میکند و کلید مناسب «ورود» را فشار داده و نگه میدارد یا توپ را فشار داده و نگه میدارد، نامیده میشود. برای یک ثانیه). -
onFocusChange()
- از
View.OnFocusChangeListener
. هنگامی که کاربر با استفاده از کلیدهای ناوبری یا گوی مسیریابی، روی آیتم یا از آن دور می شود، این نام خوانده می شود. -
onKey()
- از
View.OnKeyListener
. هنگامی که کاربر بر روی مورد متمرکز شده و یک کلید سخت افزاری روی دستگاه را فشار داده یا رها می کند، این نام خوانده می شود. -
onTouch()
- از
View.OnTouchListener
. زمانی که کاربر اقدامی را انجام میدهد که به عنوان یک رویداد لمسی، از جمله فشار دادن، رها کردن، یا هر حرکت حرکتی روی صفحه نمایش (در محدوده مورد) را انجام میدهد، این نام خوانده میشود. -
onCreateContextMenu()
- از
View.OnCreateContextMenuListener
. هنگامی که یک منوی زمینه در حال ساخت است (به عنوان نتیجه یک "کلیک طولانی" پایدار) این نام خوانده می شود. بحث در مورد منوهای زمینه را در راهنمای برنامهنویس منوها ببینید.
این روش ها تنها ساکنان رابط مربوطه خود هستند. برای تعریف یکی از این روش ها و مدیریت رویدادهای خود، رابط تودرتو را در Activity خود پیاده سازی کنید یا آن را به عنوان یک کلاس ناشناس تعریف کنید. سپس، یک نمونه از پیاده سازی خود را به متد View.set...Listener()
مربوطه ارسال کنید. (به عنوان مثال،
را فراخوانی کنید و پیاده سازی setOnClickListener()
OnClickListener
را به آن ارسال کنید.)
مثال زیر نحوه ثبت یک شنونده روی کلیک را برای یک دکمه نشان می دهد.
کاتلین
protected void onCreate(savedValues: Bundle) { ... val button: Button = findViewById(R.id.corky) // Register the onClick listener with the implementation above button.setOnClickListener { view -> // do something when the button is clicked } ... }
جاوا
// Create an anonymous implementation of OnClickListener private OnClickListener corkyListener = new OnClickListener() { public void onClick(View v) { // do something when the button is clicked } }; protected void onCreate(Bundle savedValues) { ... // Capture our button from layout Button button = (Button)findViewById(R.id.corky); // Register the onClick listener with the implementation above button.setOnClickListener(corkyListener); ... }
همچنین ممکن است پیاده سازی OnClickListener به عنوان بخشی از فعالیت خود راحت تر باشد. این از بار کلاس اضافی و تخصیص شی جلوگیری می کند. به عنوان مثال:
کاتلین
class ExampleActivity : Activity(), OnClickListener { protected fun onCreate(savedValues: Bundle) { val button: Button = findViewById(R.id.corky) button.setOnClickListener(this) } // Implement the OnClickListener callback fun onClick(v: View) { // do something when the button is clicked } }
جاوا
public class ExampleActivity extends Activity implements OnClickListener { protected void onCreate(Bundle savedValues) { ... Button button = (Button)findViewById(R.id.corky); button.setOnClickListener(this); } // Implement the OnClickListener callback public void onClick(View v) { // do something when the button is clicked } ... }
توجه داشته باشید که onClick()
در مثال بالا مقدار بازگشتی ندارد، اما برخی از متدهای شنونده رویداد دیگر باید یک Boolean برگردانند. دلیل بستگی به رویداد دارد. برای معدودی که این کار را انجام می دهند، در اینجا دلیل آن است:
-
- این یک Boolean برمی گرداند تا نشان دهد که آیا شما رویداد را مصرف کرده اید و نباید بیشتر انجام شود. یعنی به درستی برگردید تا نشان دهید که شما رویداد را مدیریت کرده اید و باید در اینجا متوقف شود. اگر شما آن را مدیریت نکرده اید، false را بازگردانید و/یا رویداد باید برای سایر شنوندگان کلیکی ادامه یابد.onLongClick()
-
- این یک Boolean برمی گرداند تا نشان دهد که آیا شما رویداد را مصرف کرده اید و نباید بیشتر انجام شود. یعنی به درستی برگردید تا نشان دهید که شما رویداد را مدیریت کرده اید و باید در اینجا متوقف شود. اگر آن را مدیریت نکردهاید، false را بازگردانید و/یا رویداد باید برای سایر شنوندگان کلیدی ادامه یابد.onKey()
-
- این یک Boolean برمی گرداند تا نشان دهد که آیا شنونده شما این رویداد را مصرف می کند یا خیر. نکته مهم این است که این رویداد می تواند چندین کنش داشته باشد که به دنبال یکدیگر می آیند. بنابراین، اگر هنگام دریافت رویداد down action، false را برگردانید، نشان میدهید که رویداد را مصرف نکردهاید و همچنین علاقهای به اقدامات بعدی این رویداد ندارید. بنابراین، از شما برای هیچ گونه اقدام دیگری در رویداد، مانند اشاره انگشت، یا رویداد اقدام نهایی فراخوانی نمی شود.onTouch()
به یاد داشته باشید که رویدادهای کلیدی سختافزاری همیشه به نمای فعلی در فوکوس ارائه میشوند. آنها از بالای سلسله مراتب View فرستاده می شوند و سپس به پایین تا رسیدن به مقصد مناسب ارسال می شوند. اگر نمای شما (یا فرزند نمای شما) در حال حاضر فوکوس دارد، میتوانید سفر رویداد را از طریق متد
مشاهده کنید. به عنوان جایگزینی برای ثبت رویدادهای کلیدی از طریق View خود، میتوانید تمام رویدادهای داخل Activity خود را با dispatchKeyEvent()
و onKeyDown()
دریافت کنید.onKeyUp()
همچنین، هنگامی که به ورودی متن برای برنامه خود فکر می کنید، به یاد داشته باشید که بسیاری از دستگاه ها فقط روش های ورودی نرم افزاری دارند. لازم نیست چنین روش هایی مبتنی بر کلید باشند. برخی ممکن است از ورودی صوتی، دست خط و غیره استفاده کنند. حتی اگر یک متد ورودی یک رابط صفحهکلید مانند ارائه دهد، معمولاً خانواده رویدادهای
راهاندازی نمیکند . هرگز نباید رابط کاربری ایجاد کنید که نیاز به فشار دادن کلیدهای خاصی برای کنترل داشته باشد، مگر اینکه بخواهید برنامه خود را به دستگاه هایی با صفحه کلید سخت افزاری محدود کنید. به ویژه، هنگامی که کاربر کلید بازگشت را فشار می دهد، برای تأیید اعتبار ورودی به این روش ها اعتماد نکنید. در عوض، از اقداماتی مانند onKeyDown()
IME_ACTION_DONE
استفاده کنید تا به روش ورودی سیگنال دهید که برنامه شما چگونه انتظار دارد واکنش نشان دهد، بنابراین ممکن است رابط کاربری خود را به روشی معنادار تغییر دهد. از فرضیات در مورد نحوه عملکرد یک روش ورودی نرم افزار اجتناب کنید و فقط به آن اعتماد کنید تا متن فرمت شده قبلی را به برنامه شما ارائه دهد.
توجه: اندروید ابتدا کنترلکنندههای رویداد و سپس کنترلکنندههای پیشفرض مناسب را از تعریف کلاس فراخوانی میکند. به این ترتیب، بازگرداندن true از این شنوندگان رویداد، انتشار رویداد را به سایر شنوندگان رویداد متوقف میکند و همچنین پاسخ تماس به کنترلکننده رویداد پیشفرض در View را مسدود میکند. بنابراین مطمئن باشید که می خواهید رویداد را با بازگشت true خاتمه دهید.
گردانندگان رویداد
اگر یک مؤلفه سفارشی از View ایجاد میکنید، میتوانید چندین روش پاسخ به تماس را که بهعنوان کنترلکننده رویداد پیشفرض استفاده میشوند، تعریف کنید. در سند مربوط به مؤلفههای نمای سفارشی ، برخی از تماسهای متداول مورد استفاده برای مدیریت رویداد را خواهید آموخت، از جمله:
-
- زمانی که یک رویداد کلیدی جدید رخ می دهد، فراخوانی می شود.onKeyDown(int, KeyEvent)
-
- زمانی که یک رویداد کلیدی رخ می دهد، فراخوانی می شود.onKeyUp(int, KeyEvent)
-
- هنگامی که یک رویداد حرکت گوی رخ می دهد، تماس می گیرد.onTrackballEvent(MotionEvent)
-
- زمانی که یک رویداد حرکتی صفحه نمایش لمسی رخ می دهد، فراخوانی می شود.onTouchEvent(MotionEvent)
-
- زمانی فراخوانی می شود که نمای فوکوس را به دست آورد یا از دست بدهد.onFocusChanged(boolean, int, Rect)
روشهای دیگری نیز وجود دارد که باید از آنها آگاه باشید، که بخشی از کلاس View نیستند، اما میتوانند مستقیماً بر نحوه مدیریت رویدادها تأثیر بگذارند. بنابراین، هنگام مدیریت رویدادهای پیچیده تر در یک طرح، این روش های دیگر را در نظر بگیرید:
-
- این بهActivity.dispatchTouchEvent(MotionEvent)
Activity
شما اجازه می دهد تا تمام رویدادهای لمسی را قبل از ارسال به پنجره رهگیری کند. -
- این امکان را بهViewGroup.onInterceptTouchEvent(MotionEvent)
ViewGroup
می دهد تا رویدادها را هنگام ارسال به نمایش های کودک تماشا کند. -
- این را با یک View والد صدا کنید تا نشان دهد که نباید رویدادهای لمسی را باViewParent.requestDisallowInterceptTouchEvent(boolean)
رهگیری کند.onInterceptTouchEvent(MotionEvent)
حالت لمسی
هنگامی که کاربر در حال پیمایش یک رابط کاربری با کلیدهای جهت دار یا گوی ردیابی است، لازم است به موارد عملی (مانند دکمه ها) توجه شود تا کاربر بتواند ببیند چه چیزی ورودی را می پذیرد. با این حال، اگر دستگاه دارای قابلیت لمسی باشد و کاربر با لمس آن با رابط ارتباط برقرار کند، دیگر نیازی به برجسته کردن موارد یا تمرکز روی یک نمای خاص نیست. بنابراین، حالتی برای تعامل به نام "حالت لمسی" وجود دارد.
برای یک دستگاه با قابلیت لمس، هنگامی که کاربر صفحه را لمس کند، دستگاه وارد حالت لمسی می شود. از این مرحله به بعد، فقط نماهایی که برای آنها isFocusableInTouchMode()
true است، مانند ویجت های ویرایش متن، قابل فوکوس خواهند بود. سایر نماهایی که قابل لمس هستند، مانند دکمهها، با لمس فوکوس نمیشوند. آنها به سادگی شنوندگان کلیکی خود را با فشار دادن فعال می کنند.
هر زمان که کاربر کلید جهت را بزند یا با یک گوی پیمایش کند، دستگاه از حالت لمسی خارج میشود و نمایی برای تمرکز پیدا میکند. اکنون، کاربر ممکن است بدون لمس صفحه، تعامل با رابط کاربری را از سر بگیرد.
حالت حالت لمسی در کل سیستم (همه پنجره ها و فعالیت ها) حفظ می شود. برای پرس و جو از وضعیت فعلی، می توانید با isInTouchMode()
تماس بگیرید تا ببینید آیا دستگاه در حال حاضر در حالت لمسی است یا خیر.
رسیدگی به تمرکز
این چارچوب حرکت معمول فوکوس را در پاسخ به ورودی کاربر مدیریت می کند. این شامل تغییر تمرکز با حذف یا پنهان شدن نماها یا در دسترس قرار گرفتن نماهای جدید است. View ها تمایل آنها را برای تمرکز از طریق متد
نشان می دهد. برای تغییر اینکه آیا یک View می تواند فوکوس کند یا خیر، isFocusable()
را فراخوانی کنید. هنگامی که در حالت لمسی هستید، میتوانید بپرسید که آیا View اجازه فوکوس را با setFocusable()
میدهد. می توانید این را با isFocusableInTouchMode()
تغییر دهید.setFocusableInTouchMode()
در دستگاههای دارای Android 9 (سطح API 28) یا بالاتر، فعالیتها تمرکز اولیه ندارند. در عوض، در صورت تمایل، باید صراحتاً فوکوس اولیه را درخواست کنید.
حرکت فوکوس بر اساس الگوریتمی است که نزدیکترین همسایه را در یک جهت مشخص پیدا می کند. در موارد نادر، الگوریتم پیش فرض ممکن است با رفتار مورد نظر توسعه دهنده مطابقت نداشته باشد. در این شرایط، میتوانید با ویژگیهای XML زیر در فایل طرحبندی، بازنویسیهای صریح ارائه کنید: nextFocusDown ، nextFocusLeft ، nextFocusRight و nextFocusUp . یکی از این ویژگی ها را به View که فوکوس از آن خارج می شود اضافه کنید. مقدار مشخصه را به عنوان شناسه نمایه ای که باید به آن فوکوس داده شود، تعیین کنید. به عنوان مثال:
<LinearLayout android:orientation="vertical" ... > <Button android:id="@+id/top" android:nextFocusUp="@+id/bottom" ... /> <Button android:id="@+id/bottom" android:nextFocusDown="@+id/top" ... /> </LinearLayout>
به طور معمول، در این طرح عمودی، پیمایش از دکمه اول به بالا به جایی نمی رسد، و همچنین حرکت از دکمه دوم به پایین نمی تواند انجام شود. اکنون که دکمه بالا، دکمه پایین را به عنوان nextFocusUp (و بالعکس) تعریف کرده است، فوکوس ناوبری از بالا به پایین و از پایین به بالا چرخه خواهد شد.
اگر میخواهید یک View را در رابط کاربری خود بهعنوان قابل فوکوسپذیر اعلام کنید (در صورتی که معمولاً اینطور نیست)، ویژگی android:focusable
XML را در اعلان طرحبندی خود به View اضافه کنید. مقدار true را تنظیم کنید. همچنین میتوانید در حالت لمسی با android:focusableInTouchMode
، یک View را بهعنوان قابل فوکوس اعلام کنید.
برای درخواست یک View خاص برای فوکوس کردن،
را فراخوانی کنید.requestFocus()
برای گوش دادن به رویدادهای فوکوس (در صورت دریافت یا از دست دادن فوکوس یک View مطلع شوید)، از
استفاده کنید، همانطور که در بخش شنوندگان رویداد بحث شد. onFocusChange()