Android-এ, আপনার অ্যাপ্লিকেশনের সাথে ব্যবহারকারীর ইন্টার্যাকশন থেকে ইভেন্ট ইন্টারসেপ্ট করার একাধিক উপায় আছে। আপনার ইউজার ইন্টারফেসের মধ্যে ইভেন্ট বিবেচনা করার সময়, ব্যবহারকারী যে নির্দিষ্ট View অবজেক্টের সাথে ইন্টার্যাক্ট করেন, সেখান থেকে ইভেন্ট ক্যাপচার করার পদ্ধতি ব্যবহার করা হয়। View ক্লাস এটি করার উপায় প্রদান করে।
আপনার লেআউট কম্পোজ করার জন্য আপনি যে বিভিন্ন ভিউ ক্লাস ব্যবহার করবেন, তার মধ্যে আপনি বেশ কিছু সর্বজনীন কলব্যাক পদ্ধতি লক্ষ্য করতে পারেন যা UI ইভেন্টের জন্য উপযোগী বলে মনে হয়। Android ফ্রেমওয়ার্ক এইসব পদ্ধতিকে কল করে যখন
সেই অবজেক্টে সংশ্লিষ্ট অ্যাকশন ঘটে। যেমন, কোনও ভিউ (যেমন, বোতাম) টাচ করা হলে,
সেই অবজেক্টে onTouchEvent() মেথড কল করা হয়। তবে, এটি ইন্টারসেপ্ট করতে, আপনাকে অবশ্যই ক্লাসটি এক্সটেন্ড করতে হবে
এবং পদ্ধতিটি ওভাররাইড করতে হবে। তবে, এই ধরনের ইভেন্ট ম্যানেজ করার জন্য
প্রতিটি View অবজেক্ট এক্সটেন্ড করা বাস্তবসম্মত হবে না। এই কারণেই View ক্লাসে কলব্যাক সহ নেস্টেড ইন্টারফেসের একটি সংগ্রহও রয়েছে যা আপনি আরও সহজে সংজ্ঞায়িত করতে পারেন। এইসব ইন্টারফেসকে ইভেন্ট লিসেনার বলা হয় এবং এগুলি আপনার UI-এর সাথে ব্যবহারকারীর ইন্টার্যাকশন ক্যাপচার করার টিকিট।
ব্যবহারকারীর ইন্টার্যাকশন শোনার জন্য আপনি সাধারণত ইভেন্ট লিসেনার ব্যবহার করলেও,
কাস্টম কম্পোনেন্ট তৈরি করার জন্য আপনাকে View ক্লাস বড় করতে হতে পারে।
আপনি হয়ত আরও আকর্ষণীয় কিছু তৈরি করতে Button
ক্লাসটি এক্সটেন্ড করতে চান। এই ক্ষেত্রে, আপনি ক্লাসের ইভেন্ট হ্যান্ডলার ব্যবহার করে আপনার ক্লাসের জন্য ডিফল্ট ইভেন্ট আচরণ নির্ধারণ করতে পারবেন।
ইভেন্ট লিসনার
ইভেন্ট লিসনার হল View ক্লাসের একটি ইন্টারফেস যাতে একটিমাত্র
কলব্যাক পদ্ধতি থাকে। Android ফ্রেমওয়ার্ক এইসব পদ্ধতি কল করবে যখন UI-তে আইটেমের সাথে ব্যবহারকারীর ইন্টার্যাকশনের মাধ্যমে
রেজিস্টার করা লিসনারের ভিউ ট্রিগার করা হবে।
ইভেন্ট লিসেনার ইন্টারফেসে নিম্নলিখিত কলব্যাক পদ্ধতি অন্তর্ভুক্ত থাকে:
onClick()View.OnClickListenerথেকে। ব্যবহারকারী আইটেম স্পর্শ করলে (টাচ মোডে থাকাকালীন) অথবা নেভিগেশন-কী বা ট্র্যাকবল ব্যবহার করে আইটেমে ফোকাস করে উপযুক্ত "Enter" কী প্রেস করলে অথবা ট্র্যাকবল প্রেস করলে এটি কল করা হয়।onLongClick()View.OnLongClickListenerথেকে। ব্যবহারকারী আইটেমটি টাচ করে ধরে রাখলে (টাচ মোডে থাকাকালীন) অথবা নেভিগেশন-কী বা ট্র্যাকবল ব্যবহার করে আইটেমটি ফোকাস করলে এবং উপযুক্ত "Enter" কী প্রেস করে ধরে রাখলে অথবা ট্র্যাকবল প্রেস করে ধরে রাখলে (এক সেকেন্ডের জন্য) এটি কল করা হয়।onFocusChange()View.OnFocusChangeListenerথেকে। ব্যবহারকারী নেভিগেশন-কী বা ট্র্যাকবল ব্যবহার করে আইটেমে বা আইটেম থেকে দূরে নেভিগেট করলে এটি কল করা হয়।onKey()View.OnKeyListenerথেকে। ব্যবহারকারী আইটেমে ফোকাস করে ডিভাইসের হার্ডওয়্যার কী প্রেস করলে বা ছেড়ে দিলে এটি কল করা হয়।onTouch()View.OnTouchListenerথেকে। ব্যবহারকারী টাচ ইভেন্ট হিসেবে গণ্য করা কোনও অ্যাকশন করলে এটি কল করা হয়, যার মধ্যে স্ক্রিনে (আইটেমের সীমার মধ্যে) প্রেস করা, রিলিজ করা বা যেকোনও মুভমেন্ট জেসচার অন্তর্ভুক্ত।onCreateContextMenu()View.OnCreateContextMenuListenerথেকে। এটি তখন কল করা হয় যখন একটি কনটেক্সট মেনু তৈরি করা হচ্ছে (একটি টেকসই "লং ক্লিক" এর ফলস্বরূপ)। মেনু ডেভেলপার গাইডে কন্টেক্সট মেনু সম্পর্কে আলোচনা দেখুন।
এই পদ্ধতিগুলি তাদের নিজ নিজ ইন্টারফেসের একমাত্র বাসিন্দা। এইসব পদ্ধতির মধ্যে কোনও একটিকে সংজ্ঞায়িত করতে
এবং আপনার ইভেন্ট ম্যানেজ করতে, আপনার অ্যাক্টিভিটিতে নেস্টেড ইন্টারফেস প্রয়োগ করুন অথবা এটিকে একটি বেনামী ক্লাস হিসেবে সংজ্ঞায়িত করুন।
তারপর, আপনার ইমপ্লিমেন্টেশনের একটি ইনস্ট্যান্স
সংশ্লিষ্ট View.set...Listener() পদ্ধতিতে পাস করুন। (যেমন,
কল করুন এবং setOnClickListener()OnClickListener-এর ইমপ্লিমেন্টেশন পাস করুন।)
নিচের উদাহরণে দেখানো হয়েছে যে কীভাবে কোনও বোতামের জন্য অন-ক্লিক লিসনার রেজিস্টার করতে হয়।
Kotlin
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 প্রয়োগ করা আরও সুবিধাজনক বলে মনে হতে পারে। এটি অতিরিক্ত ক্লাস লোড এবং অবজেক্ট অ্যালোকেশন এড়াবে। যেমন:
Kotlin
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() কলব্যাকের
কোনও রিটার্ন ভ্যালু নেই, তবে অন্য কিছু ইভেন্ট লিসনার পদ্ধতিতে অবশ্যই বুলিয়ান রিটার্ন করতে হবে। কারণটি
ইভেন্টের উপর নির্ভর করে। যে কয়েকটি ক্ষেত্রে এটি হয়, তার কারণ এখানে দেওয়া হল:
- এটি একটি বুলিয়ান রিটার্ন করে যা নির্দেশ করে যে আপনি ইভেন্টটি ব্যবহার করেছেন এবং এটি আর চালিয়ে যাওয়া উচিত নয়। অর্থাৎ, আপনি ইভেন্টটি হ্যান্ডেল করেছেন এবং এটি এখানেই বন্ধ হওয়া উচিত তা নির্দেশ করতে true রিটার্ন করুন; আপনি যদি এটি হ্যান্ডেল না করে থাকেন এবং/অথবা ইভেন্টটি অন্য কোনও অন-ক্লিক লিসনারে চালিয়ে যাওয়া উচিত হলে false রিটার্ন করুন।onLongClick()- এটি একটি বুলিয়ান রিটার্ন করে যা নির্দেশ করে যে আপনি ইভেন্টটি ব্যবহার করেছেন এবং এটি আর চালিয়ে যাওয়া উচিত নয়। অর্থাৎ, আপনি ইভেন্টটি হ্যান্ডেল করেছেন এবং এটি এখানেই বন্ধ হওয়া উচিত তা নির্দেশ করতে true রিটার্ন করুন; আপনি যদি এটি হ্যান্ডেল না করে থাকেন এবং/অথবা ইভেন্টটি অন্য কোনও অন-কী লিসেনারে চালিয়ে যাওয়া উচিত হলে false রিটার্ন করুন।onKey()- আপনার লিসনার এই ইভেন্ট ব্যবহার করে কিনা তা নির্দেশ করার জন্য এটি একটি বুলিয়ান রিটার্ন করে। গুরুত্বপূর্ণ বিষয় হল, এই ইভেন্টে একাধিক অ্যাকশন থাকতে পারে যা একে অপরের পরে ঘটে। তাই, ডাউন অ্যাকশন ইভেন্ট পাওয়ার পরে আপনি false রিটার্ন করলে, আপনি বোঝাতে চাইছেন যে আপনি ইভেন্টটি ব্যবহার করেননি এবং এই ইভেন্ট থেকে পরবর্তী অ্যাকশন সম্পর্কে আগ্রহী নন। তাই, ইভেন্টের মধ্যে আপনাকে অন্য কোনও অ্যাকশন করতে বলা হবে না, যেমন আঙুলের জেসচার বা ইভেন্ট শেষ করার অ্যাকশন।onTouch()
মনে রাখবেন যে হার্ডওয়্যার কী ইভেন্ট সবসময় বর্তমানে ফোকাসে থাকা ভিউতে ডেলিভার করা হয়। ভিউ হায়ারার্কির সবচেয়ে উপরের অংশ থেকে শুরু করে নিচের দিকে উপযুক্ত গন্তব্যে না পৌঁছানো পর্যন্ত এগুলি পাঠানো হয়। আপনার ভিউ (বা আপনার ভিউয়ের চাইল্ড)
বর্তমানে ফোকাসে থাকলে, আপনি পদ্ধতির মাধ্যমে ইভেন্ট ট্রাভেল দেখতে পাবেন। আপনার ভিউয়ের মাধ্যমে গুরুত্বপূর্ণ ইভেন্ট ক্যাপচার করার বিকল্প হিসেবে, আপনি dispatchKeyEvent()
এবং onKeyDown()-এর মাধ্যমে আপনার অ্যাক্টিভিটির মধ্যে সব ইভেন্ট
পেতে পারেন।onKeyUp()
এছাড়াও, আপনার অ্যাপ্লিকেশনের জন্য টেক্সট ইনপুট সম্পর্কে চিন্তা করার সময়, মনে রাখবেন যে অনেক ডিভাইসে শুধুমাত্র সফ্টওয়্যার ইনপুট
পদ্ধতি আছে। এই ধরনের পদ্ধতি কী-ভিত্তিক হতে হবে এমন কোনও বাধ্যবাধকতা নেই; কিছু ক্ষেত্রে ভয়েস ইনপুট, হাতের লেখা ইত্যাদি ব্যবহার করা হতে পারে। এমনকি
কোনও ইনপুট পদ্ধতি কীবোর্ডের মতো ইন্টারফেস দেখালেও, এটি সাধারণত ফ্যামিলি অফ ইভেন্ট
ট্রিগার করবে না। আপনি যদি হার্ডওয়্যার কীবোর্ড আছে এমন ডিভাইসে আপনার অ্যাপ্লিকেশন সীমাবদ্ধ করতে না চান, তাহলে
এমন UI কখনই তৈরি করবেন না যা নিয়ন্ত্রণ করার জন্য নির্দিষ্ট কী প্রেস করতে হয়। বিশেষ করে, ব্যবহারকারী
রিটার্ন কী প্রেস করলে ইনপুট যাচাই করার জন্য এইসব পদ্ধতির উপর নির্ভর করবেন না; এর পরিবর্তে, আপনার অ্যাপ্লিকেশন কীভাবে প্রতিক্রিয়া দেখাবে তা ইনপুট পদ্ধতিকে
সিগন্যাল দিতে onKeyDown()IME_ACTION_DONE-এর মতো অ্যাকশন ব্যবহার করুন, যাতে এটি অর্থপূর্ণ উপায়ে UI পরিবর্তন করতে পারে। সফ্টওয়্যার ইনপুট পদ্ধতি কীভাবে কাজ করা উচিত সেই সম্পর্কে অনুমান করা এড়িয়ে চলুন এবং আপনার অ্যাপ্লিকেশনে আগে থেকে ফর্ম্যাট করা টেক্সট সরবরাহ করার জন্য এটিকে বিশ্বাস করুন।
মনে রাখবেন: Android প্রথমে ইভেন্ট হ্যান্ডলারকে কল করবে এবং তারপরে ক্লাস ডেফিনেশন থেকে উপযুক্ত ডিফল্ট হ্যান্ডলারকে কল করবে। তাই, এইসব ইভেন্ট লিসনার থেকে true রিটার্ন করলে, অন্যান্য ইভেন্ট লিসনারে ইভেন্ট প্রোপাগেশন বন্ধ হয়ে যাবে এবং ভিউতে ডিফল্ট ইভেন্ট হ্যান্ডলারে কলব্যাকও ব্লক হয়ে যাবে। তাই 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-কে ইভেন্ট দেখার অনুমতি দেয়, কারণ সেগুলি চাইল্ড ভিউতে পাঠানো হয়।- এটি প্যারেন্ট ভিউতে কল করুন যাতে বোঝা যায় যে এটিViewParent.requestDisallowInterceptTouchEvent(boolean)-এর সাথে টাচ ইভেন্ট ইন্টারসেপ্ট করবে না।onInterceptTouchEvent(MotionEvent)
স্পর্শ মোড
ব্যবহারকারী যখন ডিরেকশনাল কী বা ট্র্যাকবল ব্যবহার করে ইউজার ইন্টারফেসে নেভিগেট করেন, তখন অ্যাকশন করা যায় এমন আইটেমে (যেমন বোতাম) ফোকাস করা প্রয়োজন যাতে ব্যবহারকারী দেখতে পান কোন আইটেম ইনপুট গ্রহণ করবে। তবে, ডিভাইসে টাচ করার সুবিধা থাকলে এবং ব্যবহারকারী ইন্টারফেস টাচ করে ইন্টার্যাক্ট করা শুরু করলে, আইটেম হাইলাইট করা বা নির্দিষ্ট কোনও ভিউতে ফোকাস করার আর প্রয়োজন হয় না। তাই, ইন্টার্যাকশনের জন্য "টাচ মোড" নামে একটি মোড আছে।
টাচ-সক্ষম ডিভাইসের জন্য, ব্যবহারকারী স্ক্রিন টাচ করলে, ডিভাইসটি
টাচ মোডে প্রবেশ করবে। এই পয়েন্ট থেকে, শুধুমাত্র সেইসব ভিউ ফোকাস করা যাবে যেগুলির জন্য
isFocusableInTouchMode() সত্য, যেমন টেক্সট এডিটিং উইজেট।
অন্যান্য ভিউ যা টাচ করা যায়, যেমন বোতাম, টাচ করা হলে ফোকাস নেবে না; প্রেস করা হলে
তারা শুধু তাদের অন-ক্লিক লিসনার ফায়ার করবে।
ব্যবহারকারী যখনই কোনও ডিরেকশনাল কী প্রেস করেন বা ট্র্যাকবল দিয়ে স্ক্রল করেন, ডিভাইসটি টাচ মোড থেকে বেরিয়ে আসে এবং ফোকাস করার জন্য কোনও ভিউ খুঁজে নেয়। এখন, ব্যবহারকারী স্ক্রিন টাচ না করেই ইউজার ইন্টারফেসের সাথে ইন্টার্যাক্ট করা আবার শুরু করতে পারবেন।
টাচ মোড স্টেট পুরো সিস্টেম (সব উইন্ডো ও অ্যাক্টিভিটি) জুড়ে বজায় রাখা হয়।
বর্তমান অবস্থা সম্পর্কে কোয়েরি করতে, ডিভাইসটি বর্তমানে টাচ মোডে আছে কিনা তা দেখতে আপনি
isInTouchMode() কল করতে পারেন।
ফোকাস ম্যানেজ করা
ব্যবহারকারীর ইনপুটের উত্তরে ফ্রেমওয়ার্ক রুটিন ফোকাস মুভমেন্ট ম্যানেজ করবে।
এর মধ্যে রয়েছে, ভিউ সরিয়ে দেওয়া বা লুকানো অথবা নতুন ভিউ উপলভ্য হওয়ার সাথে সাথে ফোকাস পরিবর্তন করা। ভিউ থেকে বোঝা যায় যে তারা পদ্ধতির মাধ্যমে
ফোকাস নিতে ইচ্ছুক। কোনও ভিউ ফোকাস নিতে পারবে কিনা তা পরিবর্তন করতে, isFocusable() কল করুন। টাচ মোডে থাকাকালীন,
আপনি কোয়েরি করতে পারেন যে কোনও ভিউ setFocusable()-এর মাধ্যমে ফোকাস করার অনুমতি দেয় কিনা।
আপনি isFocusableInTouchMode()-এর মাধ্যমে এটি পরিবর্তন করতে পারবেন।
setFocusableInTouchMode()
Android 9 (API লেভেল ২৮) বা তার পরবর্তী যেকোনও ভার্সনে চলা ডিভাইসে, অ্যাক্টিভিটি কোনও প্রারম্ভিক ফোকাস অ্যাসাইন করে না। পরিবর্তে, আপনি চাইলে, আপনাকে অবশ্যই স্পষ্টভাবে প্রারম্ভিক ফোকাসের জন্য অনুরোধ করতে হবে।
ফোকাস মুভমেন্ট একটি অ্যালগরিদমের উপর ভিত্তি করে কাজ করে যা নির্দিষ্ট দিকে সবচেয়ে কাছের প্রতিবেশী খুঁজে বের করে। বিরল ক্ষেত্রে, ডিফল্ট অ্যালগরিদম ডেভেলপারের অভিপ্রেত আচরণের সাথে নাও মিলতে পারে। এইসব পরিস্থিতিতে, আপনি লেআউট ফাইলে নিম্নলিখিত XML অ্যাট্রিবিউট সহ স্পষ্ট ওভাররাইড প্রদান করতে পারেন: nextFocusDown, nextFocusLeft, nextFocusRight এবং nextFocusUp। যে ভিউ থেকে ফোকাস সরে যাচ্ছে, সেটিতে এইসব অ্যাট্রিবিউটের মধ্যে একটি যোগ করুন। অ্যাট্রিবিউটের ভ্যালু এমনভাবে নির্ধারণ করুন যাতে সেটি ভিউয়ের আইডি হয় যেটিতে ফোকাস করা উচিত। যেমন:
<LinearLayout android:orientation="vertical" ... > <Button android:id="@+id/top" android:nextFocusUp="@+id/bottom" ... /> <Button android:id="@+id/bottom" android:nextFocusDown="@+id/top" ... /> </LinearLayout>
সাধারণত, এই উল্লম্ব লেআউটে, প্রথম বোতাম থেকে উপরের দিকে নেভিগেট করলে কোথাও যাওয়া যাবে না, দ্বিতীয় বোতাম থেকে নিচের দিকে নেভিগেট করলেও কোথাও যাওয়া যাবে না। এখন উপরের বোতামটি নিচের বোতামটিকে nextFocusUp হিসেবে সংজ্ঞায়িত করেছে (এবং এর উল্টোটাও), নেভিগেশন ফোকাস উপর-থেকে-নিচে এবং নিচ-থেকে-উপরে চক্রাকারে ঘুরবে।
আপনার UI-তে কোনও ভিউকে ফোকাসযোগ্য হিসেবে ঘোষণা করতে চাইলে (যখন এটি সাধারণত হয় না),
আপনার লেআউট ঘোষণায় ভিউতে android:focusable XML অ্যাট্রিবিউট যোগ করুন।
true ভ্যালু সেট করুন। এছাড়াও, আপনি android:focusableInTouchMode-এর মাধ্যমে টাচ মোডে থাকাকালীন
কোনও ভিউকে ফোকাসযোগ্য হিসেবে ঘোষণা করতে পারেন।
কোনও নির্দিষ্ট ভিউতে ফোকাস করার অনুরোধ করতে, -এ কল করুন।requestFocus()
ফোকাস ইভেন্ট শুনতে (কোনও ভিউ ফোকাস পেলে বা হারালে বিজ্ঞপ্তি পেতে),
ব্যবহার করুন, যেমনটি ইভেন্ট লিসেনার বিভাগে আলোচনা করা হয়েছে।onFocusChange()