<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: goodlords</title>
    <description>The latest articles on DEV Community by goodlords (@zealot2002).</description>
    <link>https://dev.to/zealot2002</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3939247%2F9f37a317-a504-4090-9ddd-7305f6de5be2.jpeg</url>
      <title>DEV Community: goodlords</title>
      <link>https://dev.to/zealot2002</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zealot2002"/>
    <language>en</language>
    <item>
      <title>I built a pure-frontend, all-in-one toolbox for the tasks I reach for every day</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Wed, 10 Jun 2026 09:02:26 +0000</pubDate>
      <link>https://dev.to/zealot2002/appforge-app-dev-workstation-for-mobile-developers-82h</link>
      <guid>https://dev.to/zealot2002/appforge-app-dev-workstation-for-mobile-developers-82h</guid>
      <description>&lt;p&gt;After years of mobile development, one of the most annoying parts of my daily workflow is jumping between scattered tool websites.&lt;/p&gt;

&lt;p&gt;Finding image assets means digging through folders layer by layer — SVG and Lottie need separate preview tools. Converting or compressing images means uploading to online converters. Debugging APIs means opening a JSON formatter. Inspecting an APK means yet another dedicated site. By the end of the day I have a dozen tabs open, constantly context-switching. Worse, many online tools require file uploads — internal project assets and unreleased builds always feel risky.&lt;/p&gt;

&lt;p&gt;When things slowed down recently, I built a pure-frontend, all-in-one toolbox for the tasks I reach for every day. I call it &lt;strong&gt;AppForge&lt;/strong&gt;. Core features run locally in the browser — files never leave your machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kba2td6dynp34mcvprc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kba2td6dynp34mcvprc.png" alt="AppForge homepage — AI picks + dev tools" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Resource Preview: find one icon in 2,870 files
&lt;/h2&gt;

&lt;p&gt;This was the first module I built — and the one I use most — because it hits a daily pain point for our &lt;strong&gt;40-person app team&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One project scan surfaces &lt;strong&gt;2,870&lt;/strong&gt; resource files. Search &lt;code&gt;close&lt;/code&gt; and you get &lt;strong&gt;80+&lt;/strong&gt; near-identical close icons: inconsistent names, scattered paths, zero discipline. Can I push the whole team to clean this up overnight? Honestly, no.&lt;/p&gt;

&lt;p&gt;But one missing asset blocks your whole flow. My take is simple: &lt;strong&gt;if I can't fix the mess, I can at least find what I need in seconds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Select a local project folder — AppForge scans everything and recognizes SVG, WebP, PNG, GIF, Lottie, Vector, Iconfont, and more. The screenshot shows it in action: search &lt;code&gt;close&lt;/code&gt;, filter Vector, 81 matches with instant preview and full paths. No Finder spelunking, no guessing the rest of the filename.&lt;/p&gt;

&lt;p&gt;Results cache locally — reopen and you're ready. Onboarding legacy projects, auditing duplicate assets, or chasing "that little X close icon" — what used to take minutes now takes seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1eh6vnn4rnizeztjfqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1eh6vnn4rnizeztjfqq.png" alt="Resource preview — search close among 2,870 assets" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  File Conversion: image processing in one place
&lt;/h2&gt;

&lt;p&gt;After finding assets comes format work: SVG → PNG for multi-platform, PNG → WebP for smaller bundles, HEIC → common formats, occasional background removal for marketing assets.&lt;/p&gt;

&lt;p&gt;Instead of design software or multiple upload sites, the convert module handles format conversion, smart compression, and background removal — all locally. Drop files in, download results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fti4y41pir6fawkp9m5t8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fti4y41pir6fawkp9m5t8.png" alt="File conversion — formats, HEIC, compression" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  APK Inspector: unpack locally
&lt;/h2&gt;

&lt;p&gt;Android devs regularly need to inspect APKs: competitor package names and versions, signatures and permissions, icons and resources.&lt;/p&gt;

&lt;p&gt;Drag an APK into AppForge to view package info, Manifest, permissions, components, and export internal assets. Need decompilation? One click to JADX.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds71pnaqfag6p7yypux6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds71pnaqfag6p7yypux6.png" alt="APK inspector — package info, permissions, components" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Image OCR: copy text from screenshots
&lt;/h2&gt;

&lt;p&gt;Stack traces, design copy, code snippets in docs — often trapped in screenshots. The OCR module runs locally, supports Chinese and English, batch processing, one-click copy. Files stay on your machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq4s000s179hrmch9jr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq4s000s179hrmch9jr8.png" alt="Image OCR — Chinese &amp;amp; English" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Mini Tools: no more bookmark clutter
&lt;/h2&gt;

&lt;p&gt;JSON formatting, Base64 / URL / Unicode encode-decode, regex testing, timestamp conversion — small but essential. Built-in presets for email, phone, ID, IP, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfakh9zla4stoi1y9k9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfakh9zla4stoi1y9k9z.png" alt="Mini tools — JSON, regex, Base64, and more" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  AI-Curated Tech Articles: skip the noise
&lt;/h2&gt;

&lt;p&gt;Another big pain point. As a mobile developer I skim tons of tech content daily — most of it is fluff, reposts, or clickbait.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;AI-curated articles&lt;/strong&gt; section pulls candidates from DEV and Hacker News, scores each post with an LLM, and keeps only high-quality picks. &lt;strong&gt;Updated daily with cumulative history&lt;/strong&gt; — past picks aren't wiped each run. Browse by category in Chinese or English — like having someone pre-filter for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauu49rgxkvk965lrbr0z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauu49rgxkvk965lrbr0z.png" alt="AI-curated articles — categories, scores, and reasons" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Open APIs: quick reference for demos
&lt;/h2&gt;

&lt;p&gt;Building a small demo often means hunting for free APIs, testing endpoints, bookmarking docs. I curated common APIs by category with sample calls — look up when you need them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwv3vpuo7gwszu1of2ik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwv3vpuo7gwszu1of2ik.png" alt="Open APIs — categorized quick reference" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I built it this way
&lt;/h2&gt;

&lt;p&gt;Simple goal: &lt;strong&gt;make my own workflow smoother&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local-first&lt;/strong&gt;: sensitive project assets and builds stay in the browser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero friction&lt;/strong&gt;: no signup, no desktop install — just open and use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real scenarios&lt;/strong&gt;: every feature comes from actual daily pain points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built with &lt;strong&gt;React 19 + Vite 8 + Tailwind CSS 4&lt;/strong&gt;, deployed on Cloudflare Pages, with lazy loading, caching, and bilingual UI.&lt;/p&gt;

&lt;p&gt;Started as a personal toolbox — after using it for a while I polished it for others. If you're a mobile developer tired of scattered tools, give it a try.&lt;/p&gt;

&lt;p&gt;What's missing from your dev workstation? Share the tools and workflow tricks you can't live without in the comments — let's swap notes and level up together.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;👉 Try it now: &lt;a href="https://appforge-7tw.pages.dev" rel="noopener noreferrer"&gt;https://appforge-7tw.pages.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AppForge&lt;/strong&gt; — AI-curated reads and dev tools at your fingertips, all-in-one.&lt;/p&gt;

</description>
      <category>android</category>
      <category>ios</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Modern Android Architecture (Part 4): Design Patterns — The Glue of Lego Architecture</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Mon, 01 Jun 2026 02:06:48 +0000</pubDate>
      <link>https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f</link>
      <guid>https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series Navigation&lt;/strong&gt;: &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f"&gt;Article 1: A Decade of Android Architecture Evolution&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7"&gt;Article 2: The Lego Architecture: Divide and Conquer, Taken to the Extreme&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4"&gt;Article 3: Refactoring a Product Detail Page with Lego Architecture&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Repository&lt;/strong&gt;: &lt;a href="https://github.com/zealot2002/androidArch" rel="noopener noreferrer"&gt;https://github.com/zealot2002/androidArch&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Foreword: Bricks Are Ready, How to Assemble Them Stably?
&lt;/h2&gt;

&lt;p&gt;In the first three articles, we followed a clear path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Article 1&lt;/strong&gt; pointed out: Architecture is just "technique" — it can manage layering, but not splitting granularity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Article 2&lt;/strong&gt; proposed Lego Architecture: Split infinitely to minimum particles, making reuse visible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Article 3&lt;/strong&gt; proved with practical product detail page: Bricks like Mapper, Assembler, ListItem can indeed split a 3000-line disaster into 15 independent components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there's a question hinted at the end of Article 3 — &lt;strong&gt;Splitting is only the first step; assembly determines whether this system can run long-term.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two pages both require "login before operation" — do you plan to copy-paste two sets of &lt;code&gt;if (isLogin)&lt;/code&gt; checks? Three types of posters (product, social, store) share the same "render → screenshot → preview → share" workflow, but with completely different UI layouts — do you plan to write three &lt;code&gt;when&lt;/code&gt; branches in Activity, each hundreds of lines long?&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;design patterns&lt;/strong&gt; come in. They are not another "silver bullet architecture," but the &lt;strong&gt;glue&lt;/strong&gt; between Lego bricks — using minimal, proven connection methods to stably assemble already-split particles together.&lt;/p&gt;

&lt;p&gt;The 23 GoF patterns and more evolving patterns each solve different "assembly" problems: Factory is responsible for &lt;strong&gt;creating&lt;/strong&gt; the right bricks, Strategy for &lt;strong&gt;switching&lt;/strong&gt; replaceable behaviors, Adapter for &lt;strong&gt;connecting&lt;/strong&gt; incompatible interfaces, Observer for &lt;strong&gt;responding&lt;/strong&gt; to state changes, Template Method for &lt;strong&gt;solidifying&lt;/strong&gt; invariant processes... Due to space constraints, this article won't cover all of them, but will select two representative cases from the demo project — &lt;strong&gt;Observer&lt;/strong&gt; and &lt;strong&gt;Template Method&lt;/strong&gt; — to illustrate how design patterns generally work in Lego Architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rp863k7hyghawg1jnx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rp863k7hyghawg1jnx2.png" alt="Demo project screenshot" width="799" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Left: Product detail page from Article 3 — favorite, add to cart, and buy now gated by &lt;code&gt;LoginRouter&lt;/code&gt;; Right: Three poster share pages (product / social / store) — sharing the &lt;code&gt;BillActivity&lt;/code&gt; screenshot flow, each rendered by a different &lt;code&gt;BaseBillRender&lt;/code&gt; subclass.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  I. Observer Pattern: LoginRouter — The "Broadcast Station" for Login State
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 Pain Point: Login Interception Scattered Everywhere
&lt;/h3&gt;

&lt;p&gt;In e-commerce apps, many operations depend on login state: favorite products, add to cart, buy now, post comments...&lt;/p&gt;

&lt;p&gt;The crudest approach is to repeat this check in every click event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLogin&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LoginActivity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problems are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repetition&lt;/strong&gt;: Ten buttons, ten copies of the same check logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken flow&lt;/strong&gt;: After successful login, the original operation is often "lost" — the user has to click the button again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coupling&lt;/strong&gt;: Some projects even write post-login navigation directly into &lt;code&gt;LoginActivity&lt;/code&gt;, coupling the login module with other modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lego Architecture requires: &lt;strong&gt;Extract "execute after login" as an independent, reusable brick.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 Solution: Observer Pattern
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;LoginRouter&lt;/code&gt; consists of two observable sources (&lt;code&gt;LifecycleOwner&lt;/code&gt;, &lt;code&gt;LoginStateLiveData&lt;/code&gt;) and a &lt;code&gt;pendingBlock&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;LoginStateLiveData&lt;/code&gt;&lt;/strong&gt; — Subscribe to login state. Publish &lt;code&gt;true&lt;/code&gt; after successful login to trigger pending callbacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;LifecycleOwner&lt;/code&gt;&lt;/strong&gt; — Subscribe to page lifecycle. Clear pending when page is destroyed to avoid leaks; also clear on &lt;code&gt;ON_RESUME&lt;/code&gt; — when user presses back from login page without logging in, pending operations should be abandoned.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pendingBlock&lt;/code&gt;&lt;/strong&gt; — Store the "execute after login" operation. Suspended when not logged in, automatically &lt;code&gt;invoke()&lt;/code&gt; after successful login.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Core code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;pendingBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;LifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Observer: Login success → execute pending operation&lt;/span&gt;
            &lt;span class="nc"&gt;LoginStateLiveData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;LifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;pendingBlock&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;pendingBlock&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// ON_RESUME: User returns from login page but not logged in (e.g., pressed back), abandon pending&lt;/span&gt;
            &lt;span class="c1"&gt;// ON_DESTROY: Page destroyed, clean up pending&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;LifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;LifecycleEventObserver&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ON_RESUME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ON_DESTROY&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pendingBlock&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;runBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;LifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LoginStateLiveData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;pendingBlock&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;
                &lt;span class="nc"&gt;AppRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After successful login, the login page only needs to update the global state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// LoginActivity&lt;/span&gt;
&lt;span class="nc"&gt;LoginStateLiveData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This is the complete Observer Pattern loop:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LoginActivity login successful
       │
       ▼
LoginStateLiveData.value = true   ← Subject publishes state
       │
       ▼
LoginRouter receives notification ← Observer
       │
       ▼
pendingBlock?.invoke()            ← Automatically execute suspended operation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.3 Usage in Product Detail Page
&lt;/h3&gt;

&lt;p&gt;In the refactored &lt;code&gt;GoodsDetailActivity&lt;/code&gt; from Article 3, favorite, add to cart, and buy now are all handled with one line through &lt;code&gt;LoginRouter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;loginRouter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LoginRouter&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;LoginRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Favorite&lt;/span&gt;
&lt;span class="n"&gt;loginRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runBlock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Note: this is not a page navigation — it triggers a state update after login&lt;/span&gt;
    &lt;span class="n"&gt;favViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFavorite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSpuId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetFavorite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Add to cart&lt;/span&gt;
&lt;span class="n"&gt;loginRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runBlock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ToastUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goods_action_add_cart_hint&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Buy now → Navigate to confirm order page after login&lt;/span&gt;
&lt;span class="n"&gt;loginRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runBlock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;AppRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openConfirmOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference between &lt;code&gt;LoginRouter&lt;/code&gt; and a route interceptor: interceptors usually only handle unified page navigation, while &lt;code&gt;runBlock&lt;/code&gt; can queue any operation as pending — favorite, API request, show Toast, not limited to opening new pages. Subsequent actions are still declared locally in the page, and &lt;code&gt;LoginActivity&lt;/code&gt; no longer needs to act as a transit hub. Module boundaries are clear and decoupled.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.4 Origin and Boundaries
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;LoginRouter&lt;/code&gt; wasn't designed upfront; it emerged from project pain points.&lt;/p&gt;

&lt;p&gt;After connecting favorite, add to cart, and buy now to the detail page, the same logic repeatedly appeared across multiple buttons: check login, navigate to login page, continue original operation after success. Interceptors could only intercept navigation uniformly, not handle "continue favorite after login"; writing destinations into &lt;code&gt;LoginActivity&lt;/code&gt; would couple the login module with business logic. After several rounds of copy-paste, the pain point became clear — &lt;strong&gt;missing a common brick that can queue any follow-up action as pending.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Extract, observe, abstract: &lt;code&gt;LoginRouter&lt;/code&gt; combines login guard and pending continuation into one brick, using &lt;code&gt;LoginStateLiveData&lt;/code&gt; and &lt;code&gt;LifecycleOwner&lt;/code&gt; to coordinate timing, elegantly solving this pain point.&lt;/p&gt;

&lt;p&gt;Lego Architecture not only requires the ability to split, but also to see patterns in repetition and discover bricks in pain points — &lt;code&gt;LoginRouter&lt;/code&gt; is one such refinement.&lt;/p&gt;




&lt;h2&gt;
  
  
  II. Template Method Pattern: BillActivity — Fixed Process, Variable Content
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Pain Point: Three Poster Types, One Workflow
&lt;/h3&gt;

&lt;p&gt;We added a &lt;strong&gt;poster sharing&lt;/strong&gt; feature to the demo project — users can generate beautiful posters for products, social posts, or store pages, save to album, or share to WeChat.&lt;/p&gt;

&lt;p&gt;The three poster types have completely different UI layouts, but &lt;strong&gt;the page-level workflow is identical&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load data → Select Render → Bind view → Wait for render ready → Screenshot → Preview → Save/Share
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we write three sets of rendering logic in &lt;code&gt;BillActivity&lt;/code&gt; using &lt;code&gt;when (billCase)&lt;/code&gt;, the Activity will quickly bloat; if we write a separate Activity for each poster type, the screenshot, preview, and save code will be duplicated three times.&lt;/p&gt;

&lt;p&gt;Template Method Pattern solution: &lt;strong&gt;Solidify the "invariant process" in a template, leave "variable parts" for subclasses to implement.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Architecture Layers: Interface → Abstract Template → Concrete Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Define Brick Interface
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;BillRender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onBindView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getBillView&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;

    &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Listener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;screenReady&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bgBitmap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bitmap&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;BillRender&lt;/code&gt; is a standard interface — all poster Render bricks must follow these two methods.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Abstract Template Class Solidifies Common Skeleton
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseBillRender&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewBinding&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BillRender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;

    &lt;span class="c1"&gt;// Subclasses only implement this method — fill specific UI&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onRenderView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BillRender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Template method: Reflection automatically inflates corresponding ViewBinding&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;superclass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;javaClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;genericSuperclass&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;ParameterizedType&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bindingClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;superclass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actualTypeArguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;inflate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bindingClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDeclaredMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"inflate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LayoutInflater&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;layoutInflater&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onBindView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BillRender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onRenderView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Call subclass implementation&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getBillView&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This is the core of Template Method Pattern:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BaseBillRender&lt;/code&gt; defines the &lt;strong&gt;algorithm skeleton&lt;/strong&gt; (inflate Binding → call &lt;code&gt;onRenderView&lt;/code&gt; → expose &lt;code&gt;getBillView&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Subclasses only need to implement &lt;strong&gt;one hook:&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;onRenderView&lt;/code&gt;&lt;/strong&gt;, filling in their own UI logic.&lt;/li&gt;
&lt;li&gt;Common ViewBinding initialization is done through generics + reflection, with zero boilerplate code for subclasses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 3: Concrete Subclasses Only Care About Their UI, Need Only Implement One Method
&lt;/h4&gt;

&lt;p&gt;Taking product poster as example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoodsBillRender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nc"&gt;BaseBillRender&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoodsBillData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LayoutBillGoodsBinding&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onRenderView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsBillData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LayoutBillGoodsBinding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BillRender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tvTitle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tvPrice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;
        &lt;span class="c1"&gt;// ... Fill product-specific fields&lt;/span&gt;

        &lt;span class="c1"&gt;// Wait for layout drawing + network image loading to complete&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ivCover&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadNetworkImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onSuccess&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;markReady&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ivQrCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadNetworkImageCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;miniProgramCodeUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onSuccess&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;markReady&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;// Call screenReady when all ready&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;markReady()&lt;/code&gt; internally maintains a counter (product poster needs to wait for layout drawing + cover image + QR code = 3 items), and only triggers &lt;code&gt;screenReady&lt;/code&gt; when the count is complete, ensuring complete content during screenshot.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SocialBillRender&lt;/code&gt; and &lt;code&gt;ShopBillRender&lt;/code&gt; have the same structure, each binding different layouts and Data types. &lt;strong&gt;Adding a new poster type only requires adding a new Render subclass + one Layout XML, zero modifications to existing code.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Factory Selects Concrete Brick
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;BillRenderFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;BillRender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;RouterConstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BILL_CASE_SOCIAL&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;SocialBillRender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nc"&gt;RouterConstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BILL_CASE_SHOP&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ShopBillRender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;GoodsBillRender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3 BillActivity: Orchestrating the Fixed Workflow
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;BillActivity&lt;/code&gt; itself contains no specific poster UI logic; it only &lt;strong&gt;orchestrates the template process&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BillActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ... Initialize views, share button&lt;/span&gt;

        &lt;span class="c1"&gt;// 1. Factory selects Render brick&lt;/span&gt;
        &lt;span class="n"&gt;billRender&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BillRenderFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;billCase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flBillContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;billRender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBillView&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Load data + bind view&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;billData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BillDataLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;billCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;billId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;billRender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onBindView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;billData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;BillRender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Listener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;screenReady&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bgBitmap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bitmap&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;captureBillSnapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// 3. Render ready → screenshot&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;captureBillSnapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 4. View → Bitmap → Preview display&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bitmap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BillBitmapUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewToBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;billRender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBillView&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ivBill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setImageBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bitmap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// 5. Show bottom save/share bar&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The responsibility boundaries are clear throughout the page:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BillDataLoader&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Load Mock data by case&lt;/td&gt;
&lt;td&gt;Simple Factory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BillRenderFactory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select specific Render implementation&lt;/td&gt;
&lt;td&gt;Simple Factory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BaseBillRender&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Solidify inflate + bind skeleton&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Template Method&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;GoodsBillRender&lt;/code&gt;, etc.&lt;/td&gt;
&lt;td&gt;Fill specific UI + async ready detection&lt;/td&gt;
&lt;td&gt;Template Method hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BillActivity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Orchestrate load → render → screenshot → preview → share&lt;/td&gt;
&lt;td&gt;Process controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;BillBitmapUtils&lt;/code&gt; / &lt;code&gt;BillImageSaver&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Screenshot and save&lt;/td&gt;
&lt;td&gt;Independent utility bricks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2.4 Echo with Article 2: When to Use Template Method?
&lt;/h3&gt;

&lt;p&gt;In Article 2, we harshly criticized this kind of Base:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;initCallerData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// Forced order&lt;/span&gt;
        &lt;span class="nf"&gt;initView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;initPageData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;initObservers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initPageData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is the template method in &lt;code&gt;BaseBillRender&lt;/code&gt; acceptable, but not in &lt;code&gt;BaseActivity&lt;/code&gt;?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;br&gt;&lt;/th&gt;
&lt;th&gt;Bad BaseActivity Template&lt;/th&gt;
&lt;th&gt;Good BaseBillRender Template&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Is the process really consistent?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Different pages have very different initialization orders&lt;/td&gt;
&lt;td&gt;All posters must inflate → bind → render → ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Constrains order or structure?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Forces &lt;code&gt;initView&lt;/code&gt; before &lt;code&gt;initData&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Only specifies "call &lt;code&gt;onRenderView&lt;/code&gt; when binding data"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subclass freedom&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Kidnapped by four abstract methods&lt;/td&gt;
&lt;td&gt;Only need to implement one &lt;code&gt;onRenderView&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Is it pluggable?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Must inherit Base to use&lt;/td&gt;
&lt;td&gt;Just implement &lt;code&gt;BillRender&lt;/code&gt; interface, no inheritance required&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The judgment is simple: Only use template method when the algorithm skeleton is truly consistent across multiple subclasses; if you're just "incidentally" stuffing a bunch of optional initialization steps into Base, it's a shackle, not a template.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  III. Gluing Approaches from Two Cases
&lt;/h2&gt;

&lt;p&gt;The two cases above demonstrate two common "gluing" directions of design patterns in Lego Architecture — &lt;strong&gt;responding to changes&lt;/strong&gt; and &lt;strong&gt;solidifying processes&lt;/strong&gt;. Other patterns solve different dimensions of assembly problems like creation, replacement, adaptation, etc., with similar thinking.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Observer (LoginRouter)&lt;/th&gt;
&lt;th&gt;Template Method (BillRender)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Problem Solved&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When A's state changes, B needs to respond automatically&lt;/td&gt;
&lt;td&gt;Multiple subclasses share the same algorithm skeleton, only some steps differ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Connection Method&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Subscription / Callback&lt;/td&gt;
&lt;td&gt;Inherit abstract class + implement hook methods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Coupling Direction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Subject doesn't know who's observing (unidirectional)&lt;/td&gt;
&lt;td&gt;Subclass depends on parent skeleton (unidirectional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lego Position&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cross-module event broadcasting brick&lt;/td&gt;
&lt;td&gt;Common skeleton brick for similar Renders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Extension Method&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add new observers without modifying Subject&lt;/td&gt;
&lt;td&gt;Add new subclasses without modifying template skeleton&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Regardless of pattern, there's a common prerequisite: &lt;strong&gt;They are used to "glue" bricks after Lego splitting — not to replace splitting itself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you haven't split login logic into &lt;code&gt;LoginRouter&lt;/code&gt;, Observer Pattern won't save you — you're just writing LiveData observations in three Activities. If you haven't split the three posters into independent Renders, Template Method won't save you either — &lt;code&gt;BaseBillRender&lt;/code&gt; will be filled with &lt;code&gt;if (case == SOCIAL)&lt;/code&gt; branches. Same for Factory, Strategy, and other patterns — &lt;strong&gt;Split first, then glue, order matters.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Beyond the two cases detailed in this article, the demo project has patterns working silently throughout — they're not the stars, but they're connectors between bricks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Location in Project&lt;/th&gt;
&lt;th&gt;What It Glues&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LoginRouter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Login state changes → cross-page pending follow-up operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Template Method&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BaseBillRender&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multiple posters share inflate → bind → render skeleton&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Simple Factory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;BillRenderFactory&lt;/code&gt;, &lt;code&gt;BillDataLoader&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Create corresponding Render / data by &lt;code&gt;billCase&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strategy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;BillRender&lt;/code&gt; and its implementations&lt;/td&gt;
&lt;td&gt;Switch different poster rendering strategies under the same screenshot process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Adapter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GoodsDetailAdapter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;14 types of &lt;code&gt;ListItem&lt;/code&gt; → RecyclerView multi-type rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  IV. Complete Lego Architecture System: Four Articles Connected
&lt;/h2&gt;

&lt;p&gt;At this point, the four articles form a complete narrative:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Article 1: Problem Awareness
  └─ Architecture is just "technique", connection count determines complexity

Article 2: Splitting Methodology
  └─ Lego Architecture = Infinite splitting to minimum particles + Governance iteration

Article 3: Splitting Practice
  └─ Product Detail Page: ListItem + Mapper + Assembler + ViewModel

Article 4: The Glue
  └─ Design Patterns: On top of splitting, use appropriate patterns to stably assemble bricks (this article focuses on Observer and Template Method)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete Lego Architecture system can be summarized as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One Axiom&lt;/strong&gt;: Divide-and-conquer + Single Responsibility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Theorems&lt;/strong&gt;: Governance thinking, tool iteration (Private→Shared→Remote), reuse discovery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One Practice&lt;/strong&gt;: 15 independent components in product detail page&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One Layer of Glue&lt;/strong&gt;: Design patterns — this article focuses on Observer and Template Method; the project also uses Factory, Strategy, Adapter patterns for connection (see table above)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you truly build applications with Lego thinking, you'll find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity doesn't come from the application itself&lt;/strong&gt;, but from not splitting it into small enough bricks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design patterns aren't for showing off&lt;/strong&gt;, but for selecting appropriate patterns by scenario after splitting, using minimal connections to stably assemble bricks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Good code isn't written by learning one architecture&lt;/strong&gt;, but by having divide-and-conquer awareness, governance discipline, pattern intuition, and the ability to spot reusable bricks.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Series Conclusion
&lt;/h2&gt;

&lt;p&gt;Four articles, from "Architecture Evolution History" to "Lego Splitting Methodology", to "Product Detail Page Practice", and finally to "Design Pattern Glue" — we've tried to answer a consistent question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to truly improve Android code quality?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer isn't in the labels of MVVM or MVI, but in daily programming discipline: split until you can't split anymore, glue only when needed, govern for sustainable iteration.&lt;/p&gt;

&lt;p&gt;May your codebase be like a box of Lego — each brick has clear responsibilities, stable interfaces, can be combined freely, and can still build new models after many years.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related Reading&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f"&gt;Article 1: A Decade of Android Architecture Evolution: What Problem Are We Really Solving?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7"&gt;Article 2: The Lego Architecture: Divide and Conquer, Taken to the Extreme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4"&gt;Article 3: Refactoring a Product Detail Page with Lego Architecture: From 3000 Lines to 15 Standalone Components&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>mobile</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Modern Android Architecture (Part 3): Refactoring a Product Detail Page with Lego Architecture: From 3000 Lines to 15 Standalone Components</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Mon, 01 Jun 2026 02:06:26 +0000</pubDate>
      <link>https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4</link>
      <guid>https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series Navigation&lt;/strong&gt;: &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f"&gt;Article 1: A Decade of Android Architecture Evolution&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7"&gt;Article 2: The Lego Architecture: Divide and Conquer, Taken to the Extreme&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f"&gt;Article 4: Design Patterns — The Glue of Lego Architecture&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Repository&lt;/strong&gt;: &lt;a href="https://github.com/zealot2002/androidArch" rel="noopener noreferrer"&gt;https://github.com/zealot2002/androidArch&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Foreword: Product Detail Page — The "Touchstone" of Architecture
&lt;/h2&gt;

&lt;p&gt;The product detail page is widely recognized as the "touchstone" of e-commerce app architecture. A standard detail page typically contains over 10 business sections: image carousel, price marketing, specification selection, user reviews, store information, product details, recommended products...&lt;/p&gt;

&lt;p&gt;In traditional architecture, we've seen too many real and painful disasters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unclear overall control logic, no real "traffic hub"&lt;/strong&gt;: Page control logic is scattered across Activity, Fragment, Adapter, and even utility classes. You find code loading data in Activity, follow the call chain to ViewModel, then it might end up in an Adapter's internal callback. There's no centralized place to see "what this page does in what order."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Severe code redundancy&lt;/strong&gt;: Redundant logic and slightly different code snippets are scattered everywhere. Either you don't know how to extract methods — always feeling the method name would be longer than the code itself — or you force an extraction that does multiple things (a method called &lt;code&gt;updatePrice&lt;/code&gt; that also refreshes inventory, logs analytics, and shows a Toast).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scattered glue code everywhere&lt;/strong&gt;: Temporary flags, anonymous callbacks, nested conditionals... scattered throughout, reading like a book without table of contents or chapters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chaotic organization, vague responsibility boundaries&lt;/strong&gt;: Although seemingly divided into classes or packages, data conversion, UI rendering, and business logic are often intertwined. Changing a price display logic might require jumping through five or six files along the call chain, always worrying about breaking unrelated logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard to find things&lt;/strong&gt;: A price formatting method might be hidden in &lt;code&gt;GoodsUtils&lt;/code&gt;, in a ViewModel's private method, or even hardcoded directly in an Adapter's &lt;code&gt;onBindViewHolder&lt;/code&gt;. Newcomers spend most of their time "archaeological searching" rather than understanding business.&lt;/p&gt;

&lt;p&gt;The essence of these problems isn't the lack of some "advanced architecture," but:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Not split into minimal particles&lt;/strong&gt; — lacking the divide-and-conquer thinking advocated by Lego Architecture, code blocks are too large with too many responsibilities, making reuse and maintenance difficult.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of governance thinking&lt;/strong&gt; — no clear code organization standards or boundaries established, allowing redundant logic and glue code to proliferate until it spirals out of control.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As discussed in Article 2, the core of Lego Architecture is divide-and-conquer and single responsibility, along with practical methods like governance thinking, tool iteration, and reuse discovery. Today, we'll demonstrate with actual project code: &lt;strong&gt;how to apply Lego Architecture's "minimum granularity + dynamic assembly" philosophy to break down complex UI and business logic into independent, reusable, pluggable bricks using a product detail page as an example.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  I. Core Design: Everything is a List Item — The Ultimate Practice of Minimum Granularity
&lt;/h2&gt;

&lt;p&gt;Following Lego Architecture's principle of "infinite splitting to minimum particles," we need to break down the entire page into individual UI units. Following this idea, we choose to use &lt;strong&gt;a single&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;RecyclerView&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;to host all UI elements&lt;/strong&gt;. While counterintuitive at first glance, this is a natural projection of divide-and-conquer thinking for list-based pages.&lt;/p&gt;

&lt;p&gt;The benefits are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each UI unit corresponds to an independent list item type, with no nested dependencies between them&lt;/li&gt;
&lt;li&gt;Scrolling performance is uniformly managed by &lt;code&gt;RecyclerView&lt;/code&gt;, avoiding lag and memory issues from multi-layer nesting&lt;/li&gt;
&lt;li&gt;Adding or removing sections doesn't require layout structure changes, just add/remove corresponding list items&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.1 Define a Unified Brick Interface
&lt;/h3&gt;

&lt;p&gt;We use &lt;code&gt;sealed class&lt;/code&gt; to define all list item types — our "brick inventory." &lt;strong&gt;Each list item brick has only one responsibility: describe the data needed for a UI section.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Product basic information sections&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PriceMarketing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Responsibility: Display price, promotion tags&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;ProductTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// Responsibility: Display product title, subtitle&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;ServiceSales&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// Responsibility: Display service commitments, sales data&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AfterSales&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;     &lt;span class="c1"&gt;// Responsibility: Display after-sales guarantee information&lt;/span&gt;

    &lt;span class="c1"&gt;// Specification and quantity sections&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;SpecSelection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// Responsibility: Display specification selector (weight/flavor, etc.)&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PurchaseQuantity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Responsibility: Display quantity increment/decrement controls&lt;/span&gt;

    &lt;span class="c1"&gt;// Universal decoration sections&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;SectionDivider&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Responsibility: Divider between sections&lt;/span&gt;

    &lt;span class="c1"&gt;// Review and store sections&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Review&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailReviewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Responsibility: Display user review summary (rating, review count)&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Shop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailShopState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;     &lt;span class="c1"&gt;// Responsibility: Display store info (name, rating, customer service)&lt;/span&gt;

    &lt;span class="c1"&gt;// Product detail sections&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;DetailsTitle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                       &lt;span class="c1"&gt;// Responsibility: Display "Product Details" title&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;DetailImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// Responsibility: Display one detail image&lt;/span&gt;

    &lt;span class="c1"&gt;// Recommendation sections&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;RecommendTitle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                     &lt;span class="c1"&gt;// Responsibility: Display "Recommended for You" title&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;RecommendProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BrowseProduct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Responsibility: Display single recommended product&lt;/span&gt;

    &lt;span class="c1"&gt;// Footer section&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;ListFooter&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Responsibility: List footer placeholder/loading complete indicator&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why is this better than traditional approaches?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates "God layouts" completely: No nested &lt;code&gt;ScrollView&lt;/code&gt; or &lt;code&gt;LinearLayout&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Each list item can be developed, tested, and iterated independently&lt;/li&gt;
&lt;li&gt;Adding a new UI section only requires adding a new subclass, &lt;strong&gt;no existing code needs modification&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  II. Data Layering: Raw Data → UI State — Encapsulating Data Conversion with Mapper
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;[Mapper Responsibility:]&lt;/strong&gt; Responsible for converting backend raw data into immutable state objects directly usable by the UI layer. It contains no business logic and is a pure function that takes raw data and outputs UI state.&lt;/p&gt;

&lt;p&gt;With list item bricks defined, we need to prepare data for each brick. To reduce coupling between UI and backend data models, we introduce a &lt;strong&gt;data conversion layer (Mapper)&lt;/strong&gt; to produce data for individual list item bricks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionMapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Responsibility: Convert GoodsDetail backend model + user selections (specifications, quantity) into UI state for product basic sections&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;shipFromCity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
        &lt;span class="n"&gt;selectedWeightIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;selectedFlavorIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;selectedSku&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selectedWeightIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firstOrNull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;priceYuan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectedSku&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;priceYuan&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;"98.00"&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;formattedPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDisplayPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priceYuan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// ... other field mappings&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;priceYuan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;formattedPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;weightSpecs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Core Value&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolate backend changes&lt;/strong&gt;: If backend changes field names, only &lt;code&gt;Mapper&lt;/code&gt; needs modification, UI layer is completely unaffected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unified data format&lt;/strong&gt;: All UI formatting logic is centralized in Mapper&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete decoupling&lt;/strong&gt;: UI layer only depends on UI state, not any backend data models&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  III. Dynamic Assembly: Assembler — The Instruction Manual for Bricks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;[Assembler Responsibility:]&lt;/strong&gt; Responsible for dynamically assembling the final list item sequence based on current state (product info, recommendation list, experiment flags, etc.). It determines which sections to display and in what order — the page's "assembly workshop."&lt;/p&gt;

&lt;p&gt;If list items are bricks, then &lt;code&gt;Assembler&lt;/code&gt; is the Lego instruction manual. It tells us which bricks to use, in what order, and how to assemble them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListAssembler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Responsibility: Assemble complete list items based on input section states&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;detailImageUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="n"&gt;recommendProducts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BrowseProduct&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="n"&gt;showListEndFooter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PriceMarketing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ProductTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ServiceSales&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SectionDivider&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AfterSales&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SectionDivider&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SpecSelection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PurchaseQuantity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SectionDivider&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Review&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetailReviewMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SectionDivider&lt;/span&gt;

        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Shop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetailShopMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SectionDivider&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DetailsTitle&lt;/span&gt;
        &lt;span class="n"&gt;detailImageUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DetailImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RecommendTitle&lt;/span&gt;
        &lt;span class="n"&gt;recommendProducts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RecommendProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showListEndFooter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ListFooter&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;Assembler&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;solves multiple pain points of traditional architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pain Point&lt;/th&gt;
&lt;th&gt;Assembler Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dynamicity&lt;/td&gt;
&lt;td&gt;Dynamically determine which sections to display based on backend data, AB tests, user identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurability&lt;/td&gt;
&lt;td&gt;Adjusting section order only requires moving two lines of code, no UI logic changes needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoupling&lt;/td&gt;
&lt;td&gt;Sections are dynamically assembled, naturally avoiding logic being coupled inside specific sections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testability&lt;/td&gt;
&lt;td&gt;Pass different parameters to verify different assembly results without launching the App&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  IV. ViewModel: Pure State Coordinator
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;[ViewModel Responsibility:]&lt;/strong&gt; Acts as a page-level state holder and coordinator. It contains no UI logic and no complex business logic — only responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Holding page data (LiveData/StateFlow)&lt;/li&gt;
&lt;li&gt;Receiving user operations from View (e.g., clicking specifications, modifying quantity)&lt;/li&gt;
&lt;li&gt;Calling Mapper and Assembler to generate new UI state&lt;/li&gt;
&lt;li&gt;Exposing state to View for observation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailViewModel&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;repository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoodsRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_detail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetail&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetail&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_detail&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_listItems&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;listItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetailListItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_listItems&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_detailImageUrls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;detailImageUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_detailImageUrls&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;selectedWeightIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;selectedFlavorIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;purchaseQuantity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spuId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;detailResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchGoodsDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spuId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;_detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detailResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;rebuildListItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;selectWeightSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;selectedWeightIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
        &lt;span class="nf"&gt;rebuildListItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;selectFlavorSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;selectedFlavorIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
        &lt;span class="nf"&gt;rebuildListItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;incrementQuantity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;purchaseQuantity&lt;/span&gt;&lt;span class="p"&gt;++&lt;/span&gt;
        &lt;span class="nf"&gt;rebuildListItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;decrementQuantity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;purchaseQuantity&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;purchaseQuantity--&lt;/span&gt;
            &lt;span class="nf"&gt;rebuildListItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;rebuildListItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;productSection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailProductSectionMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;shipFromCity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shipFromCity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;selectedWeightIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectedWeightIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;selectedFlavorIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectedFlavorIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;purchaseQuantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailListAssembler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;productSection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;productSection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;detailImageUrls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detailImages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;recommendProducts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;emptyList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;showListEndFooter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;_listItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;_detailImageUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detailImages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire &lt;code&gt;ViewModel&lt;/code&gt; has a single responsibility and clear logic, making it easy for newcomers to understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  V. Activity: A Thin Shell — The Glue Layer Between Architecture and View
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;[Activity Responsibility:]&lt;/strong&gt; Serves as the interaction entry point between the page and Android system, responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initializing view binding (&lt;code&gt;setContentView&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Setting up &lt;code&gt;RecyclerView&lt;/code&gt;, Adapter, and other UI components&lt;/li&gt;
&lt;li&gt;Forwarding user click events to &lt;code&gt;ViewModel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Observing LiveData in &lt;code&gt;ViewModel&lt;/code&gt; and updating UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Activity is not "just a container"; it's an important glue layer between architecture and the Android view system.&lt;/strong&gt; In Lego Architecture, we still respect Activity's role as navigation and lifecycle manager, but delegate all specific UI assembly and business logic to bricks — ensuring Activity never bloats.&lt;/p&gt;

&lt;p&gt;The final &lt;code&gt;Activity&lt;/code&gt; code is clean and clear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RouterConstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GOODS_DETAIL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityGoodsDetailBinding&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ViewModelProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nc"&gt;GoodsDetailViewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;imageAdapter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoodsImagePagerAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;detailAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailAdapter&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ActivityGoodsDetailBinding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layoutInflater&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;setupReviewListPanel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;setupDetailRecyclerView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;setupScrollToTop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;setupTopBarScroll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;setupActions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;setupPager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;observeViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;observeViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;currentDetail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;
            &lt;span class="n"&gt;currentReviewState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailReviewMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;imageAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bannerImages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;updateImageCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bannerImages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;imageUrls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detailImageUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;orEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;detailAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageUrls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detailImageUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;imageUrls&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;imageUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;detailAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageUrls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire &lt;code&gt;Activity&lt;/code&gt; only does three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize views and &lt;code&gt;Adapter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Forward user click events to &lt;code&gt;ViewModel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Observe &lt;code&gt;ViewModel&lt;/code&gt; state and update UI&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  VI. Independent Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 Grid Spacing Decoration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;[Responsibility: GridSpacingDecoration]&lt;/strong&gt; A universal RecyclerView grid spacing decorator responsible for adding equal outer margins to each item in grid layouts. Placed in the &lt;code&gt;common&lt;/code&gt; module, it can be directly reused in any project requiring grid layouts.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.2 Review Panel: Minimally Intrusive Page Composition
&lt;/h3&gt;

&lt;p&gt;In the product detail page, the review list is a complex independent feature, but we want it &lt;strong&gt;not to affect the main page's simplicity&lt;/strong&gt;. Through a side panel + Fragment approach, we achieve minimally intrusive page composition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Components and Responsibilities&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ReviewListPanelController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Controls panel animations (show/hide), manages Fragment addition/removal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GoodsReviewListFragment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Independently hosts complete review list UI and interaction logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GoodsReviewListAdapter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RecyclerView Adapter for review list, responsible for rendering each review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GoodsDetailReviewMapper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Converts detail data to UI state needed by review panel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Lego Thinking in Action&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Completely Independent Fragment&lt;/strong&gt;: Review functionality is fully encapsulated in &lt;code&gt;GoodsReviewListFragment&lt;/code&gt;, containing complete list logic
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoodsReviewListFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;listAdapter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoodsReviewListAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rvReviewList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layoutManager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LinearLayoutManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;requireContext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rvReviewList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;adapter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listAdapter&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailReviewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tvReviewListTitle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goods_review_section_title_format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;listAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GoodsReviewListMockData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clean Controller&lt;/strong&gt;: Panel controller only handles animations and Fragment management, no business logic
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReviewListPanelController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FragmentActivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;panelRoot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;scrim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;fragmentContainerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviewState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailReviewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;ensureFragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// Animation to show panel&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Animation to hide panel&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Main Activity&lt;/strong&gt;: Only needs to initialize Controller, review logic doesn't intrude into main Activity
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setupReviewListPanel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;reviewListPanelController&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ReviewListPanelController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;panelRoot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewListPanelOverlay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;scrim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewListPanelOverlay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewListScrim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;panel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewListPanelOverlay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewListPanel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fragmentContainerId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewListPanelOverlay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewListFragmentContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;showReviewListPanel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;reviewState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoodsDetailReviewMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reviewListPanelController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;On-Demand Fragment Creation&lt;/strong&gt;: Review panel Fragment is only created on first click, no impact on initial screen performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Architectural Benefits&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review functionality can be developed and tested independently&lt;/li&gt;
&lt;li&gt;Main Activity contains no review-related UI logic&lt;/li&gt;
&lt;li&gt;Panel animations and Fragment management are encapsulated in Controller&lt;/li&gt;
&lt;li&gt;Can be easily replaced with other implementations in the future (e.g., full-screen Fragment, BottomSheet)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  VII. Project Structure Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 Module Directory Tree
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;androidArch/
│
├── app/                          # Application entry
│   ├── App.kt                    # Application
│   └── MainActivity.kt           # Home page
│
├── common/                       # Common base (can be depended on by all modules)
│   ├── base/
│   │   ├── BaseActivity.kt       # Activity base class (encapsulates analytics, lifecycle)
│   │   └── BaseViewModel.kt      # ViewModel base class
│   │
│   ├── utils/
│   │   ├── ToastUtils.kt         # Global Toast
│   │   ├── StatusBarUtils.kt     # Status bar operations
│   │   └── PaletteColorUtils.kt  # Color extraction
│   │
│   ├── router/
│   │   └── AppRouter.kt         # Route navigation
│   │
│   └── widgets/
│       ├── GridSpacingDecoration.kt   # Universal grid spacing decorator
│       └── IconFontView.kt           # Icon font component
│
├── app_res/                      # Resource center (colors, dimensions, Drawables)
│   ├── res/
│   │   ├── drawable/             # 50+ universal Drawables
│   │   ├── values/colors_*.xml   # Three-layer color system
│   │   └── values/dimens.xml      # Dimension tokens
│   └── assets/iconfont.ttf        # Icon font
│
├── feature-goods/                # Goods module
│   ├── ui/
│   │   ├── GoodsDetailActivity.kt    # Product detail page (main controller)
│   │   ├── GoodsDetailAdapter.kt     # List adapter (14 ViewTypes)
│   │   ├── GoodsDetailListItem.kt    # List item sealed class
│   │   ├── GoodsDetailListAssembler.kt   # List assembler
│   │   ├── GoodsDetailProductSectionMapper.kt  # Data→UI state
│   │   ├── GoodsDetailReviewMapper.kt
│   │   ├── GoodsDetailShopMapper.kt
│   │   ├── ReviewListPanelController.kt  # Review panel controller
│   │   ├── GoodsReviewListFragment.kt   # Review list (independent Fragment)
│   │   └── DetailAnchorTab.kt           # Tab enum
│   │
│   ├── viewmodel/
│   │   └── GoodsDetailViewModel.kt  # State coordinator
│   │
│   ├── model/
│   │   ├── GoodsDetail.kt              # Raw data model
│   │   ├── GoodsDetailProductSectionState.kt  # UI state model
│   │   ├── GoodsDetailReviewState.kt
│   │   └── BrowseProduct.kt
│   │
│   └── data/
│       ├── GoodsRepository.kt          # Data repository
│       └── GoodsDetailMockCatalog.kt   # Mock data
│
├── feature-login/                # Login module
│   ├── ui/LoginActivity.kt
│   ├── domain/UserRepository.kt
│   └── viewmodel/LoginViewModel.kt
│
└── tools/                       # Pure utilities (cross-project reuse)
    └── utils/
        ├── DateUtils.kt
        ├── StringUtils.kt
        └── ValidateUtils.kt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 Core Class Responsibility Description
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Class Name&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;Lines of Code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ui&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailActivity&lt;/td&gt;
&lt;td&gt;View binding, lifecycle, user interaction forwarding&lt;/td&gt;
&lt;td&gt;approx. 500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ui&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailAdapter&lt;/td&gt;
&lt;td&gt;List rendering for 14 ViewTypes&lt;/td&gt;
&lt;td&gt;approx. 400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ui&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailListAssembler&lt;/td&gt;
&lt;td&gt;Dynamic list item assembly&lt;/td&gt;
&lt;td&gt;approx. 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ui&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailListItem&lt;/td&gt;
&lt;td&gt;List item type definition&lt;/td&gt;
&lt;td&gt;approx. 50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ui&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ReviewListPanelController&lt;/td&gt;
&lt;td&gt;Review panel animation and Fragment management&lt;/td&gt;
&lt;td&gt;approx. 150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ui&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DetailAnchorTab&lt;/td&gt;
&lt;td&gt;Tab enum (independent small class)&lt;/td&gt;
&lt;td&gt;approx. 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mapper&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailProductSectionMapper&lt;/td&gt;
&lt;td&gt;Data→Product section UI state&lt;/td&gt;
&lt;td&gt;approx. 60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mapper&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailReviewMapper&lt;/td&gt;
&lt;td&gt;Data→Review section UI state&lt;/td&gt;
&lt;td&gt;approx. 30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mapper&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailShopMapper&lt;/td&gt;
&lt;td&gt;Data→Shop section UI state&lt;/td&gt;
&lt;td&gt;approx. 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;vm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GoodsDetailViewModel&lt;/td&gt;
&lt;td&gt;Data loading, state holding, trigger rebuild&lt;/td&gt;
&lt;td&gt;approx. 150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;common&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;BaseActivity&lt;/td&gt;
&lt;td&gt;Encapsulates analytics, Edge-to-Edge&lt;/td&gt;
&lt;td&gt;approx. 50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;common&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GridSpacingDecoration&lt;/td&gt;
&lt;td&gt;Universal grid spacing decorator&lt;/td&gt;
&lt;td&gt;approx. 40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;common&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ToastUtils&lt;/td&gt;
&lt;td&gt;Global Toast&lt;/td&gt;
&lt;td&gt;approx. 30&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  7.3 Data Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Backend Data          Mapper Conversion         Assembler Assembly         ViewModel Holding        Activity Observation
   │                        │                           │                        │                        │
   ▼                        ▼                           ▼                        ▼                        ▼
GoodsDetail ──► GoodsDetailProduct ──► List&amp;lt;GoodsDetail ──► _listItems ─────► notifyDataSetChanged
                SectionState             ListItem&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;This practical case fully implements the core principles of Lego Architecture proposed in Article 2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Base Classes&lt;/strong&gt;: &lt;code&gt;GoodsDetailActivity&lt;/code&gt; only inherits an empty &lt;code&gt;BaseActivity&lt;/code&gt; (handling only essential seams like analytics and lifecycle), with all functionality provided through pluggable bricks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infinite Splitting&lt;/strong&gt;: The page is split into 15+ independent list item bricks, each with a single responsibility; the review panel is split into independent &lt;code&gt;Fragment&lt;/code&gt; + &lt;code&gt;Controller&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Iteration&lt;/strong&gt;: The price formatting method was initially written in &lt;code&gt;feature_goods/utils&lt;/code&gt;, then moved to &lt;code&gt;common/utils&lt;/code&gt; after review found it was needed by multiple modules — exactly the "Private → Shared" evolution path described in Article 2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Detailed methodologies on governance thinking, the three stages of tool iteration (Private→Shared→Remote), and reuse discovery were fully explained in Article 2 and won't be repeated here.&lt;/p&gt;




&lt;h2&gt;
  
  
  VIII. Architecture Advantage Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Traditional Approach (Unsplit)&lt;/th&gt;
&lt;th&gt;Lego Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Organization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 Activity with 3000+ lines&lt;/td&gt;
&lt;td&gt;10+ independent components with 100-300 lines each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Changing one thing affects everything&lt;/td&gt;
&lt;td&gt;Independent modifications, no cross-component impact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Testability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Difficult to test individually&lt;/td&gt;
&lt;td&gt;Each component can be tested independently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reusability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Almost impossible to reuse&lt;/td&gt;
&lt;td&gt;Components can be reused across multiple pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adding sections requires changing many places&lt;/td&gt;
&lt;td&gt;Adding sections only needs new ListItem and Assembler logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parallel Development&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only sequential development possible&lt;/td&gt;
&lt;td&gt;Multiple developers can work on different components in parallel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  IX. Conclusion: The Ideal Complex Page
&lt;/h2&gt;

&lt;p&gt;An ideal complex page, architecturally speaking, consists of several functional blocks with clear responsibilities and boundaries. Inside each block, you see highly cohesive utility classes and UI components, with minimal scattered glue code. Numerous basic bricks, composite bricks, advanced bricks, and UI components are battle-tested, stable, reliable "technical assets." Ultimately, what was once a bloated complex page becomes &lt;strong&gt;robust, elegant, agile, lightweight, extensible, testable, maintainable, and highly readable&lt;/strong&gt; — like a carefully designed work of art rather than a pile of unmanageable code.&lt;/p&gt;

&lt;p&gt;The complete Lego Architecture system can be summarized as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One Axiom&lt;/strong&gt;: Divide-and-conquer + Single Responsibility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Theorems&lt;/strong&gt;: Governance thinking (big-picture view, logic convergence), tool iteration (Private→Shared→Remote), reuse discovery (small independent particles facilitate scanning and integration)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you truly build applications with Lego thinking, you realize: &lt;strong&gt;Complexity doesn't come from the application itself, but from not splitting it into small enough bricks and lacking continuous governance and iteration.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Of course, mastery of design patterns, code aesthetics, and the ability to spot reusable bricks are also essential qualities of an excellent engineer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Article Preview&lt;/strong&gt;: We'll continue enriching our demo project and explore how design patterns can serve as the glue for Lego Architecture, making your brick combinations more flexible and robust. See &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f"&gt;Article 4&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related Reading&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f"&gt;Article 1: A Decade of Android Architecture Evolution: What Problem Are We Really Solving?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7"&gt;Article 2: The Lego Architecture: Divide and Conquer, Taken to the Extreme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f"&gt;Article 4: Design Patterns — The Glue of Lego Architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>mobile</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Modern Android Architecture (Part 2): The Lego Architecture: Divide and Conquer, Taken to the Extreme</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Mon, 01 Jun 2026 02:06:02 +0000</pubDate>
      <link>https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7</link>
      <guid>https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series Navigation&lt;/strong&gt;: &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f"&gt;Article 1: A Decade of Android Architecture Evolution&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4"&gt;Article 3: Refactoring a Product Detail Page with Lego Architecture&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f"&gt;Article 4: Design Patterns — The Glue of Lego Architecture&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Foreword: The Pain of Bad Code Doesn't Come from Architecture
&lt;/h3&gt;

&lt;p&gt;In the previous article, we discussed that architecture is just "technique" — it only solves the rough partitioning of code, which is far from sufficient. In this article, we face the real pain points in project implementation and propose a practical divide-and-conquer methodology — Lego Architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  0. Inspiration: Reflections from the Pain of Architecture Migration
&lt;/h3&gt;

&lt;p&gt;I've gone through three large-scale Android architecture refactorings, each time feeling like I've shed a layer of skin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From MVC to MVP: The team spent two months creating a heavy set of &lt;code&gt;BaseActivity&lt;/code&gt; / &lt;code&gt;BaseFragment&lt;/code&gt; / &lt;code&gt;BasePresenter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;From MVP to MVVM: All Base classes had to be rewritten, a large number of utility classes deeply coupled with Base were forced to change, affecting 40% of business code.&lt;/li&gt;
&lt;li&gt;When MVI started to become popular, we were completely exhausted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What made us so passive? Is migrating to MVI a one-time solution? Will future architectures like MV-Whatever repeat this nightmare? If migration is inevitable, which code can remain unchanged?&lt;/p&gt;

&lt;p&gt;This pain forced us to ask a fundamental question: &lt;strong&gt;What is the ultimate answer to architecture?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sitting in front of my computer, I suddenly remembered the Lego bricks I played with as a child.&lt;/p&gt;

&lt;p&gt;Why can a few basic bricks build houses, cars, spaceships? Why can bricks from 10 years ago still perfectly fit with new sets?&lt;br&gt;
At that moment, I seemed to see the answer to all architectural problems.&lt;/p&gt;

&lt;p&gt;The most amazing thing about Lego is not the cool finished products, but those basic 1×1 and 2×4 bricks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only a few studs and tubes, no predefined functions.&lt;/li&gt;
&lt;li&gt;Follow a globally unified connection standard, perfectly compatible with any other Lego brick.&lt;/li&gt;
&lt;li&gt;Can be used anywhere in any model.&lt;/li&gt;
&lt;li&gt;Interface specifications have never changed since 1958.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In contrast, those specialized parts designed for specific models — like the curved hull of the Millennium Falcon — are almost useless outside of that one model. Once removed, they become waste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lego's core philosophy is: Minimum granularity = Maximum reusability = Maximum flexibility.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Specialized parts become useless outside their model. The same principle applies to code reuse.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From this, we've distilled a software engineering approach called &lt;strong&gt;Lego Architecture&lt;/strong&gt; — it doesn't aim to replace MVVM or MVI, but provides a set of &lt;strong&gt;programming philosophies and engineering disciplines&lt;/strong&gt; about "how to split, how to accumulate, how to govern."&lt;/p&gt;


&lt;h3&gt;
  
  
  I. Base Classes: Avoid If Possible, Keep Minimal If Necessary
&lt;/h3&gt;

&lt;p&gt;In the three architecture refactorings, what pained me the most wasn't business logic, but those seemingly "convenient" Base classes.&lt;/p&gt;

&lt;p&gt;What's the problem? &lt;strong&gt;We tied too many unnecessary things to Base.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  1.1 The Correct Use of Base: Avoid If Possible
&lt;/h4&gt;

&lt;p&gt;Base classes have only one valid reason to exist: &lt;strong&gt;Provide a seam for lifecycle-related capabilities needed by 90% of pages.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic page entry/exit tracking for analytics&lt;/li&gt;
&lt;li&gt;Callback distribution for permission requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beyond that, no business logic, page initialization order, or utility class references should go into Base.&lt;/p&gt;
&lt;h4&gt;
  
  
  1.2 Strongly Disliked: Constraining Page Initialization Workflow in Base
&lt;/h4&gt;

&lt;p&gt;I've seen Base classes like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;initCallerData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;initView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;initPageData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;initObservers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initPageData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initCallerData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initObservers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;violent constraint&lt;/strong&gt; on subclasses. When you don't know the initialization order desired by upper-level pages (some want to initialize observers first, others want to initialize views first), this template method becomes a shackle and source of redundant confusion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good Base classes shouldn't dictate order, only provide optional capabilities.&lt;/strong&gt; Even &lt;code&gt;initView&lt;/code&gt; shouldn't exist — let each page write its own initialization in &lt;code&gt;onCreate&lt;/code&gt;, making it clear and explicit.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.3 Pluggable Bricks Instead of Base
&lt;/h4&gt;

&lt;p&gt;Observation reveals that Base classes often contain many methods or code blocks that could be in xxxUtils — permission requests, soft keyboard management, network detection... They're stuffed into Base only because "multiple pages need them," not because they're truly lifecycle-related.&lt;/p&gt;

&lt;p&gt;Better approach: Base is just an empty shell; all functionality is provided through pluggable bricks.&lt;/p&gt;

&lt;p&gt;For example, if you need permission request capability, instead of writing it in Base, use an independent PermissionHelper directly where needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PermissionHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onGranted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any page, Fragment, or Dialog can use this brick directly without depending on inheritance. Base can even be an open class with nothing inside.&lt;/p&gt;

&lt;h3&gt;
  
  
  II. From Coarse-Grained to Extreme Divide-and-Conquer: Lego Principles
&lt;/h3&gt;

&lt;p&gt;All mainstream architectures in the industry (MVC, MVP, MVVM, MVI, Clean Architecture...) essentially embody &lt;strong&gt;divide-and-conquer thinking&lt;/strong&gt; — they split code by responsibility, layer, or data flow.&lt;/p&gt;

&lt;p&gt;But their granularity is usually &lt;strong&gt;coarse&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A layer (View, ViewModel, Model)&lt;/li&gt;
&lt;li&gt;A module (feature, domain, data)&lt;/li&gt;
&lt;li&gt;A role (Presenter, UseCase)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They don't answer a crucial question: &lt;strong&gt;How fine-grained should we split?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lego bricks provide a physical-world answer: keep splitting until reaching &lt;strong&gt;indivisible basic particles&lt;/strong&gt;. A 2×4 brick has a unified interface, can be used anywhere in any Lego model, and hasn't changed in 68 years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lego Architecture is the ultimate practice of divide-and-conquer thinking: not just splitting at the MVX level, but splitting infinitely across all levels and dimensions until each unit does only one thing, with stable interfaces and no redundant functionality.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This principle can be applied to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI layer: Each &lt;code&gt;ViewHolder&lt;/code&gt; of a &lt;code&gt;RecyclerView&lt;/code&gt; is an independent brick&lt;/li&gt;
&lt;li&gt;Logic layer: Each &lt;code&gt;UseCase&lt;/code&gt; encapsulates only one business scenario&lt;/li&gt;
&lt;li&gt;Utility layer: Each utility method does only one thing&lt;/li&gt;
&lt;li&gt;State layer: Each &lt;code&gt;State&lt;/code&gt; describes only one independent domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The stopping condition for splitting is simple: stop when you can't give the unit a smaller, more accurate name. If a class or method name contains words like "and", "with", or "as well as", it means it can be split further.&lt;/p&gt;

&lt;p&gt;This is the fundamental difference between Lego Architecture and other architectures:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Other architectures tell you "which layer code should go to".&lt;br&gt;
Lego Architecture tells you "how small code should be split and how to keep splitting".&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  III. Splitting Examples Under Lego Thinking
&lt;/h3&gt;

&lt;p&gt;Let's look at some concrete examples of how code is split into minimal particles following Lego principles.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.1 Utility Classes: From Kitchen Sink to Atomic Bricks
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Counterexample&lt;/strong&gt;: A &lt;code&gt;DateUtils&lt;/code&gt; with a dozen methods for time formatting, timestamp conversion, relative time calculation, timezone handling... hundreds of lines of code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lego Split&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DateFormatUtils&lt;/code&gt;: Only formats dates into strings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TimestampConverter&lt;/code&gt;: Only converts between timestamps and date objects&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RelativeTimeCalculator&lt;/code&gt;: Only calculates "just now", "a few minutes ago", etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TimeZoneHelper&lt;/code&gt;: Only handles timezone-related operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each class has a single responsibility, clear method names, and is easy to test and reuse.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.2 ViewModel: From God Object to Service Composition
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Counterexample&lt;/strong&gt;: A &lt;code&gt;HomeViewModel&lt;/code&gt; containing carousel data, recommendation lists, user info, shopping cart count, notification unread count... 5000 lines of code, changing one place may affect unrelated fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lego Split&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;HomeBannerViewModel&lt;/code&gt;: Only responsible for carousel data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HomeRecommendViewModel&lt;/code&gt;: Only responsible for recommendation lists&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ShoppingCartViewModel&lt;/code&gt;: Universal service, reusable across multiple pages&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NotificationViewModel&lt;/code&gt;: Universal service, reusable across multiple pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combined usage in Activity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bannerVM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HomeBannerViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;viewModels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;cartVM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ShoppingCartViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;viewModels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;notificationVM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;NotificationViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;viewModels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each ViewModel can be independently tested and reused. Even &lt;code&gt;ShoppingCartViewModel&lt;/code&gt; can be observed simultaneously in product detail pages, cart pages, and home pages.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.3 Intent/MVI State: From Explosion to Grouping
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Counterexample&lt;/strong&gt;: A &lt;code&gt;HomeIntent&lt;/code&gt; sealed class stuffed with 200+ intents, including carousel clicks, recommendation list load more, user avatar clicks...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lego Split&lt;/strong&gt;: Align Intents with ViewModels, each ViewModel corresponds to an Intent group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BannerIntent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Load&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BannerIntent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BannerIntent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecommendIntent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;LoadMore&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecommendIntent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecommendItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecommendIntent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same for State: Instead of stuffing all fields into one &lt;code&gt;HomeState&lt;/code&gt;, split into &lt;code&gt;BannerState&lt;/code&gt;, &lt;code&gt;RecommendState&lt;/code&gt;, etc., with each ViewModel managing its own state.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.4 UseCase: One Class Per Scenario
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Counterexample&lt;/strong&gt;: &lt;code&gt;UserUseCase&lt;/code&gt; with five unrelated operations: login, register, change password, get user info, upload avatar...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lego Split&lt;/strong&gt;: Each UseCase encapsulates only one complete business scenario.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LoginUseCase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RegisterUseCase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UpdatePasswordUseCase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FetchUserInfoUseCase&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, any page only needs to depend on the UseCase it needs, not the entire kitchen sink.&lt;/p&gt;




&lt;h3&gt;
  
  
  IV. Discovery and Iteration of Utility Classes: Good Bricks Grow Naturally
&lt;/h3&gt;

&lt;p&gt;Bricks in Lego Architecture aren't designed in one go; they emerge naturally during continuous development and refactoring — essentially a process of evolving from specialized parts to basic parts.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1 Private Bricks: Write as You Use
&lt;/h4&gt;

&lt;p&gt;During feature development, you find a piece of logic that can be encapsulated (like a price formatting method), but you're unsure if it's universal. Write it in the current module's &lt;code&gt;utils&lt;/code&gt; package as a &lt;strong&gt;private brick&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// feature_goods/utils/PriceFormatUtils.kt&lt;/span&gt;
&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;formatPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priceYuan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"¥$priceYuan"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's only used within this module and not exposed to other modules.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.2 Shared Bricks: Regular Review, Extract for Reuse
&lt;/h4&gt;

&lt;p&gt;The project conducts a review refactoring every quarter. The team scans private utilities under each &lt;code&gt;feature_xxx/utils&lt;/code&gt;, finds classes that are &lt;strong&gt;used by at least two modules&lt;/strong&gt; or &lt;strong&gt;clearly have universal value&lt;/strong&gt;, and moves them to the &lt;code&gt;common/utils&lt;/code&gt; module to become &lt;strong&gt;shared bricks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Meanwhile, the original private bricks disappear (or become thin, leaving only a delegation to the shared brick). This step requires unit testing and Code Review to ensure no functionality is broken during the move.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.3 Remote Bricks: Battle-Tested, Become Assets
&lt;/h4&gt;

&lt;p&gt;After a shared brick has been used online for half a year or a year and proven stable by millions of users, it can be extracted from the &lt;code&gt;common&lt;/code&gt; module, published to a Maven repository, and become a &lt;strong&gt;remote brick&lt;/strong&gt; for all company projects to depend on directly.&lt;/p&gt;

&lt;p&gt;At this point, it becomes a &lt;strong&gt;"write-once, use-forever tool"&lt;/strong&gt; — like &lt;code&gt;StringUtils&lt;/code&gt;, &lt;code&gt;NetworkUtils&lt;/code&gt;, &lt;code&gt;ScreenUtils&lt;/code&gt;. You'll never need to rewrite them; just upgrade the version number.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.4 Why Must We Split to Minimum Granularity?
&lt;/h4&gt;

&lt;p&gt;Because only when split small enough can you easily spot during regular scans: "Oh, this formatting and that formatting can be merged" or "This validation logic has appeared three times." If they're scattered in hundreds-of-lines classes or duplicated across different Activities, you'll never find reuse opportunities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The infinite splitting in Lego Architecture isn't for splitting's sake; it's to make reuse opportunities visible, turning 'passive discovery' into 'active scanning'.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  V. Conclusion: Lego Architecture, Embracing Change with Stability
&lt;/h3&gt;

&lt;p&gt;Lego Architecture isn't meant to replace your existing MVVM or MVI; it's a set of &lt;strong&gt;programming disciplines and governance philosophies&lt;/strong&gt; that require you to do the following on top of any architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Base Classes&lt;/strong&gt;: Avoid if possible; if unavoidable, only include the most basic lifecycle seams, never dictate initialization order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infinite Splitting&lt;/strong&gt;: Split code across all levels (UI, logic, state, utilities) into the smallest stable particles until each unit does only one thing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Utility Iteration&lt;/strong&gt;: Private → Shared → Remote, letting good bricks grow naturally and eventually become "write-once" technical assets.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you truly achieve these, you'll find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture migration is no longer a disaster: Base classes are thin shells, business logic is in pluggable bricks, changing architecture only changes the container.&lt;/li&gt;
&lt;li&gt;Code reuse is no longer a slogan: Minimum granularity naturally drives reuse; someone may have already provided a remote brick before you even write it.&lt;/li&gt;
&lt;li&gt;Maintenance costs drop exponentially: Each brick has a single responsibility, changes don't ripple to unrelated areas.&lt;/li&gt;
&lt;li&gt;Team collaboration is easy: Newcomers only need to learn brick usage, not understand thousands of lines of god classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is Lego Architecture — the ultimate practice of divide-and-conquer, a methodology that embraces change with stability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Article Preview&lt;/strong&gt;: We'll use a real e-commerce App product detail page to demonstrate the complete process of Lego Architecture from splitting to assembly.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related Reading&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f"&gt;Article 1: A Decade of Android Architecture Evolution: What Problem Are We Really Solving?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4"&gt;Article 3: Refactoring a Product Detail Page with Lego Architecture: From 3000 Lines to 15 Standalone Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f"&gt;Article 4: Design Patterns — The Glue of Lego Architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>mobile</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Modern Android Architecture (Part 1): A Decade of Android Architecture Evolution: What Problem Are We Really Solving?</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Mon, 01 Jun 2026 02:05:31 +0000</pubDate>
      <link>https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f</link>
      <guid>https://dev.to/zealot2002/modern-android-architecture-part-1-a-decade-of-android-architecture-evolution-what-problem-are-403f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series Navigation&lt;/strong&gt;: &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7"&gt;Article 2: The Lego Architecture: Divide and Conquer, Taken to the Extreme&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4"&gt;Article 3: Refactoring a Product Detail Page with Lego Architecture&lt;/a&gt; | &lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f"&gt;Article 4: Design Patterns — The Glue of Lego Architecture&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Foreword: After Learning All Architectures, Did Our Code Actually Get Better?
&lt;/h3&gt;

&lt;p&gt;Since Android's birth in 2010, mainstream architectures have undergone at least five industry-level iterations. We've memorized MVC's layering, mastered MVP's interface decoupling, embraced MVVM's data binding, praised Clean Architecture's dependency inversion, and now we're all turning to MVI's unidirectional data flow.&lt;/p&gt;

&lt;p&gt;But here's the gut-wrenching question: &lt;strong&gt;After learning and refactoring with all these architectures, has our code actually gotten better?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your answer is "No" — or even "We just moved the garbage code to a different place" — then this article is for you.&lt;/p&gt;




&lt;h3&gt;
  
  
  I. The Essence of Architectural Evolution: A Revolution to "Reduce Connections"
&lt;/h3&gt;

&lt;p&gt;Understanding all architectural evolution requires only one extremely simple model: &lt;strong&gt;The number of strong reference connections determines system complexity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The more connections there are, the deeper the dependencies between modules, and the more likely changes will trigger cascading reactions. Throughout history, all architectures have been doing the same thing — &lt;strong&gt;reducing connections as much as possible to make dependency relationships unidirectional and clear.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  1. MVC: The Confused Triangle (6 connections)
&lt;/h4&gt;

&lt;p&gt;As the originator of modern architecture, MVC first proposed the idea of layering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model: Data&lt;/li&gt;
&lt;li&gt;View: UI&lt;/li&gt;
&lt;li&gt;Controller: Logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, in classic implementations, all three layers &lt;strong&gt;interact with each other&lt;/strong&gt;, forming a closed triangle with a total of 6 strong reference connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;View ←→ Controller ←→ Model
↑                       ↑
└───────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Android, Activity/Fragment acts as both View and Controller, leading to the common "Massive View Controller" with thousands of lines. A single data change can affect all layers, making it nearly impossible to understand the flow.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. MVP: Cutting Direct Connections (4 connections)
&lt;/h4&gt;

&lt;p&gt;MVP made a revolutionary simplification: &lt;strong&gt;Completely prohibit direct interaction between View and Model.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All cross-layer communication must go through Presenter. The triangle is broken, becoming a linear dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;View ←→ Presenter ←→ Model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Connections reduced from 6 to 4, a 33% complexity reduction. View only displays, Model only handles data, and business logic lives entirely in Presenter. Between 2015-2018, this almost saved the entire Android development community.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. MVVM: Dependency Inversion (3 connections)
&lt;/h4&gt;

&lt;p&gt;Building on MVP, MVVM introduced data binding and observable states to achieve dependency inversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;View → ViewModel ←→ Model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;View still holds a ViewModel reference, but ViewModel no longer holds any View references.&lt;/li&gt;
&lt;li&gt;After completing a task, ViewModel only updates an observable data state, completely unaware and unconcerned about who is observing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Connections reduced to 3. The relationship between View and ViewModel becomes unidirectional, eliminating manual UI update code and tedious interface definitions.&lt;/p&gt;

&lt;p&gt;The deeper value of this change: ViewModel becomes a reusable &lt;strong&gt;mediator&lt;/strong&gt; (or service provider), observable and reusable by any view. Multiple ViewModels can naturally serve a single view. Compared to Presenter, ViewModel has smaller granularity and higher reusability.&lt;/p&gt;

&lt;p&gt;These improvements made MVVM quickly replace MVP as the mainstream.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. MVI: Unidirectional Closed Loop (3 connections + strict unidirectional flow)
&lt;/h4&gt;

&lt;p&gt;MVI is the latest evolution. Building on MVVM, it &lt;strong&gt;completely straightens the data flow&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All user operations are aggregated into a single &lt;strong&gt;Intent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;All UI states are aggregated into an immutable &lt;strong&gt;State&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Data flows in a strict unidirectional cycle: &lt;code&gt;User Action → Intent → ViewModel → Model → New State → View Rendering&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a reference perspective, both MVI and MVVM have 3 connections. But MVI enforces: &lt;strong&gt;Any state change must go through ViewModel; View cannot directly modify data.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This brings significant engineering benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Centralized state management for full visibility of page behavior&lt;/li&gt;
&lt;li&gt;Immutable state prevents accidental modifications&lt;/li&gt;
&lt;li&gt;Predictable behavior for easy debugging and logging&lt;/li&gt;
&lt;li&gt;Advanced features like time-travel debugging and unified logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;However, MVI has fatal implementation barriers.&lt;/strong&gt; It requires extremely high abstraction skills from developers. When programmers lacking splitting awareness use MVI, they fall into three typical traps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intent Explosion&lt;/strong&gt;: A complex page defines 200+ Intents with long, smelly names and overlapping responsibilities, making maintenance harder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;God State&lt;/strong&gt;: A single State object stuffed with 30 unrelated fields, where changes trigger cascading updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mesh Dependencies&lt;/strong&gt;: Multiple Intents call each other, forming chaotic call chains that make the unidirectional flow meaningless.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What should be a rigorous finite state machine becomes an "infinite state machine" — this is why MVI is seen as a disaster by some.&lt;/p&gt;




&lt;h3&gt;
  
  
  II. Architecture is Just "Technique": It Can't Stop You from Writing Bad Code
&lt;/h3&gt;

&lt;p&gt;I've seen many absurd projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using advanced MVVM but writing 5000-line ViewModels (architecture can't control internal bloat)&lt;/li&gt;
&lt;li&gt;Strictly following Clean Architecture but filling the Domain layer with business coupling (architecture can't control UseCase boundaries)&lt;/li&gt;
&lt;li&gt;Insisting on MVI's unidirectional flow but mixing carousel data, recommendation lists, and user info in one State (architecture can't control State granularity)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bad programming habits don't disappear just by switching architectures. We merely moved garbage from Activity to Presenter, then to ViewModel, then to UseCase. &lt;strong&gt;We just moved garbage from one room to another without actually cleaning it up.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Take the same login logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In MVC, it's scattered across the Activity&lt;/li&gt;
&lt;li&gt;After refactoring to MVP, it's copied entirely into Presenter, still 300 lines of procedural code&lt;/li&gt;
&lt;li&gt;After migrating to MVVM, it's stuffed into a &lt;code&gt;LoginViewModel&lt;/code&gt;, with the &lt;code&gt;login()&lt;/code&gt; method still a mess&lt;/li&gt;
&lt;li&gt;Converting to MVI, it becomes a jumble of Intents and States, appearing unidirectional on the surface but with tangled logic underneath&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Architecture is "technique". It only solves the "rough partitioning" of code, specifying where View, ViewModel, and Model should go. But it can't tell you how fine-grained to split code within the same layer, how to organize it, or how to reuse it.&lt;/strong&gt; What truly improves code quality includes at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Programming Philosophy&lt;/strong&gt;: Fundamental principles like divide-and-conquer, abstraction, and single responsibility determine how we view and decompose problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Hygiene&lt;/strong&gt;: Zero tolerance for redundant code, poor naming, and out-of-bounds logic keeps the codebase healthy long-term.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Programming Literacy&lt;/strong&gt;: Habits and awareness of writing readable, testable, maintainable code make collaboration painless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scientific Implementation&lt;/strong&gt;: Practical tool encapsulation strategies, governance processes, and iteration mechanisms ensure ideas are truly executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the foundational skills and qualities of an excellent engineer. Engineers with these abilities can write clean, robust, evolvable code without relying on any "silver bullet architecture."&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related Reading&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-2-the-lego-architecture-divide-and-conquer-taken-to-the-58j7"&gt;Article 2: The Lego Architecture: Divide and Conquer, Taken to the Extreme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-3-refactoring-a-product-detail-page-with-lego-architecture-4ii4"&gt;Article 3: Refactoring a Product Detail Page with Lego Architecture: From 3000 Lines to 15 Standalone Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/modern-android-architecture-part-4-design-patterns-the-glue-of-lego-architecture-1e9f"&gt;Article 4: Design Patterns — The Glue of Lego Architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>mobile</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Modern UI Architecture (Part 4): Design Ownership and Team Rollout</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Tue, 19 May 2026 05:24:06 +0000</pubDate>
      <link>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-zong-jie-she-ji-zhu-quan-hui-gui-yu-tuan-dui-luo-di-5h5j</link>
      <guid>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-zong-jie-she-ji-zhu-quan-hui-gui-yu-tuan-dui-luo-di-5h5j</guid>
      <description>&lt;h1&gt;
  
  
  现代化 UI 架构总结：设计主权回归与团队落地
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;本文是 UI 架构系列的第四篇，也是最后一篇。建议先阅读 &lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo"&gt;第一篇：三层颜色体系与系统化设计方案&lt;/a&gt;、&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-drawable-ceng-gui-fan-yu-gong-cheng-shi-jian-16km"&gt;第二篇：Drawable 层规范与工程实践&lt;/a&gt;、&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-style-ceng-ru-he-xi-tong-xing-xiao-chu-dai-ma-rong-yu-4nmb"&gt;第三篇：Style 层如何系统性消除代码冗余&lt;/a&gt; 了解完整架构体系。&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  一、架构全景：
&lt;/h2&gt;

&lt;p&gt;在前面三篇文章中，我们构建了一套完整的 UI 资源架构体系：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdzdapaozd6p6y7n0mjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdzdapaozd6p6y7n0mjv.png" alt=" " width="702" height="1836"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 架构的核心价值
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层级&lt;/th&gt;
&lt;th&gt;核心价值&lt;/th&gt;
&lt;th&gt;解决的问题&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Style&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;消除冗余，提升复用&lt;/td&gt;
&lt;td&gt;重复属性定义&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Drawable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;统一形态，状态管理&lt;/td&gt;
&lt;td&gt;视觉不一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Func_&lt;/strong&gt;*&lt;/td&gt;
&lt;td&gt;语义抽象，职能归一&lt;/td&gt;
&lt;td&gt;颜色滥用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;基础色+主题&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;主题切换，灵活适配&lt;/td&gt;
&lt;td&gt;多模式支持&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1.2 Demo 的局限性
&lt;/h3&gt;

&lt;p&gt;需要说明的是，本仓库中的 demo 仅作为&lt;strong&gt;抛砖引玉&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;颜色覆盖&lt;/strong&gt;：只实现了常用 token 子集；矩阵补全、新增档位均由&lt;strong&gt;设计师&lt;/strong&gt;在资源文件中维护，研发不自行扩展&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drawable 资源&lt;/strong&gt;：仅实现了按钮、输入框等基础组件的状态，实际项目会更复杂&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;组件覆盖&lt;/strong&gt;：demo 覆盖常用 token 子集（表面层级、填充/渐变、按钮形态与禁用态等），列表、弹窗等复杂场景仍需按产品扩展&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.3 Demo 运行效果（日间 / 夜间）
&lt;/h3&gt;

&lt;p&gt;仓库内置 &lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/layout/activity_token_showcase.xml" rel="noopener noreferrer"&gt;&lt;strong&gt;Token 样例&lt;/strong&gt;&lt;/a&gt; 页（&lt;code&gt;activity_token_showcase&lt;/code&gt;），用于对照资源命名与真机效果：右上角切换深浅色后，&lt;strong&gt;同一套&lt;/strong&gt; &lt;code&gt;func_*&lt;/code&gt; / Drawable / Style &lt;strong&gt;无需改代码&lt;/strong&gt;，仅由 &lt;code&gt;values-night&lt;/code&gt; 中 &lt;code&gt;t_*&lt;/code&gt; 映射驱动换肤。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;日间&lt;/th&gt;
&lt;th&gt;夜间&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9guqj0p87qyurh34kkvm.png" alt="日间 Token 样例" width="800" height="1787"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvidm5sxdywk04kr526q1.png" alt="夜间 Token 样例" width="800" height="1787"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GitHub 预览（可点击查看原图）：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;日间：&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/screenshot/day.png" rel="noopener noreferrer"&gt;screenshot/day.png&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;夜间：&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/screenshot/night.png" rel="noopener noreferrer"&gt;screenshot/night.png&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;左：&lt;code&gt;values&lt;/code&gt; 日间映射；右：&lt;code&gt;values-night&lt;/code&gt; 覆写 `t_&lt;/em&gt;` 后的同一页面。*&lt;/p&gt;

&lt;p&gt;这套架构的真正价值在于&lt;strong&gt;方法论&lt;/strong&gt;，而非具体实现。&lt;/p&gt;




&lt;h2&gt;
  
  
  二、深度思考：UI 架构的权力究竟属于谁？
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 一个尖锐的问题
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UI 架构的权力究竟属于设计师还是属于程序员？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这个问题困扰了无数团队。让我们从几个角度分析：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;角色&lt;/th&gt;
&lt;th&gt;优势&lt;/th&gt;
&lt;th&gt;劣势&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;顶尖设计师&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;具备专业视觉素养，理解设计语言，追求极致细节&lt;/td&gt;
&lt;td&gt;对技术实现边界不了解，难以落地&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;程序员&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;懂技术实现，能落地，但良莠不齐&lt;/td&gt;
&lt;td&gt;缺乏设计专业训练，视觉敏感度不足&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2.2 现实的困境
&lt;/h3&gt;

&lt;p&gt;在大多数公司，现状是：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;设计师设计稿&lt;/strong&gt; → 精心设计的颜色、间距、阴影&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;研发实现&lt;/strong&gt; → 代码实现时可能随意选择颜色、调整尺寸&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;反复 UI 走查&lt;/strong&gt; → 发现偏差，返工修改&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;再次走查&lt;/strong&gt; → 仍有偏差，继续返工&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;这是一个巨大的资源浪费循环。&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 浪费有多大？
&lt;/h3&gt;

&lt;p&gt;根据我在多个中等规模项目中的经验，常见情况是：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;单次 UI 走查&lt;/strong&gt;：往往能发现数十处视觉偏差（色值、字号、间距不一致）&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;走查轮次&lt;/strong&gt;：往往要 3–5 轮才能收敛&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;每轮修复&lt;/strong&gt;：往往占用 1–2 人天研发 + 设计师复核时间&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;叠加产品经理协调、测试回归、上线推迟，&lt;strong&gt;单个项目就会白白消耗数人天到数十人天&lt;/strong&gt;。团队项目一多，这就是持续燃烧的隐性成本。&lt;/p&gt;




&lt;h2&gt;
  
  
  三、解决方案：将定义权交还给设计师
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 架构的使命
&lt;/h3&gt;

&lt;p&gt;这套 UI 架构体系的深层使命，是&lt;strong&gt;将 UI 的定义权从程序员手中重新夺回到设计师手中&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;核心思路&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;设计语言标准化&lt;/strong&gt;：由设计总监定义完整的设计语言&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;资源文件可配置化&lt;/strong&gt;：将设计决策转化为可配置的资源文件（&lt;strong&gt;所有权在设计侧&lt;/strong&gt;）&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;代码引用规范化&lt;/strong&gt;：程序员只引用已有 token 与 Style，&lt;strong&gt;无权&lt;/strong&gt;自行定义颜色、字号、圆角档位或新增 Style 变体&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.2 设计师主导的工作流
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7kon58snere3a9xo70p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7kon58snere3a9xo70p.png" alt=" " width="795" height="75"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;具体实现&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;设计阶段&lt;/strong&gt;：设计总监定义设计语言&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;颜色体系（7大色系 × 6种职能）&lt;/li&gt;
&lt;li&gt;文字规范（字号、字重、行高）&lt;/li&gt;
&lt;li&gt;间距系统（8dp 栅格）&lt;/li&gt;
&lt;li&gt;组件规范（按钮、卡片、输入框）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;配置阶段&lt;/strong&gt;：将设计语言转化为资源文件&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;colors_primitives.xml&lt;/code&gt;：基础色定义&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;colors_theme_tokens.xml&lt;/code&gt;：主题映射&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;colors_semantic.xml&lt;/code&gt;：功能色定义&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;styles_tv.xml&lt;/code&gt;：文字样式&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;styles_button.xml&lt;/code&gt;：按钮样式&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;drawable/*&lt;/code&gt;：状态选择器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;开发阶段&lt;/strong&gt;：程序员只需引用&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;   &lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"@style/tv_black_1_size_15"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"@style/Btn.Orange.Capsule.Emphasis"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3 权力回归的意义
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;设计师主导&lt;/th&gt;
&lt;th&gt;程序员主导&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;视觉一致性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;高度一致，符合设计语言&lt;/td&gt;
&lt;td&gt;参差不齐，取决于个人水平&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;设计还原度&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% 还原设计意图&lt;/td&gt;
&lt;td&gt;60-90%，取决于专业能力&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;迭代效率&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;改资源文件即可，无需改代码&lt;/td&gt;
&lt;td&gt;需要修改大量代码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;维护成本&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;低，集中管理&lt;/td&gt;
&lt;td&gt;高，分散在各处&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  四、统一架构带来的深远影响
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 世界级的产品外观
&lt;/h3&gt;

&lt;p&gt;统一的 UI 架构带来的是&lt;strong&gt;世界级的产品外观设计和视觉一致性&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;举个例子：同样是"灰色"，细微的差异就会导致 App 的品质感天差地别：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;设计稿：gray_2 = #8A8A8A（精心调配的中性灰）
错误实现：gray = #888888（随手写的灰色）
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这 0.5% 的差异，在用户眼中就是"专业"和"山寨"的区别。&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 团队协作效率提升
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;场景对比&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;传统方式&lt;/th&gt;
&lt;th&gt;架构方式&lt;/th&gt;
&lt;th&gt;效率提升&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;新增页面&lt;/td&gt;
&lt;td&gt;手动写所有属性&lt;/td&gt;
&lt;td&gt;引用 style，一行搞定&lt;/td&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;修改主题色&lt;/td&gt;
&lt;td&gt;修改所有布局文件&lt;/td&gt;
&lt;td&gt;修改一处资源&lt;/td&gt;
&lt;td&gt;99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI 走查修复&lt;/td&gt;
&lt;td&gt;查找并修改多处&lt;/td&gt;
&lt;td&gt;资源已定义，无需修改&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4.3 品牌形象的统一
&lt;/h3&gt;

&lt;p&gt;在多端、多产品线的场景下，统一架构的价值更加凸显：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Android/iOS/Web&lt;/strong&gt;：使用相同的颜色定义&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;主 App/小程序/H5&lt;/strong&gt;：保持一致的视觉风格&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;不同版本&lt;/strong&gt;：确保品牌形象的连续性&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  五、架构落地的实践建议
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 渐进式落地策略
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdd3de9cywc3zz2tdprk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdd3de9cywc3zz2tdprk.png" alt=" " width="434" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 团队协作规范
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;设计规范先行：设计总监必须先定义设计语言&lt;/li&gt;
&lt;li&gt;资源配置同步：所有颜色/字号/Style/Drawable 变更仅由设计侧提交资源 PR&lt;/li&gt;
&lt;li&gt;代码审查把关：研发 PR 禁止硬编码颜色、尺寸，禁止新增 &lt;code&gt;func_*&lt;/code&gt; / &lt;code&gt;tv_*&lt;/code&gt; / &lt;code&gt;Btn.*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;定期审计：CI 门禁 + 设计走查，发现违规引用一律打回&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.3 工具链支持
&lt;/h3&gt;

&lt;p&gt;建议配套以下工具：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;设计稿标注工具&lt;/strong&gt;：Zeplin、Figma 插件&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;资源生成工具&lt;/strong&gt;：自动从设计稿生成资源文件&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;代码检查工具&lt;/strong&gt;：Lint 规则检查硬编码&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;预览工具&lt;/strong&gt;：实时预览主题切换效果&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  六、系列文章回顾与总结
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 四篇文章的核心贡献
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;文章&lt;/th&gt;
&lt;th&gt;核心内容&lt;/th&gt;
&lt;th&gt;解决的问题&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第一篇&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;三层颜色体系与系统化设计方案&lt;/td&gt;
&lt;td&gt;主题切换、颜色一致性、职能 token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第二篇&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Drawable 层规范与工程实践&lt;/td&gt;
&lt;td&gt;形态定义、状态管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第三篇&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Style 层如何系统性消除代码冗余&lt;/td&gt;
&lt;td&gt;消除冗余、提升复用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第四篇&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;设计主权回归与团队落地&lt;/td&gt;
&lt;td&gt;权力边界、规范强制执行&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  6.2 架构的核心原则
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;分层抽象&lt;/strong&gt;：从基础色到组件，逐层抽象&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;语义化命名&lt;/strong&gt;：让资源名表达用途，而非具体值&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;正交组合&lt;/strong&gt;：属性分离，灵活组合&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;集中管理&lt;/strong&gt;：资源集中定义，便于维护&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  6.3 最终价值
&lt;/h3&gt;

&lt;p&gt;这套架构体系带来的价值是&lt;strong&gt;系统性的&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;对用户&lt;/strong&gt;：更一致、更专业的产品体验&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;对设计师&lt;/strong&gt;：设计意图得到完整还原&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;对程序员&lt;/strong&gt;：减少重复劳动，提升开发效率&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;对公司&lt;/strong&gt;：节省大量人力成本，提升品牌形象&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  七、跨平台适用性与 AI 时代的设计交付
&lt;/h2&gt;

&lt;p&gt;需要强调的是，这套 UI 架构虽然以 Android 作为例子说明，但&lt;strong&gt;核心思想可以完全平移到 iOS、React、H5、小程序等任何平台&lt;/strong&gt;。架构的本质是"设计语言的工程化表达"，与具体实现技术无关。&lt;/p&gt;

&lt;p&gt;在 AI 大模型的帮助下，设计师可以交付完整的一套 UI 架构。这套架构是 &lt;strong&gt;AI 友好的&lt;/strong&gt;——通过合理的 Prompt、设计规范与资源清单，能够快速沉淀全平台统一的设计语言。&lt;/p&gt;

&lt;p&gt;最重要的一点：&lt;strong&gt;程序员没有权力定义颜色、样式、字号、按钮，也没有权力「扩展档位」或私自新增 token&lt;/strong&gt;。需要新色、新字号、新 Style 时，必须回到设计师维护的资源文件（本体系中的 &lt;code&gt;colors_*.xml&lt;/code&gt;、&lt;code&gt;styles_*.xml&lt;/code&gt;、&lt;code&gt;drawable/&lt;/code&gt;）由设计侧变更，再合入工程。程序员的职责只有一项：&lt;strong&gt;严格引用设计师已发布的资源&lt;/strong&gt;，确保设计意图完整落地。&lt;/p&gt;




&lt;h2&gt;
  
  
  八、规范门禁：让权力回归不只停留在纸面上
&lt;/h2&gt;

&lt;p&gt;架构写得再漂亮，若缺少&lt;strong&gt;可执行的约束&lt;/strong&gt;，仍会回到「谁写页面谁说了算」的老路。所谓门禁，并不是为难研发，而是把前文所说的&lt;strong&gt;设计主权&lt;/strong&gt;固化进团队的日常流程：该谁定的已经定好，研发只做引用与实现。&lt;/p&gt;

&lt;h3&gt;
  
  
  8.1 建议守住的四条底线
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;颜色只能来自设计 token&lt;/strong&gt;：页面里不应出现随手写的色值，也不应绕过功能色层去碰主题层、基础色。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;文字与按钮必须走设计样式&lt;/strong&gt;：字号、字色、按钮形态等，应在设计侧资源中选型，而不是在页面里临时拼凑。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;禁止重复定义已规范化的属性&lt;/strong&gt;：同一类控件的表现，应通过样式体系统一，避免「这个页面特殊、那个页面例外」。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;变更入口唯一在设计侧&lt;/strong&gt;：需要新色、新档位、新样式时，由设计师更新资源与规范，研发提需求、不自行扩库。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8.2 如何落地
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;合并前审查&lt;/strong&gt;：把 UI 资源是否符合规范，纳入 Code Review 的固定项；关键版本可由设计同学参与走查或签字。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;设计资源即唯一真相&lt;/strong&gt;：颜色、样式、Drawable 等集中由设计维护的资源包发布，业务工程只依赖已发布版本，避免各端各写一套。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;自动化作为兜底&lt;/strong&gt;：团队可按需要配置静态检查或流水线卡点，但目的始终是&lt;strong&gt;拦截越权定义&lt;/strong&gt;，而不是堆砌技术细节。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;违规即打回&lt;/strong&gt;：一旦在页面里发现临时色、临时字号、临时按钮样式，应退回并要求回到设计 token 与样式体系，而不是在评审会上「差不多就行」。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8.3 门禁真正要达成的效果
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;设计师的权威性&lt;/strong&gt;：视觉语言由设计定义，研发不再充当「第二设计师」。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;规范的刚性&lt;/strong&gt;：越权改动进不了主干，减少靠人记、靠自觉的侥幸。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;产品的一致性&lt;/strong&gt;：用户在不同页面、不同版本里，看到的是同一套品牌与品质感。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;门禁不是冷冰冰的流程，而是对前文「权力回归」的&lt;strong&gt;制度保障&lt;/strong&gt;。当设计与研发都认同这套边界，UI 走查才会从「找茬大战」变成「按图验收」。&lt;/p&gt;




&lt;h2&gt;
  
  
  九、结语
&lt;/h2&gt;

&lt;p&gt;UI 架构不是简单的"颜色配置"，而是&lt;strong&gt;设计语言的工程化落地&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;它解决的核心问题是：&lt;strong&gt;如何让设计师的专业决策能够在代码中完整、一致地体现&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;在这个过程中，程序员的角色从「视觉决策者」转变为「实现执行者」：&lt;strong&gt;颜色、字号、样式、按钮形态的定义权完全在设计侧&lt;/strong&gt;；程序员的价值体现在正确引用资源、业务逻辑与性能优化——而不是在布局里「顺手改个色」。&lt;/p&gt;

&lt;h2&gt;
  
  
  希望这套架构体系能够为你的团队带来启发，让我们一起构建更好的产品体验。
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;系列文章回顾&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo"&gt;第一篇：三层颜色体系与系统化设计方案&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-drawable-ceng-gui-fan-yu-gong-cheng-shi-jian-16km"&gt;第二篇：Drawable 层规范与工程实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-style-ceng-ru-he-xi-tong-xing-xiao-chu-dai-ma-rong-yu-4nmb"&gt;第三篇：Style 层如何系统性消除代码冗余&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第四篇：设计主权回归与团队落地（本文）&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;参考代码&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec" rel="noopener noreferrer"&gt;完整实现仓库&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 如果这套架构对你有帮助，欢迎点赞、收藏、转发。关注我，获取更多Android架构设计干货。&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>android</category>
      <category>architecture</category>
      <category>mobile</category>
      <category>ui</category>
    </item>
    <item>
      <title>Modern UI Architecture (Part 3): The Style Layer and Eliminating Redundancy</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Tue, 19 May 2026 05:16:54 +0000</pubDate>
      <link>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-style-ceng-ru-he-xi-tong-xing-xiao-chu-dai-ma-rong-yu-4nmb</link>
      <guid>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-style-ceng-ru-he-xi-tong-xing-xiao-chu-dai-ma-rong-yu-4nmb</guid>
      <description>&lt;h1&gt;
  
  
  现代化 UI 架构：Style 层如何系统性消除代码冗余
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;本文是 UI 架构系列的第三篇，建议先阅读 &lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo"&gt;第一篇：三层颜色体系与系统化设计方案&lt;/a&gt;、&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-drawable-ceng-gui-fan-yu-gong-cheng-shi-jian-16km"&gt;第二篇：Drawable 层规范与工程实践&lt;/a&gt; 了解核心设计理念。&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  前言
&lt;/h2&gt;

&lt;p&gt;在多年的 Android 开发实践中，我发现一个普遍存在的问题：&lt;strong&gt;TextView 的属性定义存在大量重复&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;打开任何一个中等规模的 Android 项目，你会发现几乎每个布局文件中都有类似这样的代码：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@color/black"&lt;/span&gt;
    &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"15sp"&lt;/span&gt;
    &lt;span class="na"&gt;android:includeFontPadding=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"商品名称"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这些属性被重复定义了成千上万次。想象一下：如果你有 500 个 TextView，有一天设计师说所有文字的字号要统一从 15sp 改成 16sp，或者要关闭字体内边距，你需要打开 500 个文件逐个修改——这简直是噩梦。&lt;/p&gt;

&lt;p&gt;我们分析了大量项目中的 TextView 使用情况，遵从 98% 的 TextView 的共性，提炼出 &lt;strong&gt;3 个&lt;/strong&gt;必须封装进 &lt;code&gt;tv_base&lt;/code&gt; 的基础属性（宽高、&lt;code&gt;includeFontPadding&lt;/code&gt;）。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Style 层的核心价值&lt;/strong&gt;：由设计师在 &lt;code&gt;styles_tv.xml&lt;/code&gt;、&lt;code&gt;styles_button.xml&lt;/code&gt; 中定义文字与按钮的&lt;strong&gt;职能化&lt;/strong&gt;样式，研发在布局里只引用 &lt;code&gt;tv_*&lt;/code&gt;、&lt;code&gt;Btn.*&lt;/code&gt;，不再自行决定 &lt;code&gt;textColor&lt;/code&gt; / &lt;code&gt;textSize&lt;/code&gt; / 按钮形态。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;职能 ≠ 业务（系列铁律）&lt;/strong&gt;：&lt;code&gt;tv_black_1_size_15&lt;/code&gt;、&lt;code&gt;Btn.Orange.Capsule.Emphasis&lt;/code&gt; 命名的是&lt;strong&gt;色系 + 文本层级 / 按钮形态 + 交互档位&lt;/strong&gt;等 UI 职能，不是「商品标题」「下单支付」等业务场景。业务只决定&lt;strong&gt;在哪个页面引用哪条职能样式&lt;/strong&gt;，不应反过来用业务名定义 Style——否则全公司都会陷入「每个页面一套按钮 Style、改主题改到崩溃」的通病。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;跨平台&lt;/strong&gt;：&lt;code&gt;tv_*&lt;/code&gt; / &lt;code&gt;Btn.*&lt;/code&gt; 对应 iOS 的 &lt;code&gt;UIFont&lt;/code&gt;+语义色组合、Web 的 typography utility class；同样应由设计系统维护，研发只引用。&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  一、工程实践中的痛点：TextView 属性冗余
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 统计数据：一个中等项目的属性重复情况
&lt;/h3&gt;

&lt;p&gt;根据我们对多个项目的分析，一个包含 100 个 Activity/Fragment 的项目：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;平均每个布局文件有 5-10 个 TextView&lt;/li&gt;
&lt;li&gt;每个 TextView 平均定义 3-5 个重复属性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;总重复次数超过 2000 次&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.2 典型的重复模式
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 模式1：每个 TextView 都重复写宽高 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 模式2：每个 TextView 都要设置 includeFontPadding --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:includeFontPadding=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:includeFontPadding=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:includeFontPadding=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 模式3：颜色和字号的组合重复 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@color/black"&lt;/span&gt; &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"15sp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@color/black"&lt;/span&gt; &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"15sp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt; &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@color/black"&lt;/span&gt; &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"15sp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.3 维护成本分析
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;无 Style&lt;/th&gt;
&lt;th&gt;有 Style&lt;/th&gt;
&lt;th&gt;节省比例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;修改默认宽高&lt;/td&gt;
&lt;td&gt;需要修改所有文件&lt;/td&gt;
&lt;td&gt;修改一处&lt;/td&gt;
&lt;td&gt;~99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;修改 includeFontPadding&lt;/td&gt;
&lt;td&gt;需要修改所有文件&lt;/td&gt;
&lt;td&gt;修改一处&lt;/td&gt;
&lt;td&gt;~99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;修改字号&lt;/td&gt;
&lt;td&gt;需要修改所有文件&lt;/td&gt;
&lt;td&gt;修改一处&lt;/td&gt;
&lt;td&gt;~99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;修改颜色主题&lt;/td&gt;
&lt;td&gt;需要修改所有文件&lt;/td&gt;
&lt;td&gt;修改一处&lt;/td&gt;
&lt;td&gt;~99%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  二、经验总结：TextView 必须的 3 个基础属性
&lt;/h2&gt;

&lt;p&gt;经过多个大型项目的实践验证，我们总结出 &lt;strong&gt;TextView 必须定义的 3 个基础属性&lt;/strong&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_base"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:layout_width"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;wrap_content&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:layout_height"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;wrap_content&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:includeFontPadding"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.1 为什么是这 3 个？
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性&lt;/th&gt;
&lt;th&gt;必要性&lt;/th&gt;
&lt;th&gt;工程经验&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;layout_width="wrap_content"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;95% 的 TextView 不需要撑满一行，需要时在布局中覆盖&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;layout_height="wrap_content"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文字高度应由内容决定，避免固定高度导致截断&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;includeFontPadding="false"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Android 默认字体有额外内边距，导致垂直居中困难&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2.2 为什么不再多定义一些？
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ 不推荐：在 base 中定义过多属性 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_base_bad"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:layout_width"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;wrap_content&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:layout_height"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;wrap_content&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:includeFontPadding"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/black&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- 不应该在这里定义 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;15sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;           &lt;span class="c"&gt;&amp;lt;!-- 不应该在这里定义 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;正交性原则&lt;/strong&gt;：颜色和字号是正交的属性，应该分开定义&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;组合灵活性&lt;/strong&gt;：不同场景需要不同的颜色+字号组合&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;单一职责&lt;/strong&gt;：base 只负责"通用基础属性"，不负责"业务属性"&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  三、正交组合：颜色 × 字号 的高效复用
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 设计思路
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frftnr5tn9x7rt7ns0d3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frftnr5tn9x7rt7ns0d3m.png" alt=" " width="552" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 色系层定义
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 黑色系（主文本） --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_base"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_black_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_2"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_base"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_black_text_2&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 灰色系（辅助文本） --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_gray_1"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_base"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_gray_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_gray_2"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_base"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_gray_text_2&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 橙色系（强调文本） --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_orange_1"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_base"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_orange_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3 字号层定义
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 黑色主文本 + 各种字号 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1_size_12"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;12sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1_size_14"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;14sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1_size_15"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;15sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1_size_16"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_black_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;16sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 灰色辅助文本 + 常用字号 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_gray_2_size_12"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_gray_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;12sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tv_gray_2_size_14"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"tv_gray_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;14sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;屏幕适配优势&lt;/strong&gt;：这种集中定义的方式还有一个重要好处——便于屏幕适配。如果有一天需要支持多尺寸屏幕，只需将硬编码的 &lt;code&gt;15sp&lt;/code&gt; 修改为 &lt;code&gt;@dimen/size_15&lt;/code&gt;，然后在不同的 dimens 文件中定义不同的值即可，整个改动只需要修改 tv style 这一个文件。&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 组合效果
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;颜色层&lt;/th&gt;
&lt;th&gt;字号层&lt;/th&gt;
&lt;th&gt;组合结果&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tv_black_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;size_15&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tv_black_1_size_15&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;商品标题、主要内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tv_black_2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;size_13&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tv_black_2_size_13&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;副标题、次要内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tv_gray_2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;size_12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tv_gray_2_size_12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;提示文字、辅助说明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tv_orange_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;size_14&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tv_orange_1_size_14&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;强调文字、按钮文字&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  四、按钮 Style：同样的思路，不同的属性
&lt;/h2&gt;

&lt;p&gt;Button Style 是「业务绑定」的重灾区。很多中大型团队的项目里，你会看到 &lt;code&gt;BtnLoginSubmit&lt;/code&gt;、&lt;code&gt;BtnOrderPay&lt;/code&gt;、&lt;code&gt;BtnMemberOpen&lt;/code&gt; 并排存在——它们往往只是胶囊主按钮的重复拷贝，圆角、字重、背景几乎一样，却&lt;strong&gt;无法复用、无法统一换肤、无法做全 App 主题&lt;/strong&gt;。这是业内极其普遍的痛点；根因同样是把 &lt;strong&gt;业务名当成了 Style 名&lt;/strong&gt;，而正确的命名只能落在 &lt;strong&gt;职能&lt;/strong&gt; 上：主操作、次操作、描边强调、小尺寸等。&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 按钮必须的基础属性
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"BaseButton"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"android:Widget.Button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;15sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;bold&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:letterSpacing"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0.02&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:gravity"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;center&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:minHeight"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;48dp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:paddingLeft"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;24dp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:paddingRight"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;24dp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 按钮属性分析
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性&lt;/th&gt;
&lt;th&gt;必要性&lt;/th&gt;
&lt;th&gt;工程经验&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;textSize=15sp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;按钮文字需要足够大，保证可点击性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;textStyle=bold&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;按钮需要视觉强调，加粗效果更好&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;letterSpacing=0.02&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;适当增加字间距提升可读性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minHeight=48dp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;符合 Material Design 规范，保证点击区域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;paddingLeft/Right=24dp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;左右内边距保证文字不贴边&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4.3 按钮的正交组合
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 胶囊按钮 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Btn.Orange.Capsule.Emphasis"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"BaseButton"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:background"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@drawable/sel_orange_interact_capsule_emphasis_default&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_white_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Btn.Gray.Capsule.Neutral"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"BaseButton"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:background"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@drawable/sel_gray_interact_capsule_neutral_default&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_black_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 小尺寸按钮 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Btn.Orange.Capsule.Small"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"BaseButton"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:minHeight"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;36dp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textSize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;13sp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:paddingLeft"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;16dp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:paddingRight"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;16dp&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:background"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@drawable/sel_orange_interact_capsule_emphasis_default&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_white_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 描边按钮 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Btn.Orange.Outline.Emphasis"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"BaseButton"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:background"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@drawable/sel_orange_interact_outline_emphasis_default&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_orange_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Btn.Orange.Capsule.Emphasis&lt;/code&gt; 表达的是&lt;strong&gt;橙色 + 胶囊形态 + 强调档位&lt;/strong&gt;，与 Drawable &lt;code&gt;sel_orange_interact_capsule_emphasis_default&lt;/code&gt; 同序（色系在前）；登录页、收银台、活动页主按钮都可引用，&lt;strong&gt;不要把业务写进 Style 名&lt;/strong&gt;。&lt;/p&gt;

&lt;h3&gt;
  
  
  4.4 反例：业务型 Button Style 如何毁掉复用
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ 错误：Style 名承载业务
Btn.Login.Submit
Btn.Order.ConfirmPay
Btn.Profile.EditSave
Btn.Cart.CheckoutNow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;看似清晰，实则每个业务线各维护一套「主按钮」，设计改一版主色或圆角，要改几十个 Style、走查几十个页面。正确做法是收敛到 &lt;code&gt;Btn.Orange.Capsule.Emphasis&lt;/code&gt;、&lt;code&gt;Btn.Gray.Capsule.Neutral&lt;/code&gt;、&lt;code&gt;Btn.Orange.Outline.Emphasis&lt;/code&gt; 等&lt;strong&gt;职能命名&lt;/strong&gt;（&lt;strong&gt;色系在形状之前&lt;/strong&gt;），与 Drawable &lt;code&gt;sel_orange_interact_capsule_emphasis_default&lt;/code&gt; 字段顺序一致。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;业务命名&lt;/th&gt;
&lt;th&gt;职能命名&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;回答的问题&lt;/td&gt;
&lt;td&gt;这是哪个页面的按钮？&lt;/td&gt;
&lt;td&gt;这是什么形态、什么强调级别的按钮？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;能否跨页面复用&lt;/td&gt;
&lt;td&gt;❌ 基本不能&lt;/td&gt;
&lt;td&gt;✅ 全 App 复用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主题/品牌升级&lt;/td&gt;
&lt;td&gt;改多处、易遗漏&lt;/td&gt;
&lt;td&gt;改 Style + token 即可&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;典型名称&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BtnOrderPay&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Btn.Orange.Capsule.Emphasis&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  五、复用效果对比
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 改造前：每个 TextView 都要写完整属性
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 改造前：每个都要写 4-5 行 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:includeFontPadding=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
    &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_black_text_1"&lt;/span&gt;
    &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"15sp"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"商品名称"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:includeFontPadding=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
    &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_gray_text_2"&lt;/span&gt;
    &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"12sp"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"库存紧张"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:includeFontPadding=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
    &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_red_text_1"&lt;/span&gt;
    &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"14sp"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"¥299"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.2 改造后：一行解决
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 改造后：只需引用 style --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"@style/tv_black_1_size_15"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"商品名称"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"@style/tv_gray_2_size_12"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"库存紧张"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"@style/tv_red_1_size_14"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"¥299"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.3 量化对比
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指标&lt;/th&gt;
&lt;th&gt;改造前&lt;/th&gt;
&lt;th&gt;改造后&lt;/th&gt;
&lt;th&gt;节省比例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;代码行数（3个TextView）&lt;/td&gt;
&lt;td&gt;15 行&lt;/td&gt;
&lt;td&gt;6 行&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;属性定义次数&lt;/td&gt;
&lt;td&gt;12 次&lt;/td&gt;
&lt;td&gt;0 次&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;维护点&lt;/td&gt;
&lt;td&gt;每个 TextView&lt;/td&gt;
&lt;td&gt;1 个 Style 文件&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  六、命名规范：让复用更直观
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 文字 Style 命名
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tv_{色系}_{档位}_size_{字号}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tv_black_1_size_15&lt;/code&gt;：黑色主文本，15sp&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tv_gray_2_size_12&lt;/code&gt;：灰色辅助文本，12sp&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tv_orange_1_size_14&lt;/code&gt;：橙色强调文本，14sp&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6.2 按钮 Style 命名
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Btn.{色系}.{形状}.{交互档位}[.Small]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;（与 Drawable &lt;code&gt;sel_{色系}_…&lt;/code&gt; 一致，&lt;strong&gt;色系紧挨 Btn 前缀&lt;/strong&gt;）：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Btn.Orange.Capsule.Emphasis&lt;/code&gt;：橙色胶囊强调按钮&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Btn.Gray.Capsule.Neutral&lt;/code&gt;：灰色胶囊中性按钮&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Btn.Orange.Outline.Emphasis&lt;/code&gt;：橙色描边强调按钮&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Btn.Orange.Capsule.Small&lt;/code&gt;：橙色胶囊小尺寸&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6.3 命名原则
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;职能语义，而非业务语义&lt;/strong&gt;：&lt;code&gt;Orange&lt;/code&gt; / &lt;code&gt;Emphasis&lt;/code&gt; / &lt;code&gt;black_1&lt;/code&gt; 描述的是色系与 UI 档位，不是订单、登录、会员等业务模块&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;层次清晰&lt;/strong&gt;：&lt;code&gt;tv_{色系}_{档位}&lt;/code&gt;；&lt;code&gt;Btn_{色系}_{形状}_{档位}&lt;/code&gt;，色系位置与颜色层、Drawable 层对齐&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;易于搜索&lt;/strong&gt;：统一前缀便于 IDE 搜索；全团队共用同一套职能 Style，而不是每人发明业务名&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  七、与颜色体系的集成
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 完整数据流
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvu9ebzg792yz6n8jcez2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvu9ebzg792yz6n8jcez2.png" alt=" " width="771" height="1020"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7.2 主题切换支持
&lt;/h3&gt;

&lt;p&gt;由于 Style 通过 &lt;code&gt;@color/func_*&lt;/code&gt; 引用功能色，而功能色又通过 &lt;code&gt;@color/t_*&lt;/code&gt; 引用主题色，所以：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;日间&lt;/strong&gt;：&lt;code&gt;tv_black_1_size_15&lt;/code&gt; → &lt;code&gt;func_black_text_1&lt;/code&gt; → &lt;code&gt;t_black_8&lt;/code&gt; → &lt;code&gt;black_8&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;夜间&lt;/strong&gt;：&lt;code&gt;tv_black_1_size_15&lt;/code&gt; → &lt;code&gt;func_black_text_1&lt;/code&gt; → &lt;code&gt;t_black_8&lt;/code&gt; → &lt;code&gt;white_1&lt;/code&gt;（由 &lt;code&gt;values-night&lt;/code&gt; 中 &lt;code&gt;t_*&lt;/code&gt; 映射决定）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;无需修改任何 Style，自动适配主题&lt;/strong&gt;。&lt;/p&gt;




&lt;h2&gt;
  
  
  八、实际项目中的最佳实践
&lt;/h2&gt;

&lt;h3&gt;
  
  
  8.1 渐进式改造
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24fy58zd6cbxsho6sigt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24fy58zd6cbxsho6sigt.png" alt=" " width="541" height="1052"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8.2 团队协作规范
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;所有新增 TextView 必须使用设计师定义的 &lt;code&gt;tv_*&lt;/code&gt; Style&lt;/li&gt;
&lt;li&gt;禁止在布局中直接定义 &lt;code&gt;textColor&lt;/code&gt;、&lt;code&gt;textSize&lt;/code&gt;、&lt;code&gt;includeFontPadding&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;需要新的颜色+字号组合时，由设计师在 &lt;code&gt;styles_tv.xml&lt;/code&gt; 中新增，研发提需求、不自行加 token&lt;/li&gt;
&lt;li&gt;定期审查，清理直接定义属性的代码&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8.3 扩展原则
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;做法&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;需要新字号&lt;/td&gt;
&lt;td&gt;设计师在对应色系下添加（如 &lt;code&gt;tv_black_1_size_17&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;需要新色系&lt;/td&gt;
&lt;td&gt;设计师先补功能色，再添加 &lt;code&gt;tv_purple_1&lt;/code&gt; 及字号组合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;需要特殊效果&lt;/td&gt;
&lt;td&gt;优先在设计规范中沉淀；确属个例时可在布局用 &lt;code&gt;textStyle&lt;/code&gt; 等覆盖&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  九、总结
&lt;/h2&gt;

&lt;p&gt;Style 层不是简单的"属性集合"，而是&lt;strong&gt;工程经验的沉淀和复用&lt;/strong&gt;。&lt;/p&gt;

&lt;h3&gt;
  
  
  核心价值
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;消除冗余&lt;/strong&gt;：将重复属性抽取到 Style 中，写一次用无数次&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;统一标准&lt;/strong&gt;：通过 tv_base 确保所有 TextView 有一致的基础行为&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;降低维护成本&lt;/strong&gt;：修改一处，全局生效&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;支持主题切换&lt;/strong&gt;：与颜色体系无缝集成&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  关键设计原则
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;职能 ≠ 业务&lt;/strong&gt;：Style 只命名 UI 职能；业务场景只选择引用哪条 Style&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;最小化基础层&lt;/strong&gt;：tv_base 只定义 3 个必须属性&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;正交组合&lt;/strong&gt;：颜色和字号分开定义，灵活组合&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;按钮同样职能化&lt;/strong&gt;：&lt;code&gt;Btn.Orange.Capsule.Emphasis&lt;/code&gt; 等全 App 复用，禁止 &lt;code&gt;BtnXxxBusiness&lt;/code&gt; 式命名&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  预期收益
&lt;/h3&gt;

&lt;p&gt;根据我们的实践经验，引入 Style 层后：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;代码量减少 30-50%&lt;/strong&gt;（布局文件）&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;维护时间减少 80%&lt;/strong&gt;（属性修改）&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;视觉一致性提升&lt;/strong&gt;（避免手动书写错误）&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;参考代码（与本文配套的实现仓库一致）&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values/styles_tv.xml" rel="noopener noreferrer"&gt;文字样式定义&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values/styles_button.xml" rel="noopener noreferrer"&gt;按钮样式定义&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/tree/main/app/src/main/res/values" rel="noopener noreferrer"&gt;颜色资源&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 如果你觉得这篇文章对你有帮助，欢迎点赞、收藏、转发。关注我，获取更多Android架构设计干货。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;系列文章&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo"&gt;第一篇：三层颜色体系与系统化设计方案&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-drawable-ceng-gui-fan-yu-gong-cheng-shi-jian-16km"&gt;第二篇：Drawable 层规范与工程实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;第三篇：Style 层如何系统性消除代码冗余&lt;/strong&gt;（本文）&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-zong-jie-she-ji-zhu-quan-hui-gui-yu-tuan-dui-luo-di-5h5j"&gt;第四篇：设计主权回归与团队落地&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>mobile</category>
      <category>ui</category>
    </item>
    <item>
      <title>Modern UI Architecture (Part 2): Drawable Layer Conventions</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Tue, 19 May 2026 05:14:02 +0000</pubDate>
      <link>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-drawable-ceng-gui-fan-yu-gong-cheng-shi-jian-16km</link>
      <guid>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-drawable-ceng-gui-fan-yu-gong-cheng-shi-jian-16km</guid>
      <description>&lt;h1&gt;
  
  
  现代化 UI 架构：Drawable 层规范与工程实践
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;本文是 UI 架构系列的第二篇，建议先阅读 &lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo"&gt;第一篇：三层颜色体系与系统化设计方案&lt;/a&gt; 了解核心设计理念。&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  前言
&lt;/h2&gt;

&lt;p&gt;在上一篇文章中，我们建立了一套完整的颜色体系。但颜色只是 UI 的基础，真正让 UI 活起来的是&lt;strong&gt;形态和交互&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;一个按钮不仅需要颜色，还需要：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;圆角、描边、阴影&lt;/li&gt;
&lt;li&gt;按下、禁用、选中的状态变化&lt;/li&gt;
&lt;li&gt;渐变、透明等视觉效果&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这些都需要通过 Drawable 来实现。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;贯穿 UI 架构层的一条铁律&lt;/strong&gt;：颜色、Drawable、Style 等所有资源定义，&lt;strong&gt;都不要和业务挂钩&lt;/strong&gt;；命名表达的是 &lt;strong&gt;UI 职能&lt;/strong&gt;，&lt;strong&gt;职能 ≠ 业务&lt;/strong&gt;。一旦用「登录页按钮」「订单失败红框」这类业务语义去命名或拆分资源，就等于把形态和颜色锁死在某个页面——&lt;strong&gt;可复用性会被立刻破坏&lt;/strong&gt;。Drawable 层只描述形态、色系、交互状态与档位，业务含义由使用它的页面自己承担。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;跨平台&lt;/strong&gt;：Android 的 Drawable/selector 对应 iOS 的 Asset Catalog 状态图、Web 的 design-token + CSS 状态类；命名与分层思想一致。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;本文要点&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;为什么需要 Drawable 层规范&lt;/li&gt;
&lt;li&gt;Drawable 层的三层架构设计&lt;/li&gt;
&lt;li&gt;统一的命名规范&lt;/li&gt;
&lt;li&gt;形态层和组件层的设计要点&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  一、为什么需要 Drawable 层规范？
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 反例：混乱的 Drawable 管理
&lt;/h3&gt;

&lt;p&gt;在我接触过的项目中，经常会看到这样的 Drawable 定义：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- btn_primary.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;shape&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"#FF4B00"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"24dp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- btn_primary_pressed.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;shape&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"#CC3D00"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"24dp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- btn_disabled.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;shape&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"#CCCCCC"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"24dp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.2 问题分析
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题类型&lt;/th&gt;
&lt;th&gt;具体表现&lt;/th&gt;
&lt;th&gt;影响&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;重复定义&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;每个状态都要单独定义一个文件&lt;/td&gt;
&lt;td&gt;维护成本高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;颜色硬编码&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;直接写色值，无法跟随主题切换&lt;/td&gt;
&lt;td&gt;主题适配困难&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;命名混乱&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;btn_primary&lt;/code&gt;、&lt;code&gt;button_normal&lt;/code&gt; 等命名不统一&lt;/td&gt;
&lt;td&gt;新人难以选择&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;难以维护&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;改一个圆角需要修改所有文件&lt;/td&gt;
&lt;td&gt;修改成本高&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1.3 根本原因
&lt;/h3&gt;

&lt;p&gt;这些问题的本质在于：&lt;strong&gt;形态定义与颜色、状态过度耦合&lt;/strong&gt;。当一个 Drawable 文件同时承载了形状、颜色和状态逻辑时，任何改动都会变得非常困难。&lt;/p&gt;




&lt;h2&gt;
  
  
  二、Drawable 层的三层架构
&lt;/h2&gt;

&lt;p&gt;借鉴颜色体系的设计思路，我们同样采用&lt;strong&gt;三层架构&lt;/strong&gt;来管理 Drawable：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3g1edlcs8oezknilaaau.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3g1edlcs8oezknilaaau.png" alt=" " width="702" height="1792"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 核心原则
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层级&lt;/th&gt;
&lt;th&gt;职责&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;组件层&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;组合状态和形态&lt;/td&gt;
&lt;td&gt;通过 selector 引用 bg_*，实现状态切换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;形态层&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;定义圆角、描边、填充结构&lt;/td&gt;
&lt;td&gt;颜色只引用 &lt;code&gt;func_*&lt;/code&gt;，禁止硬编码色值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;颜色层&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;提供颜色 token&lt;/td&gt;
&lt;td&gt;设计师维护的功能色，支持主题切换&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;与业务解耦&lt;/strong&gt;：三层都只表达「UI 语言」，不表达「业务故事」。&lt;code&gt;sel_orange_interact_capsule_emphasis_default&lt;/code&gt; 可以在下单主按钮、会员开通按钮、活动页主按钮上复用；若做成 &lt;code&gt;sel_order_submit_primary&lt;/code&gt;，换页面就要复制一套 Drawable，主题与形态也无法在全 App 统一维护。&lt;/p&gt;




&lt;h2&gt;
  
  
  三、命名规范：让每个文件都有明确的含义
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 命名公式
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{类型}_{色系}_{用途}_{状态}_{档位}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 组成说明
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;组成部分&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;允许值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;类型&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Drawable 类别&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;bg&lt;/code&gt;（背景）、&lt;code&gt;sel&lt;/code&gt;（选择器）、&lt;code&gt;ic&lt;/code&gt;（图标）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;颜色分类&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gray&lt;/code&gt;、&lt;code&gt;orange&lt;/code&gt;、&lt;code&gt;red&lt;/code&gt;、&lt;code&gt;blue&lt;/code&gt;、&lt;code&gt;green&lt;/code&gt;、&lt;code&gt;black&lt;/code&gt;、&lt;code&gt;white&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;使用场景&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;surface&lt;/code&gt;、&lt;code&gt;fill&lt;/code&gt;、&lt;code&gt;stroke&lt;/code&gt;、&lt;code&gt;field&lt;/code&gt;、&lt;code&gt;interact&lt;/code&gt;、&lt;code&gt;gradient&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;状态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;交互状态&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;idle&lt;/code&gt;、&lt;code&gt;alert&lt;/code&gt;、&lt;code&gt;hint&lt;/code&gt;、&lt;code&gt;emphasis&lt;/code&gt;、&lt;code&gt;neutral&lt;/code&gt;、&lt;code&gt;default&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;档位&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;优先级&lt;/td&gt;
&lt;td&gt;数字 &lt;code&gt;1&lt;/code&gt;（主要）、&lt;code&gt;2&lt;/code&gt;（次要）、&lt;code&gt;3&lt;/code&gt;（第三）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  3.3 命名示例
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;bg_orange_fill_interact_1&lt;/span&gt;    &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;橙色交互填充背景，主档位&lt;/span&gt;
&lt;span class="err"&gt;bg_gray_surface_card_1&lt;/span&gt;       &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;灰色卡片表面背景&lt;/span&gt;
&lt;span class="err"&gt;sel_orange_interact_outline_emphasis_default&lt;/span&gt;  &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;橙色描边交互选择器&lt;/span&gt;
&lt;span class="err"&gt;bg_black_fill_scrim_1&lt;/span&gt;        &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;黑色遮罩填充&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.4 反例：业务绑定如何毁掉复用
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ 错误：文件名承载业务，无法跨场景复用
bg_login_page_primary_btn.xml
bg_order_detail_pay_btn.xml
sel_profile_avatar_upload_error.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;三个文件往往只是圆角、色值、状态略有相似，却无法合并维护。正确做法是共用 &lt;code&gt;sel_orange_interact_capsule_emphasis_default&lt;/code&gt; 等&lt;strong&gt;职能 + 形态&lt;/strong&gt;命名，由不同页面的布局或 Style 决定用在哪里。&lt;/p&gt;




&lt;h2&gt;
  
  
  四、形态层设计：结构 + 功能色引用
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 基础形状类型
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;形状&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;fill&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;实心填充&lt;/td&gt;
&lt;td&gt;按钮背景、卡片背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;stroke&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;描边空心&lt;/td&gt;
&lt;td&gt;输入框边框、幽灵按钮&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;flat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;扁平透明&lt;/td&gt;
&lt;td&gt;文字按钮、点击区域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;gradient&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;渐变效果&lt;/td&gt;
&lt;td&gt;渐变背景、光晕效果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;surface&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;表面效果&lt;/td&gt;
&lt;td&gt;卡片、浮层、阴影&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4.2 形状定义规范
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- bg_orange_fill_interact_1.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;shape&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;android:shape=&lt;/span&gt;&lt;span class="s"&gt;"rectangle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_orange_bg_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"@dimen/draw_corner_capsule"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- bg_orange_stroke_interact_1.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;shape&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;android:shape=&lt;/span&gt;&lt;span class="s"&gt;"rectangle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_clear_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- 透明填充 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;stroke&lt;/span&gt; 
        &lt;span class="na"&gt;android:width=&lt;/span&gt;&lt;span class="s"&gt;"@dimen/draw_stroke_reg"&lt;/span&gt; 
        &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_orange_border_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"@dimen/draw_corner_capsule"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;关键设计点&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;@dimen&lt;/code&gt; 引用尺寸（由设计师在 dimens 中定义），避免硬编码&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;@color/func_*&lt;/code&gt; 引用功能色，支持主题切换；&lt;strong&gt;禁止&lt;/strong&gt;在 drawable 中写 &lt;code&gt;#RRGGBB&lt;/code&gt; 或直接引用 &lt;code&gt;t_*&lt;/code&gt;、基础色&lt;/li&gt;
&lt;li&gt;同一套圆角/描边结构可搭配不同色系的功能色，由设计师在 token 层切换映射&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  五、状态色设计：状态逻辑放在 Drawable 层
&lt;/h2&gt;

&lt;p&gt;在设计这套体系时，我们曾讨论过是否需要添加「禁用态」「选中态」「按下态」等状态相关的颜色到颜色层。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;结论：状态色应该放在 drawable 层&lt;/strong&gt;，而不是颜色层。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;状态类型&lt;/th&gt;
&lt;th&gt;建议位置&lt;/th&gt;
&lt;th&gt;原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;禁用态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;drawable层&lt;/td&gt;
&lt;td&gt;通过selector组合实现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;选中态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;drawable层&lt;/td&gt;
&lt;td&gt;通过selector组合实现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;按下态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;drawable层&lt;/td&gt;
&lt;td&gt;通过selector组合实现&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  5.1 为什么不在颜色层定义状态色？
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;职责分离&lt;/strong&gt;：颜色层负责提供「原料」，drawable层负责组合「成品」&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;灵活性&lt;/strong&gt;：同一个颜色可以在不同状态下有不同表现&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;可复用性&lt;/strong&gt;：一套颜色可以组合出多种状态效果&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.2 状态效果的正确实现方式
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- drawable/sel_orange_interact_capsule_emphasis_default.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;selector&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- 禁用态 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;android:state_enabled=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;shape&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_black_bg_2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- 禁用态用灰色背景 --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"24dp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- 按下态 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;android:state_pressed=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;shape&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_orange_bg_2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- 按下态用浅色 --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"24dp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- 常态 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;shape&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_orange_bg_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- 常态用主色 --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;corners&lt;/span&gt; &lt;span class="na"&gt;android:radius=&lt;/span&gt;&lt;span class="s"&gt;"24dp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/selector&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  六、组件层设计：状态组合
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 Selector 的规范写法
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- sel_orange_interact_capsule_emphasis_default.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;selector&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- 禁用态 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; 
        &lt;span class="na"&gt;android:drawable=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/bg_gray_fill_interact_2"&lt;/span&gt; 
        &lt;span class="na"&gt;android:state_enabled=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- 按下态 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; 
        &lt;span class="na"&gt;android:drawable=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/bg_orange_fill_interact_2"&lt;/span&gt; 
        &lt;span class="na"&gt;android:state_pressed=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- 常态 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;android:drawable=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/bg_orange_fill_interact_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/selector&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 状态优先级
&lt;/h3&gt;

&lt;p&gt;Selector 中状态判断优先级（&lt;strong&gt;高 → 低&lt;/strong&gt;）：&lt;strong&gt;禁用态&lt;/strong&gt; &amp;gt; &lt;strong&gt;选中态&lt;/strong&gt; &amp;gt; &lt;strong&gt;按下态&lt;/strong&gt; &amp;gt; &lt;strong&gt;焦点态&lt;/strong&gt; &amp;gt; &lt;strong&gt;常态&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6.3 输入框状态示例
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- sel_gray_field_rect_idle_default.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;selector&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; 
        &lt;span class="na"&gt;android:drawable=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/bg_gray_field_rect_2"&lt;/span&gt; 
        &lt;span class="na"&gt;android:state_enabled=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; 
        &lt;span class="na"&gt;android:drawable=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/bg_blue_field_rect_1"&lt;/span&gt; 
        &lt;span class="na"&gt;android:state_focused=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;android:drawable=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/bg_gray_field_rect_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/selector&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  七、常用组件的 Drawable 实现
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 按钮组件
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;按钮类型&lt;/th&gt;
&lt;th&gt;Drawable 配置&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;主按钮&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sel_orange_interact_capsule_emphasis_default&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;次按钮&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sel_gray_interact_capsule_neutral_default&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;文字按钮&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sel_gray_interact_flat_neutral_default&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;幽灵按钮&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sel_orange_interact_outline_emphasis_default&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  7.2 输入框组件
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;th&gt;Drawable 配置&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;常态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sel_gray_field_rect_idle_default&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;警告态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sel_yellow_field_rect_hint_static&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;错误态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sel_red_field_rect_alert_static&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  7.3 卡片组件
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;卡片类型&lt;/th&gt;
&lt;th&gt;Drawable 配置&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;普通卡片&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bg_gray_surface_card_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;浮层卡片&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bg_gray_surface_float_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;面板卡片&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bg_gray_surface_panel_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  八、尺寸管理：统一的 Dimen 规范
&lt;/h2&gt;

&lt;h3&gt;
  
  
  8.1 圆角尺寸
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- dimens_drawable.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_corner_none"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_corner_sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;4dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_corner_reg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;8dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_corner_lg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;12dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_corner_capsule"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;999dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- 胶囊形 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8.2 描边尺寸
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_stroke_thin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0.5dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_stroke_reg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_stroke_thick"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8.3 阴影尺寸
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_shadow_elevation_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_shadow_elevation_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;4dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dimen&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"draw_shadow_elevation_3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;8dp&lt;span class="nt"&gt;&amp;lt;/dimen&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  九、与颜色体系的集成
&lt;/h2&gt;

&lt;h3&gt;
  
  
  9.1 颜色引用规范
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ✅ 正确：引用功能色层 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_orange_bg_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;stroke&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/func_orange_border_1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ❌ 错误：直接引用主题色或基础色 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/t_orange_4"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- 不推荐 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@color/orange_4"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 禁止 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.2 夜间模式自动适配
&lt;/h3&gt;

&lt;p&gt;得益于三层颜色架构，Drawable 层&lt;strong&gt;无需任何修改&lt;/strong&gt;即可支持夜间模式：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;日间模式：
func_orange_bg_1 → t_orange_4 → orange_4 (#FF4B00)

夜间模式：
func_orange_bg_1 → t_orange_4 → orange_3b (#FF8833)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  十、与 View 的集成方式
&lt;/h2&gt;

&lt;h3&gt;
  
  
  10.1 通过 Style 引用
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- styles_button.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Btn.Orange.Capsule.Emphasis"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"BaseButton"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:background"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@drawable/sel_orange_interact_capsule_emphasis_default&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:textColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/func_white_text_1&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10.2 在布局中直接使用
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
    &lt;span class="na"&gt;android:background=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/sel_orange_interact_capsule_emphasis_default"&lt;/span&gt;
    &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"主操作"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  十一、完整架构总结
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlezn5jgqrx6qum4dtj0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlezn5jgqrx6qum4dtj0.png" alt=" " width="552" height="1308"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  十二、总结
&lt;/h2&gt;

&lt;p&gt;Drawable 层是连接颜色和 UI 组件的桥梁，它的设计直接影响到：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI 的一致性和美观度&lt;/li&gt;
&lt;li&gt;代码的可维护性&lt;/li&gt;
&lt;li&gt;主题切换的灵活性&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;通过遵循以下原则，你可以构建一套优秀的 Drawable 体系：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;与业务解耦&lt;/strong&gt;：Drawable 只表达形态与交互语义，绝不使用页面名、流程名、业务事件名&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;分离关注点&lt;/strong&gt;：形态结构与填色引用分离，状态组合与组件分离&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;统一命名规范&lt;/strong&gt;：&lt;code&gt;{类型}_{色系}_{用途}_{状态}_{档位}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;复用优先&lt;/strong&gt;：避免重复定义，提高资源利用率&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;与颜色体系集成&lt;/strong&gt;：只引用设计师定义的 &lt;code&gt;func_*&lt;/code&gt;，支持主题切换&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;参考代码&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/tree/main/app/src/main/res/drawable" rel="noopener noreferrer"&gt;Drawable 资源目录&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values/styles_button.xml" rel="noopener noreferrer"&gt;样式定义&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values/dimens_drawable.xml" rel="noopener noreferrer"&gt;尺寸定义&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 如果你觉得这篇文章对你有帮助，欢迎点赞、收藏、转发。关注我，获取更多 Android 架构设计干货。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;系列文章&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo"&gt;第一篇：三层颜色体系与系统化设计方案&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;第二篇：Drawable 层规范与工程实践&lt;/strong&gt;（本文）&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-style-ceng-ru-he-xi-tong-xing-xiao-chu-dai-ma-rong-yu-4nmb"&gt;第三篇：Style 层如何系统性消除代码冗余&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-zong-jie-she-ji-zhu-quan-hui-gui-yu-tuan-dui-luo-di-5h5j"&gt;第四篇：设计主权回归与团队落地&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>mobile</category>
      <category>ui</category>
    </item>
    <item>
      <title>Modern UI Architecture (Part 1): Three-Layer Color System</title>
      <dc:creator>goodlords</dc:creator>
      <pubDate>Tue, 19 May 2026 05:11:02 +0000</pubDate>
      <link>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo</link>
      <guid>https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-san-ceng-yan-se-ti-xi-yu-xi-tong-hua-she-ji-fang-an-5ebo</guid>
      <description>&lt;h1&gt;
  
  
  现代化 UI 架构：三层颜色体系与系统化设计方案
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;UI 架构系列&lt;/strong&gt; 的第一篇，将深入探讨颜色层的设计。后续文章将依次介绍：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-drawable-ceng-gui-fan-yu-gong-cheng-shi-jian-16km"&gt;第二篇：Drawable 层规范与工程实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-style-ceng-ru-he-xi-tong-xing-xiao-chu-dai-ma-rong-yu-4nmb"&gt;第三篇：Style 层如何系统性消除代码冗余&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zealot2002/xian-dai-hua-ui-jia-gou-zong-jie-she-ji-zhu-quan-hui-gui-yu-tuan-dui-luo-di-5h5j"&gt;第四篇：设计主权回归与团队落地&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;注&lt;/strong&gt;：本文以 Android 为例进行说明，但核心思想完全适用于 iOS、React、H5、小程序等任何平台。&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  前言
&lt;/h2&gt;

&lt;p&gt;在多年的跨平台 App 开发实践中，我发现 UI 资源管理是困扰许多团队的共性问题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;颜色定义混乱，同一个色值重复定义几十次&lt;/li&gt;
&lt;li&gt;组件形态与颜色过度耦合，难以复用&lt;/li&gt;
&lt;li&gt;样式属性重复书写，维护成本极高&lt;/li&gt;
&lt;li&gt;主题切换困难，夜间模式适配工作量巨大&lt;/li&gt;
&lt;li&gt;新同事需要花费大量时间理解混乱的颜色命名&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果你也被这些问题困扰，这个系列或许值得一读——主要面向设计总监、设计师、研发总监与前端工程师。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;本文要点&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;三层颜色架构的设计理念和核心原则&lt;/li&gt;
&lt;li&gt;每一层的具体设计规范和代码实现&lt;/li&gt;
&lt;li&gt;如何实现日间/夜间模式的无缝切换&lt;/li&gt;
&lt;li&gt;架构的适用场景和扩展方向&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  架构全景
&lt;/h3&gt;

&lt;p&gt;本系列介绍的是一套完整的 &lt;strong&gt;UI 架构体系&lt;/strong&gt;，其中&lt;strong&gt;三层颜色架构&lt;/strong&gt;是核心基础：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32fvzgx9cmo1sf8by6aq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32fvzgx9cmo1sf8by6aq.png" alt=" " width="702" height="1836"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;箭头表示引用/依赖方向：应用层引用 func_&lt;/em&gt;；func_* 引用 t_&lt;em&gt;；t_&lt;/em&gt; 引用基础色。定义权在设计侧，自下而上配置。*&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;颜色层依赖关系&lt;/strong&gt;：&lt;code&gt;func_*&lt;/code&gt; → &lt;code&gt;t_*&lt;/code&gt; → 基础色（严格单向依赖）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;本文聚焦于三层颜色架构的完整设计&lt;/strong&gt;，后续文章将介绍上层应用层如何基于颜色层构建。&lt;/p&gt;




&lt;h2&gt;
  
  
  一、传统颜色管理的核心痛点
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 真实项目中的反例
&lt;/h3&gt;

&lt;p&gt;在我接触过的多个项目中，经常会看到类似这样的颜色定义：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 从真实项目中截取的颜色定义 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"bg_login"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#FFFFFF&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;      &lt;span class="c"&gt;&amp;lt;!-- 登录页背景 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"bg_home"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#F5F5F5&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;      &lt;span class="c"&gt;&amp;lt;!-- 首页背景 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"bg_profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#FFFFFF&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 个人中心背景 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text_title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#141414&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;&amp;lt;!-- 标题文字 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text_desc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#808080&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 描述文字 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text_hint"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#BFBFBF&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 提示文字 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"button_red"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#DB121F&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;&amp;lt;!-- 红色按钮 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"red_button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#DB121F&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;&amp;lt;!-- 另一个红色按钮 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.2 问题分析
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题类型&lt;/th&gt;
&lt;th&gt;具体表现&lt;/th&gt;
&lt;th&gt;影响&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;重复定义&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;#FFFFFF&lt;/code&gt; 和 &lt;code&gt;#DB121F&lt;/code&gt; 多次出现&lt;/td&gt;
&lt;td&gt;改一处需改所有地方，容易遗漏&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;业务绑定&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;bg_login&lt;/code&gt;、&lt;code&gt;bg_home&lt;/code&gt; 与具体页面绑定&lt;/td&gt;
&lt;td&gt;无法复用，扩展性差&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;命名混乱&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;button_red&lt;/code&gt; 和 &lt;code&gt;red_button&lt;/code&gt; 同时存在&lt;/td&gt;
&lt;td&gt;新人难以选择，团队协作困难&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;夜间模式灾难&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;需复制所有颜色到 &lt;code&gt;values-night&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;工作量巨大，容易出错&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1.3 根本原因
&lt;/h3&gt;

&lt;p&gt;这些问题的本质在于：&lt;strong&gt;颜色定义与业务语义、主题逻辑过度耦合&lt;/strong&gt;。当一个颜色既承载了"背景"的业务含义，又承载了"白色"的具体色值时，任何改动都会牵一发而动全身。&lt;/p&gt;




&lt;h2&gt;
  
  
  二、三层颜色架构设计理念
&lt;/h2&gt;

&lt;p&gt;针对这些问题，我设计了一套&lt;strong&gt;严格单向依赖&lt;/strong&gt;的三层颜色架构：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5h9w6q2bsymy5rv8xud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5h9w6q2bsymy5rv8xud.png" alt=" " width="670" height="1094"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 架构核心原则
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层级&lt;/th&gt;
&lt;th&gt;唯一职责&lt;/th&gt;
&lt;th&gt;命名规则&lt;/th&gt;
&lt;th&gt;是否承载业务语义&lt;/th&gt;
&lt;th&gt;修改频率&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;基础色层&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;定义原始色值&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;色系_数字&lt;/code&gt;（如 &lt;code&gt;white_1&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;❌ 否&lt;/td&gt;
&lt;td&gt;极低（品牌升级时才改）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;主题层&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;日间/夜间模式映射&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;t_色系_数字&lt;/code&gt;（如 &lt;code&gt;t_white_1&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;❌ 否&lt;/td&gt;
&lt;td&gt;低（新增主题时才改）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;功能色层&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UI 职能封装（文本、背景、边框等）&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_{色系}_{职能}_{档位}&lt;/code&gt;（如 &lt;code&gt;func_black_text_1&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;❌ 否&lt;/td&gt;
&lt;td&gt;由设计师维护（新增档位/职能时改）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;重要说明&lt;/strong&gt;：功能色层封装的是 &lt;strong&gt;UI 职能&lt;/strong&gt;（如文本、背景、边框），而非具体业务场景。&lt;code&gt;func_black_text_1&lt;/code&gt; 代表黑色系主档文本色，可用于商品标题、页面标题、按钮文字等任何场景，不绑定具体业务。&lt;strong&gt;功能色的定义权归属设计师&lt;/strong&gt;，研发只引用、不新增。&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 严格单向依赖规则
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jcjuf74mi64l8q8oiob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jcjuf74mi64l8q8oiob.png" alt=" " width="798" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;为什么必须严格遵守单向依赖？&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;避免循环依赖导致的颜色定义混乱&lt;/li&gt;
&lt;li&gt;每层只做自己的事，职责清晰，便于定位问题&lt;/li&gt;
&lt;li&gt;改一处全局生效，维护成本极低&lt;/li&gt;
&lt;li&gt;多人开发不会互相冲突&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  三、分层详解：每一层该怎么设计
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 第一层：全局基础色层
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;定位&lt;/strong&gt;：纯原始色值定义，不做任何主题绑定和业务关联&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;命名规则&lt;/strong&gt;：&lt;code&gt;色系_数字&lt;/code&gt; 下划线格式，数字按明度/饱和度递增&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;设计原则&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;白色系：数字越小越浅（&lt;code&gt;white_1&lt;/code&gt; = 纯白）&lt;/li&gt;
&lt;li&gt;黑色系：数字越小越浅（&lt;code&gt;black_1&lt;/code&gt; = 浅灰）&lt;/li&gt;
&lt;li&gt;彩色系：数字越小饱和度越低&lt;/li&gt;
&lt;li&gt;不参与日夜切换，保持绝对稳定&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;完整基础色表&lt;/strong&gt;（与仓库实现一致）：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;色系&lt;/th&gt;
&lt;th&gt;档位数&lt;/th&gt;
&lt;th&gt;命名区间 / 说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;白色系&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;white_1&lt;/code&gt; ~ &lt;code&gt;white_4&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;黑色系&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;black_1&lt;/code&gt; ~ &lt;code&gt;black_8&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;灰色系&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gray_1&lt;/code&gt; ~ &lt;code&gt;gray_7&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;红色系&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;red_1&lt;/code&gt; ~ &lt;code&gt;red_4&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;橙色系&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;orange_1&lt;/code&gt; ~ &lt;code&gt;orange_4&lt;/code&gt;；含 &lt;code&gt;orange_0&lt;/code&gt;、&lt;code&gt;orange_2b&lt;/code&gt;、&lt;code&gt;orange_3b&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;黄色系&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;yellow_1&lt;/code&gt; ~ &lt;code&gt;yellow_4&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蓝色系&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;blue_1&lt;/code&gt; ~ &lt;code&gt;blue_4&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;绿色系&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;green_1&lt;/code&gt; ~ &lt;code&gt;green_4&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;补间色&lt;/td&gt;
&lt;td&gt;按需&lt;/td&gt;
&lt;td&gt;如 &lt;code&gt;black_5a&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;透明度变体&lt;/td&gt;
&lt;td&gt;按需&lt;/td&gt;
&lt;td&gt;&lt;code&gt;基础色名_alpha{透明度}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;代码示例&lt;/strong&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ✅ 正确：统一色系_数字命名 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"white_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#FFFFFF&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"black_8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#000000&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"red_4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#DB121F&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"black_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#F0F0F0&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"white_1_alpha20"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#33FFFFFF&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 第二层：主题适配层（t_）
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;定位&lt;/strong&gt;：唯一的日夜模式映射层，只做色值代理，不承载任何业务语义&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;命名规则&lt;/strong&gt;：&lt;code&gt;t_基础色名&lt;/code&gt;，与基础色一一对应&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;设计原则&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;只引用基础色层变量，绝对不写具体色值&lt;/li&gt;
&lt;li&gt;日间/夜间模式通过 Android 资源限定符自动切换&lt;/li&gt;
&lt;li&gt;保持与基础色完全一致的命名，便于维护&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;错误做法（常见误区）&lt;/strong&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ 错误：主题层承载了业务语义 --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- values/colors.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_bg_page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#FFFFFF&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_text_main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#000000&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- values-night/colors.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_bg_page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#141414&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_text_main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#FFFFFF&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：主题层承载了业务语义，破坏了分层原则。新增主题时需要复制所有业务语义的颜色。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;正确做法&lt;/strong&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ✅ 正确：只做颜色映射，不关心用途 --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- values/colors_theme_tokens.xml（日间模式） --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_white_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/white_1&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_black_8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/black_8&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_orange_4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/orange_4&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- values-night/colors_theme_tokens.xml（夜间模式） --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_white_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/black_8&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;&amp;lt;!-- 背景色反转 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_black_8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/white_1&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;&amp;lt;!-- 主文字色反转 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"t_orange_4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/orange_3b&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- 夜间使用较浅的橙色 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;优势&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;主题层只做颜色映射，不关心用途&lt;/li&gt;
&lt;li&gt;新增主题只需要加一个资源目录&lt;/li&gt;
&lt;li&gt;夜间模式切换完全由 Android 系统自动处理，零代码侵入&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.3 第三层：功能色层（func_）
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;定位&lt;/strong&gt;：面向 UI 职能的语义抽象层，&lt;strong&gt;不承载业务语义&lt;/strong&gt;（如「登录页背景」「删除按钮红」）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;命名规则&lt;/strong&gt;：&lt;code&gt;func_{色系}_{职能}_{档位}&lt;/code&gt;，档位数字按该职能下的深浅/重要性递增&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;设计原则&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;只引用主题层变量，绝对不直接引用基础色&lt;/li&gt;
&lt;li&gt;采用「色系 × 职能 × 数字档位」模式，保留无限扩展能力&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;由设计师在资源文件中定义与维护&lt;/strong&gt;；研发在布局/代码中只引用已有 token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;为什么我反对固定语义命名？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;很多人喜欢这样定义功能色：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_text_main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_8&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_text_sub"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_5&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_text_aux"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_3&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;这在实际项目中会出问题&lt;/strong&gt;：中间态越来越多，命名很快失控。比如需要一个介于 &lt;code&gt;sub&lt;/code&gt; 和 &lt;code&gt;aux&lt;/code&gt; 之间的颜色时，该叫 &lt;code&gt;func_text_sub2&lt;/code&gt; 还是 &lt;code&gt;func_text_medium&lt;/code&gt;？&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;最佳实践：色系 + 职能 + 数字档位&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- 黑色系文本：档位越小越深、越重要 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_black_text_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_8&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_black_text_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_7&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_black_text_3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_5&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_black_text_4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_3&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 黑色系背景：档位越小越浅 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_black_bg_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_8&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_black_bg_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_black_7&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- 橙色系强调 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_orange_text_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_orange_4&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_orange_bg_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_orange_4&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;无限扩展能力&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;需要在 &lt;code&gt;func_black_text_2&lt;/code&gt; 与 &lt;code&gt;func_black_text_3&lt;/code&gt; 之间加一档，由设计师新增 &lt;code&gt;func_black_text_25&lt;/code&gt; 即可&lt;/li&gt;
&lt;li&gt;不用造 &lt;code&gt;func_product_title&lt;/code&gt; 这类业务名&lt;/li&gt;
&lt;li&gt;规范可长期稳定&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;职能分类速览&lt;/strong&gt;（详见第六节完整矩阵）：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;职能后缀&lt;/th&gt;
&lt;th&gt;命名示例&lt;/th&gt;
&lt;th&gt;典型用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_text_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;各级文字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_bg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_gray_bg_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;页面、卡片背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_border&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_gray_border_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_divider&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_divider_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;分割线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_alpha&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_alpha_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;遮罩、半透明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_shadow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_shadow_1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;阴影&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  四、两个关键争议点的深度解析
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 争议1：主题层到底该不该承载业务语义？
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;我的答案：绝对不应该&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;主题层的本质是&lt;strong&gt;颜色代理&lt;/strong&gt;，它的唯一职责是根据当前主题返回对应的基础色。它不应该关心这个颜色是用来做背景还是文字。&lt;/p&gt;

&lt;p&gt;如果主题层承载了业务语义：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;每新增一个主题，你都要复制所有业务语义的颜色&lt;/li&gt;
&lt;li&gt;业务语义变化时，你需要修改所有主题文件&lt;/li&gt;
&lt;li&gt;架构的解耦性被完全破坏&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.2 争议2：功能层用数字命名会不会可读性差？
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;不会，只要约定好规则&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;我们只需要在团队内部约定：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;文本色：数字越小越重要、越深&lt;/li&gt;
&lt;li&gt;背景色：数字越小越浅&lt;/li&gt;
&lt;li&gt;边框色：数字越小越深&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;新人只需要花 5 分钟就能记住这些规则，比记住几十个不同的语义名称要容易得多。&lt;/p&gt;




&lt;h2&gt;
  
  
  五、核心优势：为什么这套架构能解决问题？
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 维护成本显著降低
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;改色流程对比&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th&gt;传统做法&lt;/th&gt;
&lt;th&gt;三层架构&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;改品牌色&lt;/td&gt;
&lt;td&gt;全局搜索替换几百个地方&lt;/td&gt;
&lt;td&gt;修改基础色层一处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;适配夜间模式&lt;/td&gt;
&lt;td&gt;修改所有颜色定义&lt;/td&gt;
&lt;td&gt;自动切换，零代码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;新增页面&lt;/td&gt;
&lt;td&gt;定义 5-10 个新颜色&lt;/td&gt;
&lt;td&gt;复用设计师已定义的功能色&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  5.2 无限扩展能力
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;新增色系：只需要在基础色层添加&lt;/li&gt;
&lt;li&gt;新增主题：只需要加一个资源目录&lt;/li&gt;
&lt;li&gt;新增 UI 职能档位：由设计师在功能层顺延数字编号&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.3 团队协作零成本
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;统一的命名规范，没有歧义&lt;/li&gt;
&lt;li&gt;新成员 5 分钟就能上手&lt;/li&gt;
&lt;li&gt;多人开发不会互相冲突&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  六、功能色层详解：7大色系 × 6种职能
&lt;/h2&gt;

&lt;p&gt;在实际项目中，我们发现一个 App 中常用的颜色职能只需要&lt;strong&gt;6种&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;职能&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;文本色&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文字显示&lt;/td&gt;
&lt;td&gt;标题、正文、辅助文字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;背景色&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;填充区域&lt;/td&gt;
&lt;td&gt;页面背景、卡片背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;边框色&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;勾勒边界&lt;/td&gt;
&lt;td&gt;输入框边框、卡片边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;分割线&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;分隔内容&lt;/td&gt;
&lt;td&gt;列表分割线、区域分隔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;透明度&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;半透明效果&lt;/td&gt;
&lt;td&gt;遮罩、玻璃效果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;阴影色&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;阴影效果&lt;/td&gt;
&lt;td&gt;卡片阴影、按钮阴影&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;而这 6 种职能，组合&lt;strong&gt;7大色系&lt;/strong&gt;，就构成了一个完整的颜色体系。&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 为什么是这7大色系？
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;色系&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;th&gt;主要用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;黑色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;从纯黑到浅灰的完整灰阶&lt;/td&gt;
&lt;td&gt;正文、次要文字、背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;灰色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;独立的灰色梯度&lt;/td&gt;
&lt;td&gt;辅助信息、禁用状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;红色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;高饱和度警示色&lt;/td&gt;
&lt;td&gt;错误、删除、警告&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;黄色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;温和警示色&lt;/td&gt;
&lt;td&gt;待处理、进行中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;橙色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;强调色&lt;/td&gt;
&lt;td&gt;热销、促销、主按钮&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;蓝色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;信任色&lt;/td&gt;
&lt;td&gt;链接、信息、成功&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;绿色系&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;正向色&lt;/td&gt;
&lt;td&gt;成功、增长、完成&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  6.2 完整颜色矩阵
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;文本色（7色系 × 4档 = 28个）&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;色系&lt;/th&gt;
&lt;th&gt;命名&lt;/th&gt;
&lt;th&gt;深浅/饱和度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;黑色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_black_text_1&lt;/code&gt; ~ &lt;code&gt;func_black_text_4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1最深 → 4最浅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;灰色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_gray_text_1&lt;/code&gt; ~ &lt;code&gt;func_gray_text_4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1最深 → 4最浅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;红色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_red_text_1&lt;/code&gt; ~ &lt;code&gt;func_red_text_4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1高饱和 → 4低饱和&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;黄色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_yellow_text_1&lt;/code&gt; ~ &lt;code&gt;func_yellow_text_4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1高饱和 → 4低饱和&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;橙色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_orange_text_1&lt;/code&gt; ~ &lt;code&gt;func_orange_text_4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1高饱和 → 4低饱和&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蓝色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_blue_text_1&lt;/code&gt; ~ &lt;code&gt;func_blue_text_4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1高饱和 → 4低饱和&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;绿色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_green_text_1&lt;/code&gt; ~ &lt;code&gt;func_green_text_4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1高饱和 → 4低饱和&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;背景色（7色系 × 2档 = 14个）&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;色系&lt;/th&gt;
&lt;th&gt;命名&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;黑色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_black_bg_1&lt;/code&gt;, &lt;code&gt;func_black_bg_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;深色背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;灰色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_gray_bg_1&lt;/code&gt;, &lt;code&gt;func_gray_bg_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;浅灰背景、卡片&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;红色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_red_bg_1&lt;/code&gt;, &lt;code&gt;func_red_bg_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;错误背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;黄色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_yellow_bg_1&lt;/code&gt;, &lt;code&gt;func_yellow_bg_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;警告背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;橙色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_orange_bg_1&lt;/code&gt;, &lt;code&gt;func_orange_bg_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;强调背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蓝色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_blue_bg_1&lt;/code&gt;, &lt;code&gt;func_blue_bg_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;信息背景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;绿色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_green_bg_1&lt;/code&gt;, &lt;code&gt;func_green_bg_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;成功背景&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;边框色（7色系 × 2档 = 14个）&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;色系&lt;/th&gt;
&lt;th&gt;命名&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;黑色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_black_border_1&lt;/code&gt;, &lt;code&gt;func_black_border_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;常规边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;灰色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_gray_border_1&lt;/code&gt;, &lt;code&gt;func_gray_border_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;辅助边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;红色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_red_border_1&lt;/code&gt;, &lt;code&gt;func_red_border_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;错误边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;黄色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_yellow_border_1&lt;/code&gt;, &lt;code&gt;func_yellow_border_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;警告边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;橙色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_orange_border_1&lt;/code&gt;, &lt;code&gt;func_orange_border_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;强调边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蓝色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_blue_border_1&lt;/code&gt;, &lt;code&gt;func_blue_border_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;信息边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;绿色系&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;func_green_border_1&lt;/code&gt;, &lt;code&gt;func_green_border_2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;成功边框&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;分割线、透明度、阴影色&lt;/strong&gt;（各7色系 × 2档 = 各14个）：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;色系&lt;/th&gt;
&lt;th&gt;分割线命名&lt;/th&gt;
&lt;th&gt;透明度命名&lt;/th&gt;
&lt;th&gt;阴影命名&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;黑色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_divider_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_alpha_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_shadow_1~2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;灰色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_gray_divider_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_gray_alpha_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_gray_shadow_1~2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;红色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_red_divider_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_red_alpha_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_red_shadow_1~2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;黄色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_yellow_divider_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_yellow_alpha_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_yellow_shadow_1~2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;橙色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_orange_divider_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_orange_alpha_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_orange_shadow_1~2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;蓝色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_blue_divider_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_blue_alpha_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_blue_shadow_1~2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;绿色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_green_divider_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_green_alpha_1~2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_green_shadow_1~2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;理论矩阵规模：7 色系 × 6 职能 × 2–4 档 ≈ 84 个 token&lt;/strong&gt;，可覆盖绝大多数通用 UI 场景。本仓库 demo 仅实现常用子集（见 &lt;code&gt;colors_semantic.xml&lt;/code&gt;）；完整矩阵由设计师按产品需要逐步补齐，研发不自行「补色」。&lt;/p&gt;

&lt;h3&gt;
  
  
  6.3 核心原则：职能无关，业务通用
&lt;/h3&gt;

&lt;p&gt;这套颜色体系是&lt;strong&gt;业务无关&lt;/strong&gt;的。同一个 &lt;code&gt;func_red_text_1&lt;/code&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;在电商 App 中可以用作「商品下架」提示&lt;/li&gt;
&lt;li&gt;在社交 App 中可以用作「被拉黑」提示&lt;/li&gt;
&lt;li&gt;在金融 App 中可以用作「交易失败」提示&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;颜色本身不承载业务语义，业务语义由&lt;strong&gt;使用场景&lt;/strong&gt;决定。&lt;/p&gt;

&lt;h3&gt;
  
  
  6.4 反例 vs 正例
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;反例：业务绑定&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ 错误：业务绑定，无法复用 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_product_delete_text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_red_5&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 商品删除文字 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_order_cancel_text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_red_5&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 订单取消文字 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;正例：职能无关&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ✅ 正确：职能无关，业务通用 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_red_text_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_red_5&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 任何需要红色文字的地方 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;color&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"func_red_text_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@color/t_red_4&lt;span class="nt"&gt;&amp;lt;/color&amp;gt;&lt;/span&gt;    &lt;span class="c"&gt;&amp;lt;!-- 任何需要浅红文字的地方 --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.5 完整命名规范速查表
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;命名公式&lt;/strong&gt;：&lt;code&gt;func_{色系}_{职能}_{档位}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;色系前缀&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;前缀&lt;/th&gt;
&lt;th&gt;色系&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;black&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;黑色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_black_text_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gray&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;灰色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_gray_text_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;red&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;红色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_red_text_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yellow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;黄色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_yellow_text_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;orange&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;橙色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_orange_text_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;blue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;蓝色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_blue_text_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;green&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;绿色系&lt;/td&gt;
&lt;td&gt;&lt;code&gt;func_green_text_1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;职能后缀&lt;/strong&gt;：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;后缀&lt;/th&gt;
&lt;th&gt;职能&lt;/th&gt;
&lt;th&gt;档位&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文本色&lt;/td&gt;
&lt;td&gt;1-4档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_bg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;背景色&lt;/td&gt;
&lt;td&gt;1-2档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_border&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;边框色&lt;/td&gt;
&lt;td&gt;1-2档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_divider&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;分割线&lt;/td&gt;
&lt;td&gt;1-2档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_alpha&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;透明度&lt;/td&gt;
&lt;td&gt;1-2档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_shadow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;阴影色&lt;/td&gt;
&lt;td&gt;1-2档&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  七、总结
&lt;/h2&gt;

&lt;p&gt;这套三层颜色架构的核心思想其实很简单：&lt;strong&gt;解耦&lt;/strong&gt;。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;把色值定义和主题适配解耦&lt;/li&gt;
&lt;li&gt;把主题适配和 UI 职能语义解耦（职能语义仍由设计师定义，不绑定具体业务页面）&lt;/li&gt;
&lt;li&gt;每一层只做自己最擅长的事&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;通过「7大色系 × 6种职能」的设计，我们构建了一套完整、可扩展、业务无关的颜色体系，覆盖 App 所有通用 UI 场景。&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;参考代码&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values/colors_primitives.xml" rel="noopener noreferrer"&gt;基础色定义&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values/colors_theme_tokens.xml" rel="noopener noreferrer"&gt;日间主题层&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values-night/colors_theme_tokens.xml" rel="noopener noreferrer"&gt;夜间主题层&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zealot2002/arch_ui_token_spec/blob/main/app/src/main/res/values/colors_semantic.xml" rel="noopener noreferrer"&gt;功能色定义&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 如果你觉得这篇文章对你有帮助，欢迎点赞、收藏、转发。关注我，获取更多 Android 架构设计干货。&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>uidesign</category>
      <category>mobile</category>
      <category>architecture</category>
      <category>methodology</category>
    </item>
  </channel>
</rss>
