ট্র্যাভার্সাল অর্ডার পরিবর্তন করা

ট্রাভার্সাল অর্ডার হল সেই ক্রম যার মাধ্যমে অ্যাক্সেসিবিলিটি পরিষেবা UI এলিমেন্ট নেভিগেট করে। Compose অ্যাপে, এলিমেন্টগুলি প্রত্যাশিত রিডিং অর্ডারে সাজানো থাকে, যা সাধারণত বাঁদিক থেকে ডানদিকে, তারপর উপর থেকে নিচের দিকে হয়। তবে, এমন কিছু পরিস্থিতি আছে যেখানে সঠিক পাঠক্রম নির্ধারণ করার জন্য কম্পোজকে অতিরিক্ত ইঙ্গিত দিতে হতে পারে।

isTraversalGroup ও traversalIndex হল এমন সিম্যান্টিক প্রপার্টি যা আপনাকে এমন সব পরিস্থিতি অ্যাক্সেসিবিলিটি পরিষেবার জন্য ট্রাভার্সাল অর্ডারকে প্রভাবিত করতে দেয় যেখানে Compose-এর ডিফল্ট সর্টিং অ্যালগরিদম যথেষ্ট নয়। isTraversalGroup কাস্টমাইজেশনের প্রয়োজন আছে এমন শব্দার্থগতভাবে গুরুত্বপূর্ণ গ্রুপকে শনাক্ত করে, অন্যদিকে traversalIndex সেইসব গ্রুপের মধ্যে থাকা স্বতন্ত্র এলিমেন্টের ক্রমকে অ্যাডজাস্ট করে। আপনি isTraversalGroup একা ব্যবহার করে বোঝাতে পারেন যে গ্রুপের মধ্যে থাকা সব এলিমেন্ট একসাথে বেছে নিতে হবে অথবা আরও কাস্টমাইজ করার জন্য traversalIndex-এর সাথে ব্যবহার করতে পারেন।

স্ক্রিন রিডার ট্রাভার্সাল অর্ডার কন্ট্রোল করতে আপনার অ্যাপে isTraversalGroup ও traversalIndex ব্যবহার করুন।

ট্রাভার্স করার জন্য এলিমেন্ট গ্রুপ করা

isTraversalGroup হল একটি বুলিয়ান প্রপার্টি যা নির্ধারণ করে যে semantics নোড একটি ট্রাভার্সাল গ্রুপ কিনা। এই ধরনের নোডের কাজ হল নোডের চাইল্ডদের সাজানোর সময় সীমানা বা বর্ডার হিসেবে কাজ করা।

নোডে isTraversalGroup = true সেটিং করা মানে হল, অন্য এলিমেন্টে যাওয়ার আগে সেই নোডের সব চিলড্রেন দেখা হয়েছে। আপনি isTraversalGroup সেট করতে পারবেন কলাম, সারি বা বক্সের মতো স্ক্রিন রিডার ফোকাস করতে পারে না এমন নোডে।

নিচে দেওয়া উদাহরণে isTraversalGroup ব্যবহার করা হয়েছে। এটি চারটি টেক্সট এলিমেন্ট এমিট করে। বাঁদিকের দুটি এলিমেন্ট একটি CardBox এলিমেন্টের অংশ, অন্যদিকে ডানদিকের দুটি এলিমেন্ট অন্য একটি CardBox এলিমেন্টের অংশ:

// CardBox() function takes in top and bottom sample text.
@Composable
fun CardBox(
    topSampleText: String,
    bottomSampleText: String,
    modifier: Modifier = Modifier
) {
    Box(modifier) {
        Column {
            Text(topSampleText)
            Text(bottomSampleText)
        }
    }
}

@Composable
fun TraversalGroupDemo() {
    val topSampleText1 = "This sentence is in "
    val bottomSampleText1 = "the left column."
    val topSampleText2 = "This sentence is "
    val bottomSampleText2 = "on the right."
    Row {
        CardBox(
            topSampleText1,
            bottomSampleText1
        )
        CardBox(
            topSampleText2,
            bottomSampleText2
        )
    }
}

কোডটি নিম্নলিখিত আউটপুটের মতো আউটপুট তৈরি করে:

টেক্সটের দুটি কলাম সহ লেআউট, যেখানে বাঁদিকের কলামে 'এই
  বাক্যটি বাঁদিকের কলামে আছে' এবং ডানদিকের কলামে 'এই বাক্যটি ডানদিকে আছে' লেখা আছে।
ছবি ১. দুটি বাক্য সহ লেআউট (একটি বাঁদিকের কলামে এবং একটি ডানদিকের কলামে)।

কোনও সিম্যান্টিক্স সেট করা না থাকার কারণে, স্ক্রিন রিডারের ডিফল্ট আচরণ হল বাঁদিক থেকে ডানদিকে এবং উপর থেকে নিচের দিকে এলিমেন্ট ট্রাভার্স করা। এই ডিফল্ট সেটিংয়ের কারণে, টকব্যাক বাক্য খণ্ডগুলি ভুল ক্রমে পড়ে:

"এই বাক্যটি" → "এই বাক্যটি" → "বামদিকের কলামে আছে।" → "ডানদিকে দেখুন।"

ফ্র্যাগমেন্ট সঠিকভাবে সাজাতে, isTraversalGroup থেকে true সেট করতে আসল স্নিপেট পরিবর্তন করুন:

@Composable
fun TraversalGroupDemo2() {
    val topSampleText1 = "This sentence is in "
    val bottomSampleText1 = "the left column."
    val topSampleText2 = "This sentence is"
    val bottomSampleText2 = "on the right."
    Row {
        CardBox(
//      1,
            topSampleText1,
            bottomSampleText1,
            Modifier.semantics { isTraversalGroup = true }
        )
        CardBox(
//      2,
            topSampleText2,
            bottomSampleText2,
            Modifier.semantics { isTraversalGroup = true }
        )
    }
}

isTraversalGroup প্রতিটি CardBox-এ আলাদাভাবে সেট করা থাকে বলে, CardBox সেগুলির এলিমেন্ট সাজানোর সময় সীমা প্রযোজ্য হয়। এই ক্ষেত্রে, বাঁদিকের CardBox অংশটি প্রথমে এবং তারপরে ডানদিকের CardBox অংশটি পড়া হয়।

এখন, টকব্যাক সঠিক ক্রমে বাক্যাংশগুলি পড়ে শোনাবে:

"এই বাক্যটি" → "বামদিকের কলামে আছে।" → "এই বাক্যটি" → "ডানদিকে আছে।"

ট্রাভার্সাল অর্ডার কাস্টমাইজ করা

traversalIndex হল একটি ফ্লোট প্রপার্টি যা আপনাকে টকব্যাক ট্রাভার্সাল অর্ডার কাস্টমাইজ করতে দেয়। TalkBack-এর সঠিকভাবে কাজ করার জন্য এলিমেন্টগুলিকে একসাথে গ্রুপ করা যথেষ্ট না হলে, স্ক্রিন রিডার অর্ডারিং আরও কাস্টমাইজ করতে traversalIndex-এর সাথে isTraversalGroup ব্যবহার করুন।

traversalIndex প্রপার্টির নিম্নলিখিত বৈশিষ্ট্য আছে:

  • কম traversalIndex ভ্যালু সহ এলিমেন্টকে প্রথমে অগ্রাধিকার দেওয়া হয়।
  • ধনাত্মক বা ঋণাত্মক হতে পারে।
  • ডিফল্ট ভ্যালু হল 0f।
  • ট্রাভার্সাল ইনডেক্সকে ট্রাভার্সাল আচরণ প্রভাবিত করতে হলে, এটিকে অবশ্যই এমন কম্পোনেন্টে সেট করতে হবে যা অ্যাক্সেসিবিলিটি পরিষেবা বেছে নিতে ও ফোকাস করতে পারবে, যেমন টেক্সট বা বোতামের মতো অন-স্ক্রিন এলিমেন্ট।
    • যেমন, Column-এ শুধু traversalIndex চালু করলে কোনও প্রভাব পড়বে না, যদি না কলামে isTraversalGroup-ও চালু করা থাকে।

traversalIndex এবং isTraversalGroup একসাথে কীভাবে ব্যবহার করতে পারবেন তা নিম্নলিখিত উদাহরণ থেকে দেখুন।

ঘড়ির ডায়াল হল এমন একটি সাধারণ পরিস্থিতি যেখানে স্ট্যান্ডার্ড ট্রাভার্সাল অর্ডারিং কাজ করে না। এই বিভাগে দেওয়া উদাহরণটি হল টাইম পিকার, যেখানে ব্যবহারকারী ক্লক ফেসে দেওয়া সংখ্যাগুলির মাধ্যমে ট্রাভার্স করতে এবং ঘণ্টার ও মিনিটের স্লটের জন্য ডিজিট বেছে নিতে পারেন।

উপরে টাইম পিকার সহ একটি ক্লক ফেস।
ছবি ২. ক্লক ফেসের ছবি।

নিচে দেওয়া সহজবোধ্য স্নিপেটে একটি CircularLayout আছে, যেখানে ১২ টি সংখ্যা আঁকা হয়েছে, ১২ থেকে শুরু করে বৃত্তের চারপাশে ঘড়ির কাঁটার দিকে এগুলি সাজানো হয়েছে:

@Composable
fun ClockFaceDemo() {
    CircularLayout {
        repeat(12) { hour ->
            ClockText(hour)
        }
    }
}

@Composable
private fun ClockText(value: Int) {
    Box(modifier = Modifier) {
        Text((if (value == 0) 12 else value).toString())
    }
}

কারণ, ডিফল্ট বাঁদিক থেকে ডানদিক ও উপর থেকে নিচের ক্রমে ক্লক ফেস লজিক্যালি পড়া হয় না, তাই টকব্যাক সংখ্যাগুলি এলোমেলোভাবে পড়ে। এটি সংশোধন করতে, নিম্নলিখিত স্নিপেটে দেখানো ইনক্রিমেন্টিং কাউন্টার ভ্যালু ব্যবহার করুন:

@Composable
fun ClockFaceDemo() {
    CircularLayout(Modifier.semantics { isTraversalGroup = true }) {
        repeat(12) { hour ->
            ClockText(hour)
        }
    }
}

@Composable
private fun ClockText(value: Int) {
    Box(modifier = Modifier.semantics { this.traversalIndex = value.toFloat() }) {
        Text((if (value == 0) 12 else value).toString())
    }
}

ট্রাভার্সাল অর্ডারিং সঠিকভাবে সেট করতে, প্রথমে CircularLayout-কে ট্রাভার্সাল গ্রুপ হিসেবে সেট করুন এবং isTraversalGroup = true সেট করুন। তারপর, প্রতিটি ক্লক টেক্সট লেআউটে ড্র করা হলে, তার সংশ্লিষ্ট traversalIndex-কে কাউন্টার ভ্যালুতে সেট করুন।

যেহেতু কাউন্টার ভ্যালু ক্রমাগত বাড়তে থাকে, তাই প্রতিটি ক্লক ভ্যালুর traversalIndex মান স্ক্রিনে সংখ্যা যোগ করার সাথে সাথে বড় হতে থাকে—ক্লক ভ্যালু ০ -এর traversalIndex মান হল ০ এবং ক্লক ভ্যালু ১-এর traversalIndex মান হল ১। এইভাবে, টকব্যাক যে ক্রমে সেগুলি পড়ে তা সেট করা হয়। এখন, CircularLayout-এর মধ্যে থাকা সংখ্যাগুলি প্রত্যাশিত ক্রমে পড়া হয়।

কারণ, সেট করা traversalIndexes শুধুমাত্র একই গ্রুপিংয়ের মধ্যে থাকা অন্যান্য ইনডেক্সের সাথে সম্পর্কিত, স্ক্রিনের বাকি অংশের ক্রম ঠিক রাখা হয়েছে। অন্যভাবে বলতে গেলে, আগের কোড স্নিপেটে দেখানো শব্দার্থগত পরিবর্তন শুধুমাত্র ক্লক ফেসে থাকা isTraversalGroup = true সেট করা আইটেমের ক্রম পরিবর্তন করে।

মনে রাখবেন, CircularLayout's সিম্যান্টিক্স isTraversalGroup = true হিসেবে সেট না করলেও, traversalIndex পরিবর্তন এখনও প্রযোজ্য হবে। তবে, এগুলিকে বাইন্ড করার জন্য CircularLayout না থাকলে, স্ক্রিনের অন্যান্য সব এলিমেন্ট দেখা হয়ে যাওয়ার পরে, ক্লক ফেসে থাকা বারোটি ডিজিট সবশেষে পড়া হয়। এটি ঘটে কারণ অন্যান্য সব এলিমেন্টের ডিফল্ট traversalIndex হল 0f এবং অন্যান্য সব 0f এলিমেন্টের পরে ক্লক টেক্সট এলিমেন্ট পড়া হয়।

API সংক্রান্ত বিবেচ্য বিষয়

ট্রাভার্সাল API ব্যবহার করার সময় নিম্নলিখিত বিষয়গুলি বিবেচনা করুন:

  • গ্রুপ করা উপাদান থাকা অভিভাবকের উপর isTraversalGroup = true সেট করতে হবে।
  • traversalIndex-কে এমন চাইল্ড কম্পোনেন্টে সেট করতে হবে যাতে সিম্যান্টিক্স থাকে এবং অ্যাক্সেসিবিলিটি পরিষেবা এটি বেছে নেবে।
  • আপনি যেসব এলিমেন্ট নিয়ে তদন্ত করছেন সেগুলি একই zIndex লেভেলে আছে কিনা তা নিশ্চিত করুন, কারণ এটিও শব্দার্থ ও ট্রাভার্সাল অর্ডারকে প্রভাবিত করে।
  • অপ্রয়োজনীয় কোনও সিম্যান্টিক যেন মার্জ না করা হয় তা নিশ্চিত করুন, কারণ এটি কোন কম্পোনেন্ট ট্রাভার্সাল ইনডেক্স প্রয়োগ করা হবে তা প্রভাবিত করতে পারে।