স্প্যান

রচনা পদ্ধতি চেষ্টা করুন
জেটপ্যাক কম্পোজ হল Android এর জন্য প্রস্তাবিত UI টুলকিট। কম্পোজে টেক্সট ব্যবহার করতে শিখুন।

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

অ্যান্ড্রয়েড বিভিন্ন ধরণের স্প্যান সরবরাহ করে যা বিভিন্ন সাধারণ পাঠ্য স্টাইলিং প্যাটার্নগুলিকে কভার করে৷ আপনি কাস্টম স্টাইলিং প্রয়োগ করতে আপনার নিজস্ব স্প্যান তৈরি করতে পারেন।

একটি স্প্যান তৈরি করুন এবং প্রয়োগ করুন

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

ক্লাস পরিবর্তনযোগ্য পাঠ্য পরিবর্তনযোগ্য মার্কআপ ডেটা স্ট্রাকচার
SpannedString না না লিনিয়ার অ্যারে
SpannableString না হ্যাঁ লিনিয়ার অ্যারে
SpannableStringBuilder হ্যাঁ হ্যাঁ ব্যবধান গাছ

তিনটি ক্লাসই Spanned ইন্টারফেস প্রসারিত করে। SpannableString এবং SpannableStringBuilder এছাড়াও Spannable ইন্টারফেস প্রসারিত করে।

কোনটি ব্যবহার করবেন তা এখানে কীভাবে সিদ্ধান্ত নেওয়া যায়:

  • আপনি যদি তৈরি করার পরে টেক্সট বা মার্কআপ পরিবর্তন না করেন, তাহলে SpannedString ব্যবহার করুন।
  • আপনি যদি একটি একক পাঠ্য বস্তুর সাথে অল্প সংখ্যক স্প্যান সংযুক্ত করতে চান এবং পাঠ্যটি কেবলমাত্র পঠনযোগ্য হয়, তাহলে SpannableString ব্যবহার করুন।
  • আপনি যদি তৈরি করার পরে পাঠ্য পরিবর্তন করতে চান এবং আপনাকে পাঠ্যের সাথে স্প্যান সংযুক্ত করতে হবে, SpannableStringBuilder ব্যবহার করুন।
  • আপনি যদি একটি পাঠ্য বস্তুর সাথে প্রচুর সংখ্যক স্প্যান সংযুক্ত করতে চান, পাঠ্যটি শুধুমাত্র পাঠযোগ্য কিনা তা নির্বিশেষে, SpannableStringBuilder ব্যবহার করুন।

একটি স্প্যান প্রয়োগ করতে, একটি Spannable বস্তুতে setSpan(Object _what_, int _start_, int _end_, int _flags_) কল করুন। কোন প্যারামিটারটি আপনি পাঠ্যটিতে যে স্প্যানটি প্রয়োগ করছেন তা বোঝায় এবং শুরু এবং শেষ পরামিতিগুলি পাঠ্যের যে অংশটিতে আপনি স্প্যানটি প্রয়োগ করছেন তা নির্দেশ করে৷

আপনি যদি একটি স্প্যানের সীমানার মধ্যে পাঠ্য সন্নিবেশ করেন, স্প্যানটি স্বয়ংক্রিয়ভাবে সন্নিবেশিত পাঠ্য অন্তর্ভুক্ত করতে প্রসারিত হয়। স্প্যান বাউন্ডারিতে টেক্সট ঢোকানোর সময়—অর্থাৎ, শুরু বা শেষ সূচকে— ফ্ল্যাগ প্যারামিটার নির্ধারণ করে যে স্প্যানটি সন্নিবেশিত পাঠ্য অন্তর্ভুক্ত করতে প্রসারিত হবে কিনা। ঢোকানো পাঠ্য অন্তর্ভুক্ত করতে Spannable.SPAN_EXCLUSIVE_INCLUSIVE পতাকা ব্যবহার করুন এবং ঢোকানো পাঠ্যটি বাদ দিতে Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ব্যবহার করুন৷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
);
একটি চিত্র একটি ধূসর পাঠ্য দেখাচ্ছে, আংশিক লাল৷
চিত্র 1. ForegroundColorSpan দিয়ে স্টাইল করা টেক্সট।

কারণ স্প্যানটি Spannable.SPAN_EXCLUSIVE_INCLUSIVE ব্যবহার করে সেট করা হয়েছে৷ 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)");
যখন SPAN_EXCLUSIVE_INCLUSIVE ব্যবহার করা হয় তখন স্প্যান কীভাবে আরও পাঠ্য অন্তর্ভুক্ত করে তা দেখানো একটি চিত্র৷
চিত্র 2. Spannable.SPAN_EXCLUSIVE_INCLUSIVE ব্যবহার করার সময় অতিরিক্ত পাঠ্য অন্তর্ভুক্ত করার জন্য স্প্যানটি প্রসারিত হয়৷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)`
চিত্র 3. একাধিক স্প্যান সহ পাঠ্য: ForegroundColorSpan(Color.RED) এবং StyleSpan(BOLD)

অ্যান্ড্রয়েড স্প্যান প্রকার

Android android.text.style প্যাকেজে 20টিরও বেশি স্প্যান প্রকার সরবরাহ করে। অ্যান্ড্রয়েড দুটি প্রাথমিক উপায়ে স্প্যানকে শ্রেণীবদ্ধ করে:

  • স্প্যান কীভাবে পাঠ্যকে প্রভাবিত করে: একটি স্প্যান পাঠ্যের উপস্থিতি বা পাঠ্য মেট্রিক্সকে প্রভাবিত করতে পারে।
  • স্প্যান স্কোপ: কিছু স্প্যান পৃথক অক্ষরগুলিতে প্রয়োগ করা যেতে পারে, অন্যগুলি অবশ্যই একটি সম্পূর্ণ অনুচ্ছেদে প্রয়োগ করতে হবে।
বিভিন্ন স্প্যান বিভাগ দেখানো একটি চিত্র
চিত্র 4. অ্যান্ড্রয়েড স্প্যানের বিভাগগুলি।

নিম্নলিখিত বিভাগগুলি এই বিভাগগুলিকে আরও বিশদে বর্ণনা করে৷

স্প্যান যা পাঠ্যের চেহারাকে প্রভাবিত করে

অক্ষর স্তরে প্রযোজ্য কিছু স্প্যান পাঠ্যের চেহারাকে প্রভাবিত করে, যেমন পাঠ্য বা পটভূমির রঙ পরিবর্তন করা এবং আন্ডারলাইন বা স্ট্রাইকথ্রু যোগ করা। এই স্প্যানগুলি 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);
একটি `আন্ডারলাইনস্প্যান` ব্যবহার করে পাঠ্যকে কীভাবে আন্ডারলাইন করতে হয় তা দেখানো একটি চিত্র
চিত্র 5. একটি UnderlineSpan ব্যবহার করে আন্ডারলাইন করা পাঠ্য।

যে স্প্যানগুলি শুধুমাত্র পাঠ্যের চেহারাকে প্রভাবিত করে সেগুলি লেআউটের পুনঃগণনা ট্রিগার না করেই পাঠ্যের একটি পুনঃআঁকে ট্রিগার করে। এই স্প্যানগুলি UpdateAppearance বাস্তবায়ন করে এবং CharacterStyle প্রসারিত করে। CharacterStyle সাবক্লাস TextPaint আপডেট করার অ্যাক্সেস প্রদান করে কীভাবে পাঠ্য আঁকতে হয় তা সংজ্ঞায়িত করে।

স্প্যান যা টেক্সট মেট্রিক্সকে প্রভাবিত করে

অক্ষর স্তরে প্রযোজ্য অন্যান্য স্প্যানগুলি পাঠ্য মেট্রিক্সকে প্রভাবিত করে, যেমন লাইনের উচ্চতা এবং পাঠ্যের আকার। এই স্প্যানগুলি MetricAffectingSpan ক্লাস প্রসারিত করে।

নিম্নলিখিত কোড উদাহরণটি একটি RelativeSizeSpan তৈরি করে যা পাঠ্যের আকার 50% বৃদ্ধি করে:

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 এর ব্যবহার দেখানো একটি চিত্র
চিত্র 6. একটি RelativeSizeSpan ব্যবহার করে পাঠ্যকে বড় করা হয়েছে।

টেক্সট মেট্রিক্সকে প্রভাবিত করে এমন একটি স্প্যান প্রয়োগ করার ফলে একটি পর্যবেক্ষক বস্তু সঠিক লেআউট এবং রেন্ডারিংয়ের জন্য টেক্সটকে পুনরায় পরিমাপ করতে পারে—উদাহরণস্বরূপ, পাঠ্যের আকার পরিবর্তন করার ফলে শব্দগুলি বিভিন্ন লাইনে প্রদর্শিত হতে পারে। পূর্ববর্তী স্প্যানটি প্রয়োগ করা একটি পুনঃপরিমাপ, পাঠ্য বিন্যাসের পুনঃগণনা এবং পাঠ্যের পুনরায় অঙ্কনকে ট্রিগার করে।

স্প্যানগুলি যেগুলি পাঠ্যের মেট্রিক্সকে প্রভাবিত করে সেগুলি MetricAffectingSpan ক্লাসকে প্রসারিত করে, একটি বিমূর্ত শ্রেণী যা সাবক্লাসগুলিকে সংজ্ঞায়িত করতে দেয় যে স্প্যানটি TextPaint এ অ্যাক্সেস প্রদান করে পাঠ্য পরিমাপকে কীভাবে প্রভাবিত করে। যেহেতু MetricAffectingSpan CharacterSpan প্রসারিত করে, তাই সাবক্লাসগুলি অক্ষর স্তরে পাঠ্যের উপস্থিতিকে প্রভাবিত করে।

স্প্যান যা অনুচ্ছেদকে প্রভাবিত করে

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

চিত্র 8 দেখায় কিভাবে Android পাঠ্যের অনুচ্ছেদগুলিকে আলাদা করে।

চিত্র 7. অ্যান্ড্রয়েডে, অনুচ্ছেদ একটি নতুন লাইন ( \n ) অক্ষর দিয়ে শেষ হয়।

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

spannable.setSpan(QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(new QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
QuoteSpan এর একটি উদাহরণ দেখানো একটি চিত্র
চিত্র 8. একটি অনুচ্ছেদে প্রয়োগ করা একটি 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 ইন্টারফেস আপনাকে স্প্যান সেট করতে এবং পাঠ্য থেকে স্প্যান পুনরুদ্ধার করতে দেয়। পরীক্ষা করার সময়, সঠিক স্থানে সঠিক স্প্যান যোগ করা হয়েছে তা যাচাই করতে একটি Android 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));
}

আরও পরীক্ষার উদাহরণের জন্য, GitHub-এ MarkdownBuilderTest দেখুন।

কাস্টম স্প্যান পরীক্ষা করুন

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

আপনি একটি AndroidJUnit পরীক্ষা প্রয়োগ করে এই শ্রেণীর আচরণ পরীক্ষা করতে পারেন, নিম্নলিখিতগুলি পরীক্ষা করে:

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

আপনি GitHub এ TextStyling নমুনায় এই পরীক্ষার বাস্তবায়ন দেখতে পারেন।

আপনি ক্যানভাসকে উপহাস করে, উপহাস করা বস্তুটিকে drawLeadingMargin() পদ্ধতিতে পাস করে এবং সঠিক প্যারামিটারের সাথে সঠিক পদ্ধতিগুলিকে কল করা হয়েছে তা যাচাই করে ক্যানভাসের মিথস্ক্রিয়া পরীক্ষা করতে পারেন।

আপনি BulletPointSpanTest- এ আরও স্প্যান পরীক্ষার নমুনা খুঁজে পেতে পারেন।

স্প্যান ব্যবহার করার জন্য সর্বোত্তম অনুশীলন

আপনার প্রয়োজনের উপর নির্ভর করে TextView এ পাঠ্য সেট করার জন্য বেশ কিছু মেমরি-দক্ষ উপায় রয়েছে।

অন্তর্নিহিত পাঠ্য পরিবর্তন না করে একটি স্প্যান সংযুক্ত করুন বা বিচ্ছিন্ন করুন৷

TextView.setText() একাধিক ওভারলোড রয়েছে যা স্প্যানগুলিকে ভিন্নভাবে পরিচালনা করে। উদাহরণস্বরূপ, আপনি নিম্নলিখিত কোড সহ একটি Spannable পাঠ্য বস্তু সেট করতে পারেন:

textView.setText(spannableObject)
textView.setText(spannableObject);

setText() এর এই ওভারলোডটিকে কল করার সময়, TextView আপনার Spannable এর একটি SpannedString হিসাবে একটি অনুলিপি তৈরি করে এবং এটিকে একটি CharSequence হিসাবে মেমরিতে রাখে। এর মানে হল যে আপনার পাঠ্য এবং স্প্যানগুলি অপরিবর্তনীয়, তাই যখন আপনাকে পাঠ্য বা স্প্যানগুলি আপডেট করতে হবে, একটি নতুন 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
    }
}
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);

একবার Spannable.Factory অবজেক্ট সেট করুন, আপনি আপনার TextView এর রেফারেন্স পাওয়ার পরেই। আপনি যদি RecyclerView ব্যবহার করেন, আপনি যখন প্রথম আপনার দৃষ্টিভঙ্গি স্ফীত করবেন তখন Factory অবজেক্ট সেট করুন। যখন আপনার RecyclerView আপনার ViewHolder একটি নতুন আইটেম আবদ্ধ করে তখন এটি অতিরিক্ত অবজেক্ট তৈরিকে এড়িয়ে যায়।

অভ্যন্তরীণ স্প্যান বৈশিষ্ট্য পরিবর্তন করুন

আপনি যদি একটি পরিবর্তনযোগ্য স্প্যানের শুধুমাত্র একটি অভ্যন্তরীণ বৈশিষ্ট্য পরিবর্তন করতে চান, যেমন একটি কাস্টম বুলেট স্প্যানে বুলেটের রঙ, আপনি স্প্যানটি তৈরি হওয়ার সাথে সাথে একটি রেফারেন্স রেখে setText() একাধিকবার কল করা থেকে ওভারহেড এড়াতে পারেন। আপনি যখন স্প্যানটি পরিবর্তন করতে চান, তখন আপনি রেফারেন্সটি পরিবর্তন করতে পারেন এবং তারপরে আপনার পরিবর্তিত বৈশিষ্ট্যের ধরণের উপর নির্ভর করে TextViewinvalidate() বা 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();
            }
        });
    }
}

অ্যান্ড্রয়েড কেটিএক্স এক্সটেনশন ফাংশন ব্যবহার করুন

অ্যান্ড্রয়েড কেটিএক্সে এক্সটেনশন ফাংশনও রয়েছে যা স্প্যানগুলির সাথে কাজ করা সহজ করে তোলে। আরও জানতে, androidx.core.text প্যাকেজের ডকুমেন্টেশন দেখুন।