সেম্যান্টিক্স

কম্পোজেবল যে প্রাথমিক তথ্য বহন করে, যেমন Text কম্পোজেবলের টেক্সট স্ট্রিং, সেটি ছাড়াও UI এলিমেন্ট সম্পর্কে আরও পরিপূরক তথ্য থাকলে তা সহায়ক হতে পারে।

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

উপযুক্ত Compose API-এর সাথে উপযুক্ত সিম্যান্টিক্স একত্রিত করে, আপনি অ্যাক্সেসিবিলিটি পরিষেবায় আপনার কম্পোনেন্ট সম্পর্কে যতটা সম্ভব তথ্য প্রদান করেন, যা পরে সিদ্ধান্ত নেয় যে ব্যবহারকারীর কাছে এটি কীভাবে উপস্থাপন করা হবে।

Material ও Compose UI এবং Foundation API-তে বিল্ট-ইন সিম্যান্টিক থাকে যা তাদের নির্দিষ্ট ভূমিকা ও ফাংশন অনুসরণ করে, তবে আপনি নিজের নির্দিষ্ট প্রয়োজনীয়তা অনুযায়ী আগে থেকে থাকা API-এর জন্য এইসব সিম্যান্টিক পরিবর্তন করতে অথবা কাস্টম কম্পোনেন্টের জন্য নতুন সিম্যান্টিক সেট করতে পারবেন।

সিম্যান্টিক প্রপার্টি

সিম্যান্টিক প্রপার্টি সংশ্লিষ্ট কম্পোজেবলের অর্থ বোঝায়। যেমন, Text কম্পোজেবলে একটি সিম্যান্টিক প্রপার্টি text থাকে, কারণ সেটিই হল ওই কম্পোজেবলের অর্থ। Icon-এ একটি contentDescription প্রপার্টি থাকে (ডেভেলপার সেট করলে) যা টেক্সটের মাধ্যমে আইকনের অর্থ বোঝায়।

কীভাবে শব্দার্থগত বৈশিষ্ট্য কম্পোজেবলের অর্থ প্রকাশ করে তা বিবেচনা করুন। Switch বিবেচনা করুন। ব্যবহারকারী এটি এইভাবে দেখতে পাবেন:

ছবি ১. Switch "চালু" এবং "বন্ধ" অবস্থায় আছে।

এই এলিমেন্টের অর্থ বর্ণনা করতে, আপনি নিম্নলিখিত কথাগুলি বলতে পারেন: "এটি একটি সুইচ, যা 'চালু' অবস্থায় টগল করা যায় এমন এলিমেন্ট। আপনি এটিতে ক্লিক করে ইন্টার‍্যাক্ট করতে পারবেন।"

ঠিক এই কারণেই সিম্যান্টিক প্রপার্টি ব্যবহার করা হয়। এই সুইচ এলিমেন্টের সিম্যান্টিক্স নোডে নিম্নলিখিত প্রপার্টি থাকে, যা লেআউট ইন্সপেক্টরের মাধ্যমে দেখা যায়:

লেআউট ইন্সপেক্টর, Switch কম্পোজেবলের সিম্যান্টিক্স প্রপার্টি দেখাচ্ছে
ছবি ২. লেআউট ইন্সপেক্টর Switch কম্পোজেবলের সেম্যান্টিক প্রপার্টি দেখাচ্ছে।

Role দিয়ে এলিমেন্টের ধরন বোঝানো হয়। StateDescription-এ বর্ণনা করা আছে যে কীভাবে "চালু" স্ট্যাটাস রেফারেন্স করা উচিত। ডিফল্ট হিসেবে এটি "চালু" শব্দের স্থানীয় ভার্সন, তবে এটি আরও নির্দিষ্ট (যেমন, "চালু করা হয়েছে") করা যেতে পারে প্রসঙ্গের উপর ভিত্তি করে। ToggleableState হল Switch-এর বর্তমান অবস্থা। OnClick প্রপার্টি এই এলিমেন্টের সাথে ইন্টার‍্যাক্ট করার জন্য ব্যবহৃত পদ্ধতিকে রেফারেন্স করে।

আপনার অ্যাপে কম্পোজ করার মতো প্রতিটি আইটেমের সিমেন্টিক প্রপার্টি ট্র্যাক করলে অনেক শক্তিশালী সম্ভাবনা আনলক হয়:

  • স্ক্রিনে দেখানো UI উপস্থাপন করতে এবং ব্যবহারকারীদের এটির সাথে ইন্টার‍্যাক্ট করার অনুমতি দিতে অ্যাক্সেসিবিলিটি পরিষেবা প্রপার্টি ব্যবহার করে। Switch কম্পোজেবলের জন্য, টকব্যাক হয়ত ঘোষণা করবে: "চালু; সুইচ; টগল করতে ডবল ট্যাপ করুন"। ব্যবহারকারী সুইচ বন্ধ করতে তার স্ক্রিনে ডবল ট্যাপ করতে পারেন।
  • টেস্টিং ফ্রেমওয়ার্ক নোড খুঁজতে, সেগুলির সাথে ইন্টার‍্যাক্ট করতে এবং অ্যাসার্শন করতে প্রপার্টি ব্যবহার করে:
    val mySwitch = SemanticsMatcher.expectValue(
        SemanticsProperties.Role, Role.Switch
    )
    composeTestRule.onNode(mySwitch)
        .performClick()
        .assertIsOff()

Compose-এর উপরে তৈরি করা কম্পোজেবল ও মডিফায়ার ফাউন্ডেশন লাইব্রেরি আগে থেকেই ডিফল্ট হিসেবে আপনার জন্য প্রাসঙ্গিক প্রপার্টি সেট করে। বিকল্প হিসেবে, নির্দিষ্ট ব্যবহারের ক্ষেত্রে অ্যাক্সেসিবিলিটি সংক্রান্ত সহায়তা উন্নত করতে, আপনি ম্যানুয়ালি এইসব প্রপার্টি পরিবর্তন করতে পারেন অথবা আপনার কম্পোজেবলের মার্জিং বা ক্লিয়ারিং স্ট্র্যাটেজি পরিবর্তন করতে পারেন।

অ্যাক্সেসিবিলিটি পরিষেবায় আপনার কম্পোনেন্টের নির্দিষ্ট কন্টেন্টের ধরন সম্পর্কে সিগন্যাল দিতে, আপনি বিভিন্ন ধরনের সিম্যান্টিক প্রয়োগ করতে পারেন। এইসব সংযোজন মূল শব্দার্থিক তথ্যকে সঠিক জায়গায় রাখতে সাহায্য করবে এবং অ্যাক্সেসিবিলিটি পরিষেবাকে আপনার কম্পোনেন্ট কীভাবে উপস্থাপন, ঘোষণা বা ইন্টার‍্যাক্ট করা হবে তা ফাইন-টিউন করতে সাহায্য করবে।

সিম্যান্টিক প্রপার্টির সম্পূর্ণ তালিকা দেখতে, SemanticsProperties অবজেক্ট দেখুন। সম্ভাব্য অ্যাক্সেসিবিলিটি অ্যাকশনের সম্পূর্ণ তালিকার জন্য, SemanticsActions অবজেক্ট দেখুন।

শিরোনাম

অ্যাপে প্রায়ই টেক্সট-সমৃদ্ধ কন্টেন্ট সহ স্ক্রিন থাকে, যেমন দীর্ঘ নিবন্ধ বা খবরের পৃষ্ঠা, যা সাধারণত শিরোনাম সহ বিভিন্ন উপবিভাগে বিভক্ত থাকে:

স্ক্রল করা যায় এমন কন্টেনারে নিবন্ধের টেক্সট সহ ব্লগ পোস্ট।
ছবি ৩. স্ক্রল করা যায় এমন কন্টেনারে নিবন্ধের টেক্সট সহ ব্লগ পোস্ট।

অ্যাক্সেসিবিলিটি সংক্রান্ত প্রয়োজন আছে এমন ব্যবহারকারীদের এই ধরনের স্ক্রিনে নেভিগেট করতে অসুবিধা হতে পারে। নেভিগেশনের অভিজ্ঞতা উন্নত করতে, কিছু অ্যাক্সেসিবিলিটি পরিষেবা সরাসরি বিভাগ বা শিরোনামের মধ্যে আরও সহজে নেভিগেট করার অনুমতি দেয়। এটি চালু করতে, আপনার কম্পোনেন্ট যে একটি heading তা সেটির সিম্যান্টিক্স প্রপার্টি সংজ্ঞায়িত করার মাধ্যমে উল্লেখ করুন:

@Composable
private fun Subsection(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.headlineSmall,
        modifier = Modifier.semantics { heading() }
    )
}

সতর্কতা ও পপ-আপ

আপনার কম্পোনেন্ট যদি কোনও সতর্কতা বা পপ-আপ হয়, যেমন Snackbar, তাহলে আপনি হয়ত অ্যাক্সেসিবিলিটি পরিষেবাকে সিগন্যাল দিতে চাইবেন যে কন্টেন্টের নতুন স্ট্রাকচার বা আপডেট ব্যবহারকারীদের জানানো যেতে পারে।

সতর্কতার মতো কম্পোনেন্ট liveRegion সিম্যান্টিক্স প্রপার্টি দিয়ে চিহ্নিত করা যেতে পারে। এটি অ্যাক্সেসিবিলিটি পরিষেবাকে এই কম্পোনেন্ট বা এর চাইল্ডে হওয়া পরিবর্তন সম্পর্কে ব্যবহারকারীকে অটোমেটিক বিজ্ঞপ্তি পাঠানোর অনুমতি দেয়:

PopupAlert(
    message = "You have a new message",
    modifier = Modifier.semantics {
        liveRegion = LiveRegionMode.Polite
    }
)

বেশিরভাগ ক্ষেত্রে আপনার liveRegionMode.Polite ব্যবহার করা উচিত যেখানে ব্যবহারকারীর মনোযোগ শুধুমাত্র সংক্ষেপে অ্যালার্ট বা স্ক্রিনে গুরুত্বপূর্ণ পরিবর্তনশীল কন্টেন্টের দিকে আকর্ষণ করা উচিত।

বিঘ্নিত প্রতিক্রিয়া এড়াতে আপনার liveRegion.Assertive অল্প ব্যবহার করা উচিত। এটি এমন পরিস্থিতিতে ব্যবহার করা উচিত যেখানে ব্যবহারকারীদের সময়-সংবেদনশীল কন্টেন্ট সম্পর্কে অবগত করা অত্যন্ত গুরুত্বপূর্ণ:

PopupAlert(
    message = "Emergency alert incoming",
    modifier = Modifier.semantics {
        liveRegion = LiveRegionMode.Assertive
    }
)

লাইভ রিজিয়ন এমন কন্টেন্টে ব্যবহার করা উচিত নয় যা ঘন ঘন আপডেট হয়, যেমন কাউন্টডাউন টাইমার, যাতে ব্যবহারকারীকে ক্রমাগত ফিডব্যাক দিয়ে বিরক্ত না করা হয়।

উইন্ডোর মতো কম্পোনেন্ট

ModalBottomSheet-এর মতো উইন্ডো-সদৃশ কাস্টম কম্পোনেন্টকে আশেপাশের কন্টেন্ট থেকে আলাদা করতে অতিরিক্ত সিগন্যাল প্রয়োজন। এর জন্য, আপনি paneTitle সিম্যান্টিক্স ব্যবহার করতে পারেন, যাতে প্রাসঙ্গিক উইন্ডো বা প্যানে হওয়া পরিবর্তন অ্যাক্সেসিবিলিটি পরিষেবা দ্বারা সঠিকভাবে উপস্থাপন করা যায়, এর সাথে মূল সিম্যান্টিক তথ্যও থাকে:

ShareSheet(
    message = "Choose how to share this photo",
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.TopCenter)
        .semantics { paneTitle = "New bottom sheet" }
)

রেফারেন্সের জন্য, কীভাবে Material 3 তার কম্পোনেন্টের জন্য paneTitle ব্যবহার করে তা দেখুন।

সমস্যা সংক্রান্ত কম্পোনেন্ট

অন্যান্য ধরনের কন্টেন্টের জন্য, যেমন ত্রুটি-সদৃশ কম্পোনেন্ট, আপনি হয়ত অ্যাক্সেসিবিলিটি সংক্রান্ত প্রয়োজনীয়তা আছে এমন ব্যবহারকারীদের জন্য মূল শব্দার্থিক তথ্য আরও বিস্তারিতভাবে জানাতে চাইবেন। সমস্যা সংক্রান্ত স্ট্যাটাস সংজ্ঞায়িত করার সময়, আপনি অ্যাক্সেসিবিলিটি পরিষেবাকে এর error শব্দার্থবিদ্যা সম্পর্কে জানাতে এবং সমস্যা সংক্রান্ত মেসেজ আরও বিস্তারিতভাবে প্রদান করতে পারেন।

এই উদাহরণে, টকব্যাক মূল সমস্যার টেক্সট তথ্য পড়ে, তারপরে অতিরিক্ত, বিস্তারিত মেসেজ পড়ে:

Error(
    errorText = "Fields cannot be empty",
    modifier = Modifier
        .semantics {
            error("Please add both email and password")
        }
)

প্রোগ্রেস ট্র্যাক করার কম্পোনেন্ট

প্রোগ্রেস ট্র্যাক করে এমন কাস্টম কম্পোনেন্টের জন্য, আপনি ব্যবহারকারীদের তাদের প্রোগ্রেস পরিবর্তনের ব্যাপারে জানাতে চাইতে পারেন, যার মধ্যে বর্তমান প্রোগ্রেস ভ্যালু, এর রেঞ্জ এবং স্টেপ সাইজ অন্তর্ভুক্ত। আপনি progressBarRangeInfo সিম্যান্টিক্সের মাধ্যমে এটি করতে পারেন―এটি নিশ্চিত করে যে অ্যাক্সেসিবিলিটি পরিষেবাগুলি প্রগ্রেসের পরিবর্তন সম্পর্কে সচেতন এবং সেই অনুযায়ী ব্যবহারকারীদের আপডেট করতে পারে। বিভিন্ন সহায়ক প্রযুক্তিতেও প্রগ্রেস বাড়ানো ও কমানোর ইঙ্গিত দেওয়ার অনন্য উপায় থাকতে পারে।

ProgressInfoBar(
    modifier = Modifier
        .semantics {
            progressBarRangeInfo =
                ProgressBarRangeInfo(
                    current = progress,
                    range = 0F..1F
                )
        }
)

তালিকা ও আইটেম সম্পর্কিত তথ্য

অনেক আইটেম সহ কাস্টম তালিকা এবং গ্রিডে, অ্যাক্সেসিবিলিটি পরিষেবার জন্য আরও বিস্তারিত তথ্য যেমন আইটেম এবং সূচকের মোট সংখ্যা পাওয়া সহায়ক হতে পারে।

এই দীর্ঘ তালিকায়, তালিকা ও আইটেমে যথাক্রমে collectionInfo এবং collectionItemInfo সিম্যান্টিক ব্যবহার করে, অ্যাক্সেসিবিলিটি পরিষেবাগুলি ব্যবহারকারীদের টেক্সচুয়াল সিম্যান্টিক তথ্য ছাড়াও মোট সংগ্রহের মধ্যে তারা কোন আইটেম ইনডেক্সে আছে তা জানাতে পারে:

MilkyWayList(
    modifier = Modifier
        .semantics {
            collectionInfo = CollectionInfo(
                rowCount = milkyWay.count(),
                columnCount = 1
            )
        }
) {
    milkyWay.forEachIndexed { index, text ->
        Text(
            text = text,
            modifier = Modifier.semantics {
                collectionItemInfo =
                    CollectionItemInfo(index, 0, 0, 0)
            }
        )
    }
}

স্টেটের বিবরণ

কম্পোজ করার উপযুক্ত আইটেম সিম্যান্টিক্সের জন্য stateDescription সংজ্ঞায়িত করতে পারে যা Android ফ্রেমওয়ার্ক কম্পোজ করার উপযুক্ত আইটেমের স্ট্যাটাস পড়ে শোনানোর জন্য ব্যবহার করে। যেমন, টগল করা যায় এমন কম্পোজেবল "টিকচিহ্ন দেওয়া" বা "টিকচিহ্ন সরানো" অবস্থায় থাকতে পারে। কিছু ক্ষেত্রে, আপনি হয়ত Compose-এর ব্যবহার করা ডিফল্ট স্টেট বিবরণ লেবেল ওভাররাইড করতে চাইবেন। কম্পোজেবলকে টগলযোগ্য হিসেবে সংজ্ঞায়িত করার আগে আপনি স্পষ্টভাবে স্টেট বিবরণ লেবেল নির্দিষ্ট করে এটি করতে পারেন:

@Composable
private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) {
    val stateSubscribed = stringResource(R.string.subscribed)
    val stateNotSubscribed = stringResource(R.string.not_subscribed)
    Row(
        modifier = Modifier
            .semantics {
                // Set any explicit semantic properties
                stateDescription = if (selected) stateSubscribed else stateNotSubscribed
            }
            .toggleable(
                value = selected,
                onValueChange = { onToggle() }
            )
    ) {
        /* ... */
    }
}

কাস্টম অ্যাকশন

কাস্টম অ্যাকশন আরও জটিল টাচস্ক্রিন জেসচারের জন্য ব্যবহার করা যেতে পারে, যেমন বাতিল করতে সোয়াইপ করা বা টেনে নিয়ে রাখা, কারণ এগুলি প্যারালিসিসে আক্রান্ত বা অন্যান্য প্রতিবন্ধকতাযুক্ত ব্যবহারকারীদের জন্য ইন্ট্যার‍্যাক্ট করার ক্ষেত্রে চ্যালেঞ্জিং হতে পারে।

বাতিল করার জন্য সোয়াইপ করার জেসচার আরও অ্যাক্সেসযোগ্য করতে, আপনি এটি একটি কাস্টম অ্যাকশনের সাথে লিঙ্ক করতে পারেন, সেখানে বাতিল করার অ্যাকশন এবং লেবেল পাস করতে পারেন:

SwipeToDismissBox(
    modifier = Modifier.semantics {
        // Represents the swipe to dismiss for accessibility
        customActions = listOf(
            CustomAccessibilityAction(
                label = "Remove article from list",
                action = {
                    removeArticle()
                    true
                }
            )
        )
    },
    state = rememberSwipeToDismissBoxState(),
    backgroundContent = {}
) {
    ArticleListItem()
}

টকব্যাকের মতো অ্যাক্সেসিবিলিটি পরিষেবা তখন কম্পোনেন্ট হাইলাইট করে এবং ইঙ্গিত দেয় যে এর মেনুতে আরও অ্যাকশন উপলভ্য আছে, সেখানে বাতিল করার জন্য সোয়াইপ করার অ্যাকশন প্রতিনিধিত্ব করে:

টকব্যাক অ্যাকশন মেনুর ভিজ্যুয়ালাইজেশন
ছবি ৪. টকব্যাক অ্যাকশন মেনুর ভিজ্যুয়ালাইজেশন।

কাস্টম অ্যাকশনের আরেকটি ব্যবহার হল এমন আইটেমের দীর্ঘ তালিকা যার জন্য আরও উপলভ্য অ্যাকশন আছে, কারণ প্রতিটি আইটেমের জন্য আলাদাভাবে প্রতিটি অ্যাকশন পুনরাবৃত্তি করা ব্যবহারকারীদের জন্য ক্লান্তিকর হতে পারে:

=স্ক্রিনে সুইচ অ্যাক্সেস নেভিগেশনের ভিজ্যুয়ালাইজেশন
ছবি ৫. স্ক্রিনে সুইচ অ্যাক্সেস নেভিগেশনের ভিজ্যুয়ালাইজেশন।

নেভিগেশনের অভিজ্ঞতা উন্নত করতে, যা বিশেষ করে ইন্টার‍্যাকশন-ভিত্তিক সহায়ক প্রযুক্তি যেমন সুইচ অ্যাক্সেস বা ভয়েস অ্যাক্সেসের জন্য সহায়ক, আপনি কন্টেনারে কাস্টম অ্যাকশন ব্যবহার করে অ্যাকশনকে আলাদা ট্রাভার্সাল থেকে আলাদা অ্যাকশন মেনুতে সরাতে পারবেন:

ArticleListItemRow(
    modifier = Modifier
        .semantics {
            customActions = listOf(
                CustomAccessibilityAction(
                    label = "Open article",
                    action = {
                        openArticle()
                        true
                    }
                ),
                CustomAccessibilityAction(
                    label = "Add to bookmarks",
                    action = {
                        addToBookmarks()
                        true
                    }
                ),
            )
        }
) {
    Article(
        modifier = Modifier.clearAndSetSemantics { },
        onClick = openArticle,
    )
    BookmarkButton(
        modifier = Modifier.clearAndSetSemantics { },
        onClick = addToBookmarks,
    )
}

এইসব ক্ষেত্রে, আপনি যেহেতু কাস্টম অ্যাকশনে এগুলি সরাচ্ছেন, তাই clearAndSetSemantics মডিফায়ার ব্যবহার করে আসল চিলড্রেন সিম্যান্টিকস ম্যানুয়ালি মুছে দিতে ভুলবেন না।

উদাহরণ হিসেবে, সুইচ অ্যাক্সেস ব্যবহার করার সময়, কন্টেনার বেছে নিলে এর মেনু খুলে যায় এবং সেখানে উপলভ্য নেস্টেড অ্যাকশনের তালিকা দেখায়:

নিবন্ধের তালিকা আইটেমের সুইচ অ্যাক্সেস হাইলাইট
ছবি ৬. নিবন্ধের তালিকা আইটেমের সুইচ অ্যাক্সেস হাইলাইট।
'অ্যাক্সেস পাল্টান' অ্যাকশন মেনুর ভিজ্যুয়ালাইজেশন।
ছবি ৭. 'অ্যাক্সেস পাল্টান' অ্যাকশন মেনুর ভিজ্যুয়ালাইজেশন।

সেম্যান্টিক্স ট্রি

কম্পোজিশন আপনার অ্যাপের UI বর্ণনা করে এবং কম্পোজেবল রান করার মাধ্যমে তৈরি হয়। কম্পোজিশন হল একটি ট্রি-স্ট্রাকচার যা কম্পোজেবল নিয়ে গঠিত এবং এটি আপনার UI-এর বিবরণ দেয়।

কম্পোজিশনের পাশে, একটি সমান্তরাল ট্রি থাকে, যাকে সিম্যান্টিক্স ট্রি বলা হয়। এই ট্রি আপনার UI-কে বিকল্প উপায়ে বর্ণনা করে যা অ্যাক্সেসিবিলিটি পরিষেবা এবং টেস্টিং ফ্রেমওয়ার্কের জন্য বোধগম্য। নির্দিষ্ট প্রয়োজন আছে এমন ব্যবহারকারীদের কাছে অ্যাপের বিবরণ দিতে অ্যাক্সেসিবিলিটি পরিষেবা ট্রি ব্যবহার করে। আপনার অ্যাপের সাথে ইন্টার‍্যাক্ট করতে এবং এটি সম্পর্কে অ্যাসার্শন করতে টেস্টিং ফ্রেমওয়ার্ক ট্রি ব্যবহার করে। সিম্যান্টিক ট্রি-তে আপনার কম্পোজেবল কীভাবে আঁকতে হবে সেই সম্পর্কে তথ্য থাকে না, তবে এতে আপনার কম্পোজেবলের সিম্যান্টিক অর্থ সম্পর্কে তথ্য থাকে।

একটি সাধারণ UI হায়ারার্কি এবং এর সেম্যান্টিক ট্রি
ছবি ৮. একটি সাধারণ UI হায়ারার্কি ও তার সেম্যান্টিক ট্রি।

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

উদাহরণস্বরূপ, এই কাস্টম ক্যালেন্ডার কম্পোজেবল বিবেচনা করুন:

বেছে নেওয়া যায় এমন দিনের এলিমেন্ট সহ কাস্টম ক্যালেন্ডার কম্পোজেবল
ছবি ৯. বেছে নেওয়া যায় এমন দিনের এলিমেন্ট সহ একটি কাস্টম ক্যালেন্ডার কম্পোজেবল।

এই উদাহরণে, Layout কম্পোজেবল ব্যবহার করে এবং সরাসরি Canvas-এ ড্র করে, সম্পূর্ণ ক্যালেন্ডারটি একটি একক লো-লেভেল কম্পোজেবল হিসেবে প্রয়োগ করা হয়। আপনি অন্য কিছু না করলে, অ্যাক্সেসিবিলিটি পরিষেবা কম্পোজেবলের কন্টেন্ট এবং ক্যালেন্ডারের মধ্যে ব্যবহারকারীর বেছে নেওয়া বিকল্প সম্পর্কে পর্যাপ্ত তথ্য পাবে না। যেমন, কোনও ব্যবহারকারী ১৭ তারিখের উপর ক্লিক করলে, অ্যাক্সেসিবিলিটি ফ্রেমওয়ার্ক শুধু সম্পূর্ণ ক্যালেন্ডার কন্ট্রোলের বিবরণ সংক্রান্ত তথ্য পায়। এই ক্ষেত্রে, টকব্যাক অ্যাক্সেসিবিলিটি পরিষেবা "ক্যালেন্ডার" বা, সামান্য ভালভাবে, "এপ্রিল ক্যালেন্ডার" ঘোষণা করবে এবং ব্যবহারকারী কোন দিনটি বেছে নেওয়া হয়েছে তা নিয়ে বিভ্রান্তিতে পড়বেন। এই কম্পোজেবল আরও অ্যাক্সেসযোগ্য করতে, আপনাকে ম্যানুয়ালি শব্দার্থিক তথ্য যোগ করতে হবে।

মার্জ ও আনমার্জ করা ট্রি

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

এই ধরনের কম্পোজেবলের উদাহরণ হল Button। আপনি একটি বোতামকে একটি একক উপাদান হিসাবে বিবেচনা করতে পারেন, যদিও এতে একাধিক চাইল্ড নোড থাকতে পারে:

Button(onClick = { /*TODO*/ }) {
    Icon(
        imageVector = Icons.Filled.Favorite,
        contentDescription = null
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
}

সিম্যান্টিক্স ট্রিতে, বোতামের ডিসেন্ডেন্টের প্রপার্টি মার্জ করা হয়, এবং বোতামটি ট্রিতে একটি লিফ নোড হিসেবে দেখানো হয়:

মার্জ করা সিঙ্গেল লিফ সেম্যান্টিক্স রিপ্রেজেন্টেশন
ছবি ১০. মার্জ করা সিঙ্গেল লিফ সেম্যান্টিক্স রিপ্রেজেন্টেশন।

কম্পোজেবল ও মডিফায়ার Modifier.semantics (mergeDescendants = true) {} কল করে জানাতে পারে যে তারা ডিসেন্ডেন্টের সিম্যান্টিকস প্রপার্টি মার্জ করতে চায়। এই প্রপার্টি true-এ সেট করার অর্থ হল সিম্যান্টিক্স প্রপার্টি মার্জ করতে হবে। Button উদাহরণে, Button কম্পোজেবল ইন্টার্নালি clickable মডিফায়ার ব্যবহার করে যার মধ্যে এই semantics মডিফায়ার অন্তর্ভুক্ত। তাই, বোতামের ডিসেন্ডেন্ট নোড মার্জ করা হয়েছে। আপনার কম্পোজেবলে কখন মার্জিং আচরণ পরিবর্তন করবেন সেই সম্পর্কে আরও জানতে অ্যাক্সেসিবিলিটি ডকুমেন্টেশন পড়ুন।

Foundation এবং Material Compose লাইব্রেরিতে একাধিক মডিফায়ার এবং কম্পোজেবলে এই প্রপার্টি সেট করা আছে। যেমন, clickable এবং toggleable মডিফায়ার অটোমেটিক তাদের ডিসেন্ডেন্ট মার্জ করবে। এছাড়াও, ListItem কম্পোজেবল তার ডিসেন্ডেন্টদের মার্জ করবে।

গাছটি পরীক্ষা করুন

শব্দার্থের ট্রি আসলে দুটি আলাদা ট্রি। একটি মার্জ করা সিম্যান্টিক্স ট্রি আছে, যা mergeDescendants-কে true-এ সেট করা হলে ডিসেন্ডেন্ট নোড মার্জ করে। এছাড়াও, একটি আনমার্জ করা সিম্যান্টিক্স ট্রি আছে, যা মার্জিং প্রয়োগ করে না, তবে প্রতিটি নোড অক্ষত রাখে। অ্যাক্সেসিবিলিটি পরিষেবা আনমার্জ করা ট্রি ব্যবহার করে এবং mergeDescendants প্রপার্টি বিবেচনা করে নিজস্ব মার্জিং অ্যালগরিদম প্রয়োগ করে। টেস্টিং ফ্রেমওয়ার্ক ডিফল্ট হিসেবে মার্জ করা ট্রি ব্যবহার করে।

আপনি printToLog() পদ্ধতি ব্যবহার করে দুটি ট্রিই পরীক্ষা করতে পারবেন। ডিফল্ট হিসেবে এবং আগের উদাহরণের মতো, মার্জ করা ট্রি লগ করা হয়। পরিবর্তে আনমার্জ করা ট্রি প্রিন্ট করতে, onRoot() ম্যাচারের useUnmergedTree প্যারামিটার true-এ সেট করুন:

composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")

লেআউট ইন্সপেক্টর আপনাকে ভিউ ফিল্টারে পছন্দেরটি বেছে নিয়ে মার্জ করা এবং আনমার্জ করা উভয় শব্দার্থবিদ্যা ট্রি দেখাতে দেয়:

লেআউট ইন্সপেক্টর ভিউ বিকল্প, যা মার্জ করা এবং আনমার্জ করা সেম্যান্টিক্স ট্রি, দুটিরই ডিসপ্লে দেখানোর অনুমতি দেয়
ছবি ১১. লেআউট ইন্সপেক্টর ভিউ বিকল্প, যা মার্জ করা এবং আনমার্জ করা সেম্যান্টিক্স ট্রি, দুটিই দেখানোর অনুমতি দেয়।

আপনার ট্রি-এর প্রতিটি নোডের জন্য, লেআউট ইন্সপেক্টর প্রপার্টি প্যানেলে সেই নোডে সেট করা মার্জ করা সিম্যান্টিক্স এবং সিম্যান্টিক্স, দুটিই দেখায়:

সিম্যান্টিক্স প্রপার্টি মার্জ ও সেট করা হয়েছে
ছবি ১২. সিম্যান্টিক্স প্রপার্টি মার্জ ও সেট করা হয়েছে।

ডিফল্ট হিসেবে, টেস্টিং ফ্রেমওয়ার্কে ম্যাচ করার টুল মার্জ করা সেম্যান্টিক ট্রি ব্যবহার করে। সেই কারণে, আপনি Button-এর সাথে ইন্টার‍্যাক্ট করতে পারবেন, এর জন্য আপনাকে এর মধ্যে দেখানো টেক্সট ম্যাচ করতে হবে:

composeTestRule.onNodeWithText("Like").performClick()

onRoot ম্যাচারের মতো, ম্যাচারের useUnmergedTree প্যারামিটার true-এ সেট করে এই আচরণ ওভাররাইড করুন।

ট্রি অ্যাডাপ্ট করুন

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