স্প্যান হলো শক্তিশালী মার্কআপ অবজেক্ট যা ব্যবহার করে আপনি ক্যারেক্টার বা প্যারাগ্রাফ লেভেলে টেক্সটকে স্টাইল করতে পারেন। টেক্সট অবজেক্টের সাথে স্প্যান যুক্ত করে আপনি বিভিন্ন উপায়ে টেক্সট পরিবর্তন করতে পারেন, যেমন—রঙ যোগ করা, টেক্সটকে ক্লিকযোগ্য করা, টেক্সটের আকার পরিবর্তন করা এবং নিজের মতো করে টেক্সট আঁকা। এছাড়াও স্প্যান TextPaint প্রোপার্টি পরিবর্তন করতে, Canvas এ আঁকতে এবং টেক্সট লেআউট পরিবর্তন করতে পারে।
অ্যান্ড্রয়েড বিভিন্ন ধরণের স্প্যান প্রদান করে, যেগুলোতে নানা ধরনের প্রচলিত টেক্সট স্টাইলিং প্যাটার্ন অন্তর্ভুক্ত থাকে। কাস্টম স্টাইলিং প্রয়োগ করার জন্য আপনি নিজের স্প্যানও তৈরি করতে পারেন।
একটি স্প্যান তৈরি করুন এবং প্রয়োগ করুন
একটি স্প্যান তৈরি করতে, আপনি নিম্নলিখিত সারণীতে তালিকাভুক্ত ক্লাসগুলির মধ্যে একটি ব্যবহার করতে পারেন। টেক্সটটি নিজে পরিবর্তনযোগ্য কিনা, টেক্সট মার্কআপ পরিবর্তনযোগ্য কিনা, এবং কোন অন্তর্নিহিত ডেটা স্ট্রাকচারে স্প্যানের ডেটা রয়েছে, তার উপর ভিত্তি করে ক্লাসগুলি ভিন্ন হয়।
| শ্রেণী | পরিবর্তনযোগ্য পাঠ্য | পরিবর্তনযোগ্য মার্কআপ | ডেটা কাঠামো |
|---|---|---|---|
SpannedString | না | না | রৈখিক অ্যারে |
SpannableString | না | হ্যাঁ | রৈখিক অ্যারে |
SpannableStringBuilder | হ্যাঁ | হ্যাঁ | ব্যবধান গাছ |
তিনটি ক্লাসই Spanned ইন্টারফেসকে এক্সটেন্ড করে। SpannableString এবং SpannableStringBuilder আবার Spannable ইন্টারফেসকেও এক্সটেন্ড করে।
কোনটি ব্যবহার করবেন তা ঠিক করার উপায় নিচে দেওয়া হলো:
- তৈরির পর যদি আপনি টেক্সট বা মার্কআপ পরিবর্তন না করেন, তাহলে
SpannedStringব্যবহার করুন। - যদি আপনাকে একটিমাত্র টেক্সট অবজেক্টে অল্প সংখ্যক স্প্যান সংযুক্ত করতে হয় এবং টেক্সটটি পঠনযোগ্য (read-only) হয়, তাহলে
SpannableStringব্যবহার করুন। - তৈরির পর যদি টেক্সট পরিবর্তন করার প্রয়োজন হয় এবং এর সাথে স্প্যান যুক্ত করতে চান, তাহলে
SpannableStringBuilderব্যবহার করুন। - যদি কোনো টেক্সট অবজেক্টে বিপুল সংখ্যক স্প্যান সংযুক্ত করার প্রয়োজন হয়, টেক্সটটি রিড-অনলি হোক বা না হোক,
SpannableStringBuilderব্যবহার করুন।
একটি স্প্যান প্রয়োগ করতে, একটি Spannable অবজেক্টের উপর setSpan(Object _what_, int _start_, int _end_, int _flags_) কল করুন। what প্যারামিটারটি নির্দেশ করে যে আপনি টেক্সটের উপর কোন স্প্যানটি প্রয়োগ করছেন, এবং start ও end প্যারামিটার দুটি টেক্সটের সেই অংশ নির্দেশ করে যেখানে স্প্যানটি প্রয়োগ করা হচ্ছে।
আপনি যদি একটি স্প্যানের সীমানার মধ্যে টেক্সট প্রবেশ করান, তাহলে স্প্যানটি স্বয়ংক্রিয়ভাবে প্রসারিত হয়ে প্রবেশ করানো টেক্সটটিকেও অন্তর্ভুক্ত করে। স্প্যানের সীমানায় —অর্থাৎ, শুরু বা শেষের ইনডেক্সে—টেক্সট প্রবেশ করানোর সময়, স্প্যানটি প্রসারিত হয়ে প্রবেশ করানো টেক্সটটিকে অন্তর্ভুক্ত করবে কি না, তা ফ্ল্যাগস (flags) প্যারামিটার দ্বারা নির্ধারিত হয়। প্রবেশ করানো টেক্সট অন্তর্ভুক্ত করতে Spannable.SPAN_EXCLUSIVE_INCLUSIVE ফ্ল্যাগটি ব্যবহার করুন, এবং টেক্সটটি বাদ দিতে Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ফ্ল্যাগটি ব্যবহার করুন।
নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি স্ট্রিং-এর সাথে ForegroundColorSpan সংযুক্ত করতে হয়:
কোটলিন
val spannable = SpannableStringBuilder("Text is spantastic!") spannable.setSpan( ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE )
জাভা
SpannableStringBuilder spannable = new SpannableStringBuilder("Text is spantastic!"); spannable.setSpan( new ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE );

ForegroundColorSpan দিয়ে স্টাইল করা টেক্সট। যেহেতু স্প্যানটি Spannable.SPAN_EXCLUSIVE_INCLUSIVE ব্যবহার করে সেট করা হয়েছে, তাই স্প্যানটি তার সীমানায় সন্নিবেশিত টেক্সটকে অন্তর্ভুক্ত করার জন্য প্রসারিত হয়, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
val spannable = SpannableStringBuilder("Text is spantastic!") spannable.setSpan( ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE ) spannable.insert(12, "(& fon)")
জাভা
SpannableStringBuilder spannable = new SpannableStringBuilder("Text is spantastic!"); spannable.setSpan( new ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE ); spannable.insert(12, "(& fon)");

Spannable.SPAN_EXCLUSIVE_INCLUSIVE ব্যবহার করলে স্প্যানটি প্রসারিত হয়ে অতিরিক্ত টেক্সট অন্তর্ভুক্ত করে।আপনি একই টেক্সটে একাধিক স্প্যান সংযুক্ত করতে পারেন। নিচের উদাহরণটিতে দেখানো হয়েছে কীভাবে বোল্ড এবং লাল রঙের টেক্সট তৈরি করতে হয়:
কোটলিন
val spannable = SpannableString("Text is spantastic!") spannable.setSpan(ForegroundColorSpan(Color.RED), 8, 12, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) spannable.setSpan( StyleSpan(Typeface.BOLD), 8, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE )
জাভা
SpannableString spannable = new SpannableString("Text is spantastic!"); spannable.setSpan( new ForegroundColorSpan(Color.RED), 8, 12, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ); spannable.setSpan( new StyleSpan(Typeface.BOLD), 8, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );

ForegroundColorSpan(Color.RED) এবং StyleSpan(BOLD) ।অ্যান্ড্রয়েড স্প্যান প্রকার
অ্যান্ড্রয়েড তার android.text.style প্যাকেজে ২০টিরও বেশি স্প্যান টাইপ প্রদান করে। অ্যান্ড্রয়েড প্রধানত দুটি উপায়ে স্প্যানগুলোকে শ্রেণীবদ্ধ করে:
- স্প্যান কীভাবে টেক্সটকে প্রভাবিত করে: একটি স্প্যান টেক্সটের চেহারা বা টেক্সট মেট্রিক্সকে প্রভাবিত করতে পারে।
- স্প্যান স্কোপ: কিছু স্প্যান স্বতন্ত্র অক্ষরের উপর প্রয়োগ করা যায়, আবার অন্যগুলো অবশ্যই সম্পূর্ণ অনুচ্ছেদের উপর প্রয়োগ করতে হয়।

নিম্নলিখিত বিভাগগুলিতে এই বিভাগগুলি আরও বিশদভাবে বর্ণনা করা হয়েছে।
যে স্প্যানগুলো টেক্সটের চেহারাকে প্রভাবিত করে
ক্যারেক্টার লেভেলে প্রয়োগ করা কিছু স্প্যান টেক্সটের চেহারাকে প্রভাবিত করে, যেমন টেক্সট বা ব্যাকগ্রাউন্ডের রঙ পরিবর্তন করা এবং আন্ডারলাইন বা স্ট্রাইকথ্রু যোগ করা। এই স্প্যানগুলো CharacterStyle ক্লাসকে এক্সটেন্ড করে।
নিচের কোড উদাহরণটিতে দেখানো হয়েছে কিভাবে কোনো টেক্সটের নিচে আন্ডারলাইন করার জন্য একটি UnderlineSpan প্রয়োগ করতে হয়:
কোটলিন
val string = SpannableString("Text with underline span") string.setSpan(UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
জাভা
SpannableString string = new SpannableString("Text with underline span"); string.setSpan(new UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

UnderlineSpan ব্যবহার করে লেখার নিচে দাগ দেওয়া। যে স্প্যানগুলো শুধুমাত্র টেক্সটের চেহারাকে প্রভাবিত করে, সেগুলো লেআউটের পুনর্গণনা না করেই টেক্সটকে পুনরায় আঁকে। এই স্প্যানগুলো UpdateAppearance ইমপ্লিমেন্ট করে এবং CharacterStyle এক্সটেন্ড করে। CharacterStyle সাবক্লাসগুলো TextPaint আপডেট করার অ্যাক্সেস প্রদানের মাধ্যমে টেক্সট কীভাবে আঁকতে হবে তা নির্ধারণ করে।
যে স্প্যানগুলো টেক্সট মেট্রিক্সকে প্রভাবিত করে
অন্যান্য স্প্যান, যা ক্যারেক্টার লেভেলে প্রয়োগ করা হয়, তা লাইন হাইট এবং টেক্সট সাইজের মতো টেক্সট মেট্রিকগুলোকে প্রভাবিত করে। এই স্প্যানগুলো MetricAffectingSpan ক্লাসকে এক্সটেন্ড করে।
নিম্নলিখিত কোড উদাহরণটি একটি RelativeSizeSpan তৈরি করে যা টেক্সটের আকার ৫০% বৃদ্ধি করে:
কোটলিন
val string = SpannableString("Text with relative size span") string.setSpan(RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
জাভা
SpannableString string = new SpannableString("Text with relative size span"); string.setSpan(new RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

RelativeSizeSpan ব্যবহার করে লেখাকে বড় করা হয়েছে।টেক্সট মেট্রিক্সকে প্রভাবিত করে এমন একটি স্প্যান প্রয়োগ করলে, একটি অবজার্ভিং অবজেক্ট সঠিক লেআউট এবং রেন্ডারিংয়ের জন্য টেক্সটটিকে পুনরায় পরিমাপ করে—উদাহরণস্বরূপ, টেক্সটের আকার পরিবর্তন করলে শব্দগুলো ভিন্ন ভিন্ন লাইনে প্রদর্শিত হতে পারে। পূর্ববর্তী স্প্যানটি প্রয়োগ করলে একটি পুনঃপরিমাপ, টেক্সট লেআউটের পুনঃগণনা এবং টেক্সটটির পুনঃঅঙ্কন শুরু হয়।
যে স্প্যানগুলো টেক্সট মেট্রিক্সকে প্রভাবিত করে, সেগুলো MetricAffectingSpan ক্লাসকে এক্সটেন্ড করে। এই অ্যাবস্ট্রাক্ট ক্লাসটি সাবক্লাসগুলোকে TextPaint এ অ্যাক্সেস দেওয়ার মাধ্যমে নির্ধারণ করতে দেয় যে স্প্যানটি কীভাবে টেক্সট পরিমাপকে প্রভাবিত করবে। যেহেতু MetricAffectingSpan , CharacterStyle এক্সটেন্ড করে, তাই সাবক্লাসগুলো ক্যারেক্টার লেভেলে টেক্সটের চেহারাকে প্রভাবিত করতে পারে।
অনুচ্ছেদকে প্রভাবিত করে এমন স্প্যান
একটি স্প্যান প্যারাগ্রাফ স্তরের টেক্সটকেও প্রভাবিত করতে পারে, যেমন কোনো টেক্সট ব্লকের অ্যালাইনমেন্ট বা মার্জিন পরিবর্তন করা। যে স্প্যানগুলো পুরো প্যারাগ্রাফকে প্রভাবিত করে, সেগুলো ParagraphStyle প্রয়োগ করে। এই স্প্যানগুলো ব্যবহার করার জন্য, শেষের নিউ লাইন ক্যারেক্টারটি বাদে পুরো প্যারাগ্রাফটিতে এগুলো যুক্ত করতে হয়। আপনি যদি পুরো প্যারাগ্রাফ ছাড়া অন্য কোনো কিছুতে প্যারাগ্রাফ স্প্যান প্রয়োগ করার চেষ্টা করেন, তাহলে অ্যান্ড্রয়েড স্প্যানটি মোটেই প্রয়োগ করে না।
চিত্র ৮-এ দেখানো হয়েছে অ্যান্ড্রয়েড কীভাবে টেক্সটের প্যারাগ্রাফগুলো আলাদা করে।

\n ) চিহ্ন দিয়ে শেষ হয়। নিম্নলিখিত কোড উদাহরণটি একটি প্যারাগ্রাফে QuoteSpan প্রয়োগ করে। লক্ষ্য করুন যে, যদি আপনি প্যারাগ্রাফের শুরু বা শেষ ছাড়া অন্য কোনো অবস্থানে স্প্যানটি সংযুক্ত করেন, তাহলে অ্যান্ড্রয়েড স্টাইলটি মোটেও প্রয়োগ করে না।
কোটলিন
spannable.setSpan(QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
জাভা
spannable.setSpan(new QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

QuoteSpan প্রয়োগ।কাস্টম স্প্যান তৈরি করুন
বিদ্যমান অ্যান্ড্রয়েড স্প্যানগুলিতে প্রদত্ত কার্যকারিতার চেয়ে আপনার যদি আরও বেশি কার্যকারিতার প্রয়োজন হয়, তবে আপনি একটি কাস্টম স্প্যান তৈরি করতে পারেন। আপনার নিজের স্প্যান তৈরি করার সময়, স্থির করুন যে আপনার স্প্যানটি টেক্সটকে ক্যারেক্টার লেভেলে নাকি প্যারাগ্রাফ লেভেলে প্রভাবিত করবে এবং এটি টেক্সটের লেআউট বা চেহারাকে প্রভাবিত করবে কিনা। এটি আপনাকে নির্ধারণ করতে সাহায্য করবে যে আপনি কোন বেস ক্লাসগুলি এক্সটেন্ড করতে পারেন এবং কোন ইন্টারফেসগুলি আপনাকে ইমপ্লিমেন্ট করতে হতে পারে। রেফারেন্সের জন্য নিম্নলিখিত টেবিলটি ব্যবহার করুন:
| দৃশ্যকল্প | ক্লাস বা ইন্টারফেস |
|---|---|
| আপনার স্প্যান অক্ষর স্তরে টেক্সটকে প্রভাবিত করে। | CharacterStyle |
| আপনার স্প্যান টেক্সটের চেহারাকে প্রভাবিত করে। | UpdateAppearance |
| আপনার স্প্যান টেক্সট মেট্রিক্সকে প্রভাবিত করে। | UpdateLayout |
| আপনার স্প্যান অনুচ্ছেদ স্তরের লেখাকে প্রভাবিত করে। | ParagraphStyle |
উদাহরণস্বরূপ, যদি আপনার টেক্সটের আকার এবং রঙ পরিবর্তন করে এমন একটি কাস্টম স্প্যান তৈরি করার প্রয়োজন হয়, তাহলে RelativeSizeSpan এক্সটেন্ড করুন। ইনহেরিটেন্সের মাধ্যমে, RelativeSizeSpan CharacterStyle এক্সটেন্ড করে এবং দুটি Update ইন্টারফেস ইমপ্লিমেন্ট করে। যেহেতু এই ক্লাসটি ইতিমধ্যেই updateDrawState এবং updateMeasureState এর জন্য কলব্যাক প্রদান করে, আপনি আপনার নিজস্ব আচরণ প্রয়োগ করার জন্য এই কলব্যাকগুলো ওভাররাইড করতে পারেন। নিচের কোডটি একটি কাস্টম স্প্যান তৈরি করে যা RelativeSizeSpan এক্সটেন্ড করে এবং TextPaint এর রঙ সেট করার জন্য updateDrawState কলব্যাকটি ওভাররাইড করে:
কোটলিন
class RelativeSizeColorSpan( size: Float, @ColorInt private val color: Int ) : RelativeSizeSpan(size) { override fun updateDrawState(textPaint: TextPaint) { super.updateDrawState(textPaint) textPaint.color = color } }
জাভা
public class RelativeSizeColorSpan extends RelativeSizeSpan { private int color; public RelativeSizeColorSpan(float spanSize, int spanColor) { super(spanSize); color = spanColor; } @Override public void updateDrawState(TextPaint textPaint) { super.updateDrawState(textPaint); textPaint.setColor(color); } }
এই উদাহরণটি একটি কাস্টম স্প্যান তৈরি করার পদ্ধতি প্রদর্শন করে। আপনি টেক্সটে RelativeSizeSpan এবং ForegroundColorSpan প্রয়োগ করেও একই প্রভাব অর্জন করতে পারেন।
পরীক্ষার সময়কাল ব্যবহার
Spanned ইন্টারফেসটি আপনাকে স্প্যান সেট করতে এবং টেক্সট থেকে স্প্যান পুনরুদ্ধার করতে উভয়ই দেয়। পরীক্ষা করার সময়, সঠিক স্প্যানগুলি সঠিক স্থানে যুক্ত হয়েছে কিনা তা যাচাই করার জন্য একটি অ্যান্ড্রয়েড JUnit টেস্ট প্রয়োগ করুন। টেক্সট স্টাইলিং স্যাম্পল অ্যাপটিতে একটি স্প্যান রয়েছে যা টেক্সটের সাথে BulletPointSpan সংযুক্ত করে বুলেট পয়েন্টগুলিতে মার্কআপ প্রয়োগ করে। বুলেট পয়েন্টগুলি প্রত্যাশিতভাবে প্রদর্শিত হচ্ছে কিনা তা কীভাবে পরীক্ষা করতে হয়, তা নিম্নলিখিত কোড উদাহরণে দেখানো হয়েছে:
কোটলিন
@Test fun textWithBulletPoints() { val result = builder.markdownToSpans("Points\n* one\n+ two") // Check whether the markup tags are removed. assertEquals("Points\none\ntwo", result.toString()) // Get all the spans attached to the SpannedString. val spans = result.getSpans<Any>(0, result.length, Any::class.java) // Check whether the correct number of spans are created. assertEquals(2, spans.size.toLong()) // Check whether the spans are instances of BulletPointSpan. val bulletSpan1 = spans[0] as BulletPointSpan val bulletSpan2 = spans[1] as BulletPointSpan // Check whether the start and end indices are the expected ones. assertEquals(7, result.getSpanStart(bulletSpan1).toLong()) assertEquals(11, result.getSpanEnd(bulletSpan1).toLong()) assertEquals(11, result.getSpanStart(bulletSpan2).toLong()) assertEquals(14, result.getSpanEnd(bulletSpan2).toLong()) }
জাভা
@Test public void textWithBulletPoints() { SpannedString result = builder.markdownToSpans("Points\n* one\n+ two"); // Check whether the markup tags are removed. assertEquals("Points\none\ntwo", result.toString()); // Get all the spans attached to the SpannedString. Object[] spans = result.getSpans(0, result.length(), Object.class); // Check whether the correct number of spans are created. assertEquals(2, spans.length); // Check whether the spans are instances of BulletPointSpan. BulletPointSpan bulletSpan1 = (BulletPointSpan) spans[0]; BulletPointSpan bulletSpan2 = (BulletPointSpan) spans[1]; // Check whether the start and end indices are the expected ones. assertEquals(7, result.getSpanStart(bulletSpan1)); assertEquals(11, result.getSpanEnd(bulletSpan1)); assertEquals(11, result.getSpanStart(bulletSpan2)); assertEquals(14, result.getSpanEnd(bulletSpan2)); }
আরও পরীক্ষার উদাহরণের জন্য, গিটহাবে MarkdownBuilderTest দেখুন।
কাস্টম স্প্যান পরীক্ষা করুন
স্প্যান পরীক্ষা করার সময়, যাচাই করুন যে TextPaint প্রত্যাশিত পরিবর্তনগুলো রয়েছে এবং আপনার Canvas এ সঠিক উপাদানগুলো প্রদর্শিত হচ্ছে। উদাহরণস্বরূপ, একটি কাস্টম স্প্যান ইমপ্লিমেন্টেশনের কথা ভাবুন যা কোনো টেক্সটের শুরুতে একটি বুলেট পয়েন্ট যুক্ত করে। বুলেট পয়েন্টটির একটি নির্দিষ্ট আকার ও রঙ রয়েছে এবং ড্রয়েবল এরিয়ার বাম মার্জিন ও বুলেট পয়েন্টের মধ্যে একটি ফাঁকা জায়গা আছে।
আপনি একটি AndroidJUnit টেস্ট ইমপ্লিমেন্ট করে এই ক্লাসের আচরণ পরীক্ষা করতে পারেন, যেখানে নিম্নলিখিত বিষয়গুলো যাচাই করতে হবে:
- যদি আপনি স্প্যানটি সঠিকভাবে প্রয়োগ করেন, তাহলে ক্যানভাসে নির্দিষ্ট আকার ও রঙের একটি বুলেট পয়েন্ট প্রদর্শিত হয় এবং বাম মার্জিন ও বুলেট পয়েন্টের মধ্যে যথাযথ ফাঁকা স্থান বজায় থাকে।
- আপনি স্প্যানটি প্রয়োগ না করলে, কোনো কাস্টম আচরণই প্রদর্শিত হবে না।
আপনি গিটহাবে থাকা TextStyling স্যাম্পলটিতে এই টেস্টগুলোর বাস্তবায়ন দেখতে পারেন।
আপনি ক্যানভাসকে মক করে, মক করা অবজেক্টটিকে drawLeadingMargin() মেথডে পাস করে এবং সঠিক প্যারামিটার সহ সঠিক মেথডগুলো কল করা হচ্ছে কিনা তা যাচাই করে ক্যানভাসের ইন্টারঅ্যাকশন পরীক্ষা করতে পারেন।
আপনি BulletPointSpanTest- এ আরও স্প্যান টেস্টের নমুনা খুঁজে পেতে পারেন।
স্প্যান ব্যবহারের সর্বোত্তম অনুশীলন
আপনার প্রয়োজন অনুযায়ী, একটি TextView তে টেক্সট সেট করার জন্য বেশ কয়েকটি মেমরি-সাশ্রয়ী উপায় রয়েছে।
অন্তর্নিহিত টেক্সট পরিবর্তন না করে একটি স্প্যান সংযুক্ত বা বিচ্ছিন্ন করুন
TextView.setText() -এর একাধিক ওভারলোড রয়েছে যা স্প্যানকে ভিন্নভাবে পরিচালনা করে। উদাহরণস্বরূপ, আপনি নিম্নলিখিত কোড ব্যবহার করে একটি Spannable টেক্সট অবজেক্ট সেট করতে পারেন:
কোটলিন
textView.setText(spannableObject)
জাভা
textView.setText(spannableObject);
setText() এর এই ওভারলোডটি কল করলে, TextView আপনার Spannable এর একটি অনুলিপি SpannedString হিসেবে তৈরি করে এবং সেটিকে CharSequence হিসেবে মেমরিতে সংরক্ষণ করে। এর মানে হলো, আপনার টেক্সট এবং স্প্যানগুলো অপরিবর্তনীয় (immutable), তাই যখন আপনার টেক্সট বা স্প্যানগুলো আপডেট করার প্রয়োজন হয়, তখন একটি নতুন Spannable অবজেক্ট তৈরি করে আবার setText() কল করুন, যা লেআউটের পুনরায় পরিমাপ এবং অঙ্কনকেও সক্রিয় করে।
স্প্যানগুলো যে পরিবর্তনযোগ্য হতে হবে তা বোঝাতে, আপনি এর পরিবর্তে setText(CharSequence text, TextView.BufferType type) ব্যবহার করতে পারেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
textView.setText(spannable, BufferType.SPANNABLE) val spannableText = textView.text as Spannable spannableText.setSpan( ForegroundColorSpan(color), 8, spannableText.length, SPAN_INCLUSIVE_INCLUSIVE )
জাভা
textView.setText(spannable, BufferType.SPANNABLE); Spannable spannableText = (Spannable) textView.getText(); spannableText.setSpan( new ForegroundColorSpan(color), 8, spannableText.getLength(), SPAN_INCLUSIVE_INCLUSIVE);
এই উদাহরণে, BufferType.SPANNABLE প্যারামিটারটি TextView কে একটি SpannableString তৈরি করতে নির্দেশ দেয়, এবং TextView দ্বারা সংরক্ষিত CharSequence অবজেক্টটিতে এখন পরিবর্তনযোগ্য মার্কআপ ও অপরিবর্তনযোগ্য টেক্সট থাকে। স্প্যানটি আপডেট করতে, টেক্সটটিকে একটি Spannable হিসেবে গ্রহণ করুন এবং তারপর প্রয়োজন অনুযায়ী স্প্যানগুলো আপডেট করুন।
যখন আপনি স্প্যান সংযুক্ত, বিচ্ছিন্ন বা পুনঃস্থাপন করেন, তখন টেক্সটের পরিবর্তন প্রতিফলিত করার জন্য TextView স্বয়ংক্রিয়ভাবে আপডেট হয়। যদি আপনি বিদ্যমান কোনো স্প্যানের অভ্যন্তরীণ অ্যাট্রিবিউট পরিবর্তন করেন, তাহলে বাহ্যিক রূপ-সম্পর্কিত পরিবর্তনের জন্য invalidate() অথবা মেট্রিক-সম্পর্কিত পরিবর্তনের জন্য requestLayout() কল করুন।
একটি TextView-তে একাধিকবার টেক্সট সেট করুন
কিছু ক্ষেত্রে, যেমন RecyclerView.ViewHolder ব্যবহার করার সময়, আপনি একটি TextView পুনরায় ব্যবহার করতে এবং একাধিকবার টেক্সট সেট করতে চাইতে পারেন। ডিফল্টরূপে, আপনি BufferType সেট করুন বা না করুন, TextView টি CharSequence অবজেক্টের একটি অনুলিপি তৈরি করে এবং সেটিকে মেমরিতে ধরে রাখে। এর ফলে TextView সমস্ত আপডেট ইচ্ছাকৃত হয়—টেক্সট আপডেট করার জন্য আপনি মূল CharSequence অবজেক্টটি আপডেট করতে পারবেন না। এর মানে হলো, প্রতিবার আপনি নতুন টেক্সট সেট করার সময় TextView টি একটি নতুন অবজেক্ট তৈরি করে।
এই প্রক্রিয়াটির উপর আরও বেশি নিয়ন্ত্রণ নিতে এবং অতিরিক্ত অবজেক্ট তৈরি করা এড়াতে চাইলে, আপনি নিজের Spannable.Factory ইমপ্লিমেন্ট করে newSpannable() ওভাররাইড করতে পারেন। একটি নতুন টেক্সট অবজেক্ট তৈরি করার পরিবর্তে, আপনি বিদ্যমান CharSequence Spannable হিসেবে কাস্ট করে রিটার্ন করতে পারেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
val spannableFactory = object : Spannable.Factory() { override fun newSpannable(source: CharSequence?): Spannable { return source as Spannable } }
Java
Spannable.Factory spannableFactory = new Spannable.Factory(){ @Override public Spannable newSpannable(CharSequence source) { return (Spannable) source; } };
টেক্সট সেট করার সময় আপনাকে অবশ্যই textView.setText(spannableObject, BufferType.SPANNABLE) ব্যবহার করতে হবে। অন্যথায়, সোর্স CharSequence একটি Spanned ইনস্ট্যান্স হিসেবে তৈরি হয় এবং একে Spannable এ কাস্ট করা যায় না, যার ফলে newSpannable() একটি ClassCastException থ্রো করে।
newSpannable() ওভাররাইড করার পর, TextView কে নতুন Factory ব্যবহার করতে বলুন:
কোটলিন
textView.setSpannableFactory(spannableFactory)
জাভা
textView.setSpannableFactory(spannableFactory);
আপনার TextView এর রেফারেন্স পাওয়ার ঠিক পরেই Spannable.Factory অবজেক্টটি একবার সেট করুন। যদি আপনি RecyclerView ব্যবহার করেন, তবে আপনার ভিউগুলো প্রথমবার ইনফ্লেট করার সময় Factory অবজেক্টটি সেট করুন। এর ফলে, যখন আপনার RecyclerView আপনার ViewHolder সাথে একটি নতুন আইটেম বাইন্ড করে, তখন অতিরিক্ত অবজেক্ট তৈরি হওয়া এড়ানো যায়।
অভ্যন্তরীণ স্প্যান বৈশিষ্ট্য পরিবর্তন করুন
যদি আপনাকে একটি পরিবর্তনযোগ্য স্প্যানের শুধুমাত্র কোনো অভ্যন্তরীণ অ্যাট্রিবিউট পরিবর্তন করতে হয়, যেমন একটি কাস্টম বুলেট স্প্যানের বুলেটের রঙ, তাহলে স্প্যানটি তৈরি করার সময় সেটির একটি রেফারেন্স রেখে আপনি একাধিকবার setText() কল করার অতিরিক্ত ঝামেলা এড়াতে পারেন। যখন স্প্যানটি পরিবর্তন করার প্রয়োজন হবে, তখন আপনি রেফারেন্সটি পরিবর্তন করতে পারেন এবং তারপরে, আপনার পরিবর্তন করা অ্যাট্রিবিউটের ধরনের উপর নির্ভর করে TextView তে invalidate() বা requestLayout() কল করতে পারেন।
নিম্নলিখিত কোড উদাহরণে, একটি কাস্টম বুলেট পয়েন্টের ডিফল্ট রঙ লাল, যা একটি বোতামে ট্যাপ করলে ধূসর রঙে পরিবর্তিত হয়:
কোটলিন
class MainActivity : AppCompatActivity() { // Keeping the span as a field. val bulletSpan = BulletPointSpan(color = Color.RED) override fun onCreate(savedInstanceState: Bundle?) { ... val spannable = SpannableString("Text is spantastic") // Setting the span to the bulletSpan field. spannable.setSpan( bulletSpan, 0, 4, Spanned.SPAN_INCLUSIVE_INCLUSIVE ) styledText.setText(spannable) button.setOnClickListener { // Change the color of the mutable span. bulletSpan.color = Color.GRAY // Color doesn't change until invalidate is called. styledText.invalidate() } } }
জাভা
public class MainActivity extends AppCompatActivity { private BulletPointSpan bulletSpan = new BulletPointSpan(Color.RED); @Override protected void onCreate(Bundle savedInstanceState) { ... SpannableString spannable = new SpannableString("Text is spantastic"); // Setting the span to the bulletSpan field. spannable.setSpan(bulletSpan, 0, 4, Spanned.SPAN_INCLUSIVE_INCLUSIVE); styledText.setText(spannable); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Change the color of the mutable span. bulletSpan.setColor(Color.GRAY); // Color doesn't change until invalidate is called. styledText.invalidate(); } }); } }
অ্যান্ড্রয়েড KTX এক্সটেনশন ফাংশন ব্যবহার করুন
অ্যান্ড্রয়েড KTX-এ এক্সটেনশন ফাংশনও রয়েছে যা স্প্যান নিয়ে কাজ করা সহজ করে তোলে। আরও জানতে, androidx.core.text প্যাকেজের ডকুমেন্টেশন দেখুন।
