জেটপ্যাক রচনা পর্যায়গুলি

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

কম্পোজ ডকুমেন্টেশন থিংকিং ইন কম্পোজ এন্ড স্টেট এবং জেটপ্যাক কম্পোজে কম্পোজিশন বর্ণনা করে।

একটি ফ্রেমের তিনটি পর্যায়

রচনার তিনটি প্রধান পর্যায় রয়েছে:

  1. রচনা : কি UI দেখাতে হবে। রচনা কম্পোজযোগ্য ফাংশন চালায় এবং আপনার UI এর একটি বিবরণ তৈরি করে।
  2. লেআউট : UI কোথায় রাখবেন। এই পর্বটি দুটি ধাপ নিয়ে গঠিত: পরিমাপ এবং বসানো। লেআউট উপাদানগুলি পরিমাপ করে এবং লেআউট ট্রিতে প্রতিটি নোডের জন্য 2D স্থানাঙ্কে নিজেদের এবং যেকোনো শিশু উপাদানকে রাখে।
  3. অঙ্কন : এটি কিভাবে রেন্ডার করে। UI উপাদানগুলি একটি ক্যানভাসে আঁকা হয়, সাধারণত একটি ডিভাইসের পর্দা।
যে তিনটি ধাপে কম্পোজ ডেটাকে UI-তে রূপান্তরিত করে (ক্রম, ডেটা, কম্পোজিশন, লেআউট, অঙ্কন, UI)।
চিত্র 1. যে তিনটি ধাপে কম্পোজ ডেটাকে UI-তে রূপান্তরিত করে।

এই পর্যায়গুলির ক্রম সাধারণত একই হয়, একটি ফ্রেম তৈরি করতে কম্পোজিশন থেকে লেআউট পর্যন্ত ড্রয়িং পর্যন্ত ডেটা এক দিকে প্রবাহিত হতে দেয় (এছাড়াও একমুখী ডেটা প্রবাহ নামে পরিচিত)। BoxWithConstraints , LazyColumn , এবং LazyRow উল্লেখযোগ্য ব্যতিক্রম, যেখানে এর সন্তানদের গঠন পিতামাতার লেআউট পর্যায়ের উপর নির্ভর করে।

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

পর্যায়গুলি বুঝুন

এই বিভাগটি বর্ণনা করে যে কীভাবে কম্পোজেবলের জন্য তিনটি রচনা পর্যায় আরো বিস্তারিতভাবে সম্পাদিত হয়।

রচনা

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

চিত্র 2. আপনার UI প্রতিনিধিত্বকারী ট্রি যা রচনা পর্বে তৈরি করা হয়েছে।

কোড এবং UI গাছের একটি উপবিভাগ নিম্নলিখিত মত দেখায়:

পাঁচটি কম্পোজেবল এবং ফলস্বরূপ UI ট্রি সহ একটি কোড স্নিপেট, যার মধ্যে চাইল্ড নোডগুলি তাদের প্যারেন্ট নোড থেকে শাখা হয়৷
চিত্র 3. সংশ্লিষ্ট কোড সহ একটি UI গাছের একটি উপবিভাগ।

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

লেআউট

লেআউট পর্বে, কম্পোজ ইনপুট হিসাবে রচনা পর্যায়ে উত্পাদিত UI ট্রি ব্যবহার করে। লেআউট নোডের সংগ্রহে 2D স্পেসে প্রতিটি নোডের আকার এবং অবস্থান নির্ধারণের জন্য প্রয়োজনীয় সমস্ত তথ্য রয়েছে।

চিত্র 4. লেআউট পর্বের সময় UI ট্রিতে প্রতিটি লেআউট নোডের পরিমাপ এবং স্থাপন।

লেআউট পর্বের সময়, নিম্নলিখিত তিনটি ধাপের অ্যালগরিদম ব্যবহার করে গাছটি অতিক্রম করা হয়:

  1. শিশুদের পরিমাপ করুন : একটি নোড তার শিশুদের পরিমাপ করে যদি থাকে।
  2. নিজের আকার নির্ধারণ করুন : এই পরিমাপের উপর ভিত্তি করে, একটি নোড তার নিজস্ব আকার নির্ধারণ করে।
  3. শিশুদের রাখুন : প্রতিটি চাইল্ড নোড একটি নোডের নিজস্ব অবস্থানের সাপেক্ষে স্থাপন করা হয়।

এই পর্যায়ের শেষে, প্রতিটি লেআউট নোড আছে:

  • একটি নির্ধারিত প্রস্থ এবং উচ্চতা
  • একটি x, y স্থানাঙ্ক যেখানে এটি আঁকা উচিত

পূর্ববর্তী বিভাগ থেকে UI ট্রি স্মরণ করুন:

পাঁচটি কম্পোজেবল এবং ফলস্বরূপ UI ট্রি সহ একটি কোড স্নিপেট, চাইল্ড নোডগুলি তাদের প্যারেন্ট নোড থেকে শাখাযুক্ত

এই গাছের জন্য, অ্যালগরিদম নিম্নরূপ কাজ করে:

  1. Row তার সন্তান, Image এবং Column পরিমাপ করে।
  2. Image পরিমাপ করা হয়। এটির কোনো সন্তান নেই, তাই এটি নিজের আকার নির্ধারণ করে এবং Row আকারটি রিপোর্ট করে।
  3. Column পরবর্তী পরিমাপ করা হয়. এটি প্রথমে তার নিজের বাচ্চাদের পরিমাপ করে (দুটি Text কম্পোজেবল)।
  4. প্রথম Text পরিমাপ করা হয়. এটির কোনো সন্তান নেই তাই এটি নিজের আকার নির্ধারণ করে এবং Column তার আকারের প্রতিবেদন করে।
    1. দ্বিতীয় Text পরিমাপ করা হয়. এটির কোন সন্তান নেই তাই এটি নিজের আকার নির্ধারণ করে এবং Column এটিকে রিপোর্ট করে৷
  5. Column তার নিজের আকার নির্ধারণ করতে চাইল্ড পরিমাপ ব্যবহার করে। এটি সর্বাধিক চাইল্ড প্রস্থ এবং এর বাচ্চাদের উচ্চতার সমষ্টি ব্যবহার করে।
  6. Column তার সন্তানদেরকে নিজের সাপেক্ষে রাখে, তাদের একে অপরের নীচে উল্লম্বভাবে রাখে।
  7. Row তার নিজের আকার নির্ধারণ করতে চাইল্ড পরিমাপ ব্যবহার করে। এটি সর্বোচ্চ শিশু উচ্চতা এবং এর শিশুদের প্রস্থের সমষ্টি ব্যবহার করে। এটি তারপর তার সন্তানদের রাখে।

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

অঙ্কন

অঙ্কন পর্বে, গাছটি আবার উপরে থেকে নিচ পর্যন্ত অতিক্রম করা হয় এবং প্রতিটি নোড পালাক্রমে পর্দায় নিজেকে আঁকতে থাকে।

চিত্র 5. অঙ্কন পর্ব পর্দায় পিক্সেল আঁকে।

পূর্ববর্তী উদাহরণ ব্যবহার করে, গাছের বিষয়বস্তু নিম্নলিখিত উপায়ে আঁকা হয়েছে:

  1. Row এটিতে থাকতে পারে এমন যেকোনো বিষয়বস্তু আঁকে, যেমন একটি পটভূমির রঙ।
  2. Image নিজেই আঁকে।
  3. Column নিজেই আঁকা.
  4. প্রথম এবং দ্বিতীয় Text যথাক্রমে নিজেদের আঁকা।

চিত্র 6. একটি UI গাছ এবং এর আঁকা উপস্থাপনা।

রাজ্য পড়ে

আপনি যখন পূর্বে তালিকাভুক্ত পর্যায়গুলির মধ্যে একটির সময় একটি snapshot state value পড়েন, তখন কম্পোজ স্বয়ংক্রিয়ভাবে ট্র্যাক করে যে এটি value পড়ার সময় কী করছিল৷ এই ট্র্যাকিং কম্পোজকে রিডারকে রি-এক্সিকিউট করার অনুমতি দেয় যখন স্টেটের value পরিবর্তিত হয়, এবং এটি রচনায় রাষ্ট্রীয় পর্যবেক্ষণের ভিত্তি।

আপনি সাধারণত mutableStateOf() ব্যবহার করে রাষ্ট্র তৈরি করেন এবং তারপরে দুটি উপায়ের মধ্যে একটির মাধ্যমে এটি অ্যাক্সেস করেন: সরাসরি value সম্পত্তি অ্যাক্সেস করে, অথবা বিকল্পভাবে একটি Kotlin সম্পত্তি প্রতিনিধি ব্যবহার করে। আপনি কম্পোজেবল রাজ্যে তাদের সম্পর্কে আরও পড়তে পারেন। এই গাইডের উদ্দেশ্যে, একটি "স্টেট রিড" সেই সমতুল্য অ্যাক্সেস পদ্ধতিগুলির যে কোনো একটিকে বোঝায়।

// State read without property delegate.
val paddingState: MutableState<Dp> = remember { mutableStateOf(8.dp) }
Text(
    text = "Hello",
    modifier = Modifier.padding(paddingState.value)
)

// State read with property delegate.
var padding: Dp by remember { mutableStateOf(8.dp) }
Text(
    text = "Hello",
    modifier = Modifier.padding(padding)
)

সম্পত্তি প্রতিনিধির হুডের অধীনে, "গেটার" এবং "সেটার" ফাংশনগুলি রাজ্যের value অ্যাক্সেস এবং আপডেট করতে ব্যবহৃত হয়। এই গেটার এবং সেটার ফাংশনগুলি শুধুমাত্র তখনই চালু করা হয় যখন আপনি সম্পত্তিটিকে একটি মান হিসাবে উল্লেখ করেন, এবং এটি তৈরি করার সময় নয়, এই কারণেই পূর্বে বর্ণিত দুটি উপায় সমতুল্য।

কোডের প্রতিটি ব্লক যা রি-এক্সিকিউট করা যেতে পারে যখন একটি রিড স্টেট পরিবর্তন হয় একটি রিস্টার্ট স্কোপ । কম্পোজ রাষ্ট্রীয় value পরিবর্তনের ট্র্যাক রাখে এবং বিভিন্ন ধাপে সুযোগগুলি পুনরায় চালু করে।

পর্যায়ক্রমে রাষ্ট্র পড়ে

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

নিম্নলিখিত বিভাগগুলি প্রতিটি পর্যায় বর্ণনা করে এবং বর্ণনা করে যে যখন একটি রাষ্ট্রীয় মান এটির মধ্যে পড়া হয় তখন কী ঘটে।

পর্যায় 1: রচনা

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

রচনার ফলাফলের উপর নির্ভর করে, রচনা UI লেআউট এবং অঙ্কন পর্যায়গুলি চালায়। বিষয়বস্তু একই থাকে এবং আকার এবং বিন্যাস পরিবর্তন না হলে এটি এই পর্যায়গুলি এড়িয়ে যেতে পারে।

var padding by remember { mutableStateOf(8.dp) }
Text(
    text = "Hello",
    // The `padding` state is read in the composition phase
    // when the modifier is constructed.
    // Changes in `padding` will invoke recomposition.
    modifier = Modifier.padding(padding)
)

পর্যায় 2: লেআউট

লেআউট ফেজ দুটি ধাপ নিয়ে গঠিত: পরিমাপ এবং বসানো । পরিমাপের ধাপটি Layout কম্পোজেবল, LayoutModifier ইন্টারফেসের MeasureScope.measure পদ্ধতি, অন্যদের মধ্যে পাস করা মেপে ল্যাম্বডা চালায়। প্লেসমেন্ট ধাপটি layout ফাংশনের প্লেসমেন্ট ব্লক, Modifier.offset { … } , এবং অনুরূপ ফাংশন চালায়।

এই প্রতিটি ধাপে স্টেট রিড লেআউট এবং সম্ভাব্য অঙ্কন পর্বকে প্রভাবিত করে। যখন রাষ্ট্রের value পরিবর্তিত হয়, রচনা UI লেআউট পর্বের সময়সূচী নির্ধারণ করে। আকার বা অবস্থান পরিবর্তিত হলে এটি অঙ্কন পর্বও চালায়।

var offsetX by remember { mutableStateOf(8.dp) }
Text(
    text = "Hello",
    modifier = Modifier.offset {
        // The `offsetX` state is read in the placement step
        // of the layout phase when the offset is calculated.
        // Changes in `offsetX` restart the layout.
        IntOffset(offsetX.roundToPx(), 0)
    }
)

পর্যায় 3: অঙ্কন

অঙ্কন কোডের সময় রাজ্য পড়া অঙ্কন পর্বকে প্রভাবিত করে। সাধারণ উদাহরণের মধ্যে রয়েছে Canvas() , Modifier.drawBehind , এবং Modifier.drawWithContent । যখন রাষ্ট্রের value পরিবর্তিত হয়, তখন রচনা UI শুধুমাত্র ড্র পর্ব চালায়।

var color by remember { mutableStateOf(Color.Red) }
Canvas(modifier = modifier) {
    // The `color` state is read in the drawing phase
    // when the canvas is rendered.
    // Changes in `color` restart the drawing.
    drawRect(color)
}

চিত্রটি দেখায় যে ড্র পর্বের সময় পড়া একটি রাষ্ট্র শুধুমাত্র ড্র পর্বটিকে আবার চালানোর জন্য ট্রিগার করে।

অপ্টিমাইজ স্টেট রিড

যেহেতু কম্পোজ স্থানীয়ভাবে স্টেট রিড ট্র্যাকিং সঞ্চালন করে, তাই আপনি একটি উপযুক্ত পর্যায়ে প্রতিটি স্টেট পড়ার মাধ্যমে সম্পাদিত কাজের পরিমাণ কমিয়ে আনতে পারেন।

নিম্নলিখিত উদাহরণ বিবেচনা করুন. এই উদাহরণে একটি Image() রয়েছে যা অফসেট মডিফায়ার ব্যবহার করে তার চূড়ান্ত লেআউট অবস্থান অফসেট করে, যার ফলে ব্যবহারকারী স্ক্রোল করার সাথে সাথে একটি প্যারালাক্স প্রভাব তৈরি করে।

Box {
    val listState = rememberLazyListState()

    Image(
        // ...
        // Non-optimal implementation!
        Modifier.offset(
            with(LocalDensity.current) {
                // State read of firstVisibleItemScrollOffset in composition
                (listState.firstVisibleItemScrollOffset / 2).toDp()
            }
        )
    )

    LazyColumn(state = listState) {
        // ...
    }
}

এই কোড কাজ করে, কিন্তু সাবঅপ্টিমাল কর্মক্ষমতা ফলাফল. লেখার মতো, কোডটি firstVisibleItemScrollOffset অবস্থার value পড়ে এবং এটি Modifier.offset(offset: Dp) ফাংশনে পাস করে। ব্যবহারকারী স্ক্রোল করার সাথে সাথে, firstVisibleItemScrollOffset এর value পরিবর্তন হবে। আপনি যেমন শিখেছেন, কম্পোজ যেকোনো স্টেট রিড ট্র্যাক করে যাতে এটি রিডিং কোড রিস্টার্ট (পুনরায় আমন্ত্রণ) করতে পারে, যা এই উদাহরণে Box বিষয়বস্তু।

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

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

ল্যাম্বডা দিয়ে অফসেট

অফসেট মডিফায়ারের আরেকটি সংস্করণ উপলব্ধ রয়েছে: Modifier.offset(offset: Density.() -> IntOffset)

এই সংস্করণটি একটি ল্যাম্বডা প্যারামিটার নেয়, যেখানে ফলস্বরূপ অফসেট ল্যাম্বডা ব্লক দ্বারা ফেরত দেওয়া হয়। এটি ব্যবহার করতে কোড আপডেট করুন:

Box {
    val listState = rememberLazyListState()

    Image(
        // ...
        Modifier.offset {
            // State read of firstVisibleItemScrollOffset in Layout
            IntOffset(x = 0, y = listState.firstVisibleItemScrollOffset / 2)
        }
    )

    LazyColumn(state = listState) {
        // ...
    }
}

তাহলে কেন এই বেশি পারফরম্যান্স? আপনি মডিফায়ারকে যে ল্যাম্বডা ব্লক প্রদান করেন সেটি লেআউট পর্বের সময় (বিশেষত, লেআউট ফেজের প্লেসমেন্ট ধাপের সময়) আমন্ত্রণ জানানো হয়, যার অর্থ কম্পোজিশনের সময় firstVisibleItemScrollOffset অবস্থা আর পড়া হয় না। যেহেতু কম্পোজ ট্র্যাক যখন স্টেট পড়া হয়, এই পরিবর্তনের মানে হল যদি firstVisibleItemScrollOffset এর value পরিবর্তন হয়, তবে রচনাকে শুধুমাত্র লেআউট এবং অঙ্কন পর্যায়গুলি পুনরায় চালু করতে হবে।

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

পুনর্গঠন লুপ (চক্রীয় পর্যায় নির্ভরতা)

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

Box {
    var imageHeightPx by remember { mutableStateOf(0) }

    Image(
        painter = painterResource(R.drawable.rectangle),
        contentDescription = "I'm above the text",
        modifier = Modifier
            .fillMaxWidth()
            .onSizeChanged { size ->
                // Don't do this
                imageHeightPx = size.height
            }
    )

    Text(
        text = "I'm below the image",
        modifier = Modifier.padding(
            top = with(LocalDensity.current) { imageHeightPx.toDp() }
        )
    )
}

এই উদাহরণটি একটি উল্লম্ব কলাম প্রয়োগ করে, যার উপরে চিত্রটি রয়েছে এবং তারপরে এটির নীচে পাঠ্য। এটি চিত্রটির সমাধানকৃত আকার পেতে Modifier.onSizeChanged() ব্যবহার করে এবং তারপরে এটিকে নামানোর জন্য টেক্সটে Modifier.padding() ব্যবহার করে। Px থেকে Dp এ ফিরে আসা অস্বাভাবিক রূপান্তর ইতিমধ্যেই নির্দেশ করে যে কোডটিতে কিছু সমস্যা আছে।

এই উদাহরণের সমস্যা হল যে কোডটি একটি ফ্রেমের মধ্যে "চূড়ান্ত" লেআউটে পৌঁছায় না। কোডটি ঘটতে থাকা একাধিক ফ্রেমের উপর নির্ভর করে, যা অপ্রয়োজনীয় কাজ করে এবং এর ফলে ব্যবহারকারীর জন্য UI স্ক্রিনে ঘুরে বেড়ায়।

প্রথম ফ্রেম রচনা

প্রথম ফ্রেমের রচনা পর্যায়ে, imageHeightPx প্রাথমিকভাবে 0 হয়। ফলস্বরূপ, কোডটি Modifier.padding(top = 0) সহ পাঠ্য সরবরাহ করে। পরবর্তী লেআউট পর্বটি onSizeChanged modifier-এর কলব্যাককে আহ্বান করে, যা imageHeightPx চিত্রের প্রকৃত উচ্চতায় আপডেট করে। রচনা করুন তারপর পরবর্তী ফ্রেমের জন্য একটি পুনর্গঠনের সময়সূচী করুন৷ যাইহোক, বর্তমান অঙ্কন পর্বে, পাঠ্যটি 0 এর প্যাডিং সহ রেন্ডার হয়, কারণ আপডেট করা imageHeightPx মান এখনও প্রতিফলিত হয়নি।

দ্বিতীয় ফ্রেম রচনা

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

ডায়াগ্রাম একটি পুনর্গঠন লুপ দেখাচ্ছে যেখানে বিন্যাস পর্যায়ে একটি আকার পরিবর্তন একটি পুনর্গঠনকে ট্রিগার করে, যার ফলে লেআউটটি আবার ঘটতে পারে।

এই উদাহরণটি কল্পিত মনে হতে পারে, তবে এই সাধারণ প্যাটার্নটি সম্পর্কে সতর্ক থাকুন:

  • Modifier.onSizeChanged() , onGloballyPositioned() , বা অন্য কিছু লেআউট অপারেশন
  • কিছু রাষ্ট্র আপডেট
  • লেআউট মডিফায়ারে ইনপুট হিসাবে সেই অবস্থাটি ব্যবহার করুন ( padding() , height() , বা অনুরূপ)
  • সম্ভাব্য পুনরাবৃত্তি

পূর্ববর্তী নমুনার জন্য সমাধান হল সঠিক বিন্যাস আদিম ব্যবহার করা। পূর্ববর্তী উদাহরণটি একটি Column() দিয়ে প্রয়োগ করা যেতে পারে, তবে আপনার কাছে আরও জটিল উদাহরণ থাকতে পারে যার জন্য কাস্টম কিছু প্রয়োজন, যার জন্য একটি কাস্টম লেআউট লেখার প্রয়োজন হবে। আরও তথ্যের জন্য কাস্টম লেআউট গাইড দেখুন

এখানে সাধারণ নীতি হল একাধিক UI উপাদানগুলির জন্য সত্যের একটি একক উত্স থাকা যা একে অপরের সাথে পরিমাপ করা এবং স্থাপন করা উচিত। একটি সঠিক বিন্যাস আদিম ব্যবহার করা বা একটি কাস্টম বিন্যাস তৈরি করার অর্থ হল ন্যূনতম ভাগ করা অভিভাবক সত্যের উত্স হিসাবে কাজ করে যা একাধিক উপাদানের মধ্যে সম্পর্ককে সমন্বয় করতে পারে। একটি গতিশীল রাষ্ট্র প্রবর্তন এই নীতি ভঙ্গ করে.

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}