سیستم تاچ اندروید چجوری کار میکنه؟ (1)

توی این قسمت میخوایم که یک نگاه کلی به فریمورک تاچ اندروید بندازیم و برای شما توضیح بدیم که توی برنامه هایی که مینویسید جریان تاچ به چه صورت هست و اینکه اندروید این eventها رو چجوری هندل و مدیریت میکنه و همینطور به APIهایی که برای نظارت بر تاچ اندروید وجود دارن نگاه میندازیم و اینکه چجوری میشه interactionهای سفارشی سازی شده رو در برنامه پیاده‌سازی کرد.

اندروید موقع تاچ شدن چه رفتاری از خودش نشون میده؟

همه‌ی تاچ‌هایی که توی برنامه‌ی شما انجام میشه به MotionEventهایی تقسیم میشن.

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

ما برای تاچ‌ها اکشن های از پیش تعریف شده‌ای رو داریم که چندتاشون رو براتون معرفی میکنم:

  • ACTION_DOWN
  • ACTION_UP

این دو تا اکشن‌های اولیه‌ای هستن که به محض اینکه انگشتمون رو روی صفحه قرار میدیم یا از روی صفحه بر می داریم فراخوانی میشن.

  • ACTION_MOVE

این اکشن وقتی اتفاق میفته که ما انگشتمون رو روی صفحه drag میکنیم.

  • ACTION_POINTER_DOWN
  • ACTION_POINTER_UP

این اکشن ها وقتی اتفاق میفتن که دومین انگشت بر روی صفحه قرار میگیره یا از روی صفحه برداشته میشه، بنابراین برای امور مالتی تاچ به اونا احتیاج خواهید داشت.

  • ACTION_CANCEL

این اکشن موقعی اتفاق میفته که در حال انتقال یک event از یک ویو به ویوی دیگه ارتباط قطع میشه ( البته بعدتر در مورد این event بیشتر صحبت میکنیم ).

اگه دقت کرده باشید که همه‌ی eventها مابین ACTION_UP و ACTION_DOWN اتفاق میفتن.

موقع eventهای تاچ، اولین قسمتی که تاچ رو متوجه میشه، اکتیویتی هست و در واقع اکتیویتی بالاتر از همه‌ی ویوها و کامپوننت های داخلی قرار داره، در این هنگامه که event از اکتیویتی و با فراخوانی متد ()dispatchTouchEvent شروع میشه، و از اینجا به بعده که این اونت از اکتیویتی شروع به پیمودن یک مسیر بالا به پایین میکنه ( Top to down traverse ) و در قدم بعدی به ویوی پرنت میرسه، در صورتی که لازم باشه بعدا دوباره همین مسیر به صورت برعکس از پایین به بالا طی میشه.
توی اندروید این کار از طریق متد onTouchListener و return کردن یک مقدار بولین در هر کاستوم ویو یا ویوگروپ اتفاق میفته، در صورتی که مقدار true رو return کنه، فریمورک متوجه میشه که باید این زنجیره رو ازهمونجا بِبُره تا دیگه ادامه نداشته باشه و بایستی این اونت توسط خود ویو هندل بشه. در صورتی که مقدار false برگردونده بشه، این زنجیره یا chain قطع نمیشه و تا بالا ادامه پیدا میکنه. در صورتی که موقع پایین رفتن اونتهای dispatchTouchEvent این زنجیره قطع بشه از همونجا شروع به برگشتن به طرف بالا میکنه، البته در ادامه با مثالهایی که میخوام بگم منظورم رو حتما بهتر درک خواهید کرد :)

پس تا اینجا متوجه شدیم اونتهای تاچ در اندروید از طریق متد dispatchTouchEvent از طرف بالا به پایین میرن و دوباره توسط متد ontouchEvent از پایین به بالا برمیگردن، که البته این chain یا به قولی زنجیره، به روشی که عرض کردم ( یعنی return شدن مقدار true توسط onTouchEvent ) قابل قطع شدن هست.

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

ولی در مورد ViewGroupها قضیه به چند علت کمی پیچیده تر میشه، توی ViewGroupها، ویوی پرنت باید محل اونت تاچ شدن رو پیدا کنه منظورم اینه که دقیقا تعیین کنه عمل تاچ شدن روی کدوم Child View انجام شده، اگه چندتا ویو روی هم قرار گرفته باشن، دقیقا به صورت معکوس ترتیب اضافه شدن ویوها به ViewGroup شروع به dispatch کردن اونت به هرکدوم از ویوها میکنه.

یک متد دیگه ای که وجود داره و باید بهش دقت کنید onInterceptTouchEvent() هست، وظیفه‌ی این متد اینه که ViewGroup بر اونتهایی که از ویوی پدر به ویوی زیرین یا فرزند میره نظارت میکنه و هرجا لازم باشه، جلوی رسیدن اونت به ویوی فرزند رو میگیره. در این مورد یک مثالی که میتونم براتون بزنم اینه که حتما با ScrollView یا NestedScrollView تابحال کار کردین، خب، مکانیسم اسکرول ویو اینجوریه که جلوی رسیدن اونت اسکرول شدن رو به ویوهای فرزند میگیره و از این طریق فقط ویوی والد اسکرول میشه، اون روش ازهمین متدی که اشاره کردم، یعنی onInterceptTouchEvent() استفاده میکنه.

گاهی اوقات لازمه که تضمین کنیم که این اونت تاچ شدن حتما از ویوی والد به فرزند خواهد رسید و قطع نخواهد شد، در این صورته که از متد requestDisallowToucIntercept() در ویوی پرنت استفاده کنیم، در این صورت اونت تاچ حتما به ویوی فرزند خواهد رسید. برای مثال ممکنه که توی اسکرول ویو، ما یک ریسایکلرویو داشته باشیم و بخوایم که هر وقت این ریسایکلر داخل اسکرول ویو اسکرول شد، خودِ ریسایکلر این اسکرول رو هندل کنه، در این صورته که ما از متد requestDisallowTouchIntercept استفاده میکنیم.

اگه چیزی رو مبهم گفتم بفرمایید اصلاح کنم یا در قسمتهای بعدی اضافه کنم.

اگه سوالی بود بفرمایید اگه جوابش رو بلد بودم میگم.