به این مقاله توی مدیوم برخورد کردم و دیدم چقدر مفید هست. برای همین تصمیم گرفتم که اینو ترجمه کنم.
https://medium.com/flutter-community/design-system-from-scratch-in-flutter-bc2aebb8bb02
یک نکته مهم. چون تمام کد ها توی gist روی اینجا embed شدهاند باید صبر کنید تا کد ها به نمایش داده شوند
در ابتدا، راهحلهای متعددی برای ایجاد یک دیزاین سیستم برای اپلیکیشن شما در فلاتر وجود دارد. من میخواهم تجربهام را در مورد دیزاین سیستم، که قبلاً در پروژههایمان پیادهسازی کردهایم، به اشتراک بگذارم.
در مثال ما، ما آن را برای به اشتراک گذاشتن کد طراحی خود بین اپلیکیشنهای موبایل، وب و دسکتاپ به کار بردیم. در نتیجه، این یک پکیج مستقل است که به تنهایی کار میکند. ما میتوانیم آن را در چند مرحله به هر پروژهای تزریق کنیم (Inject).
به عنوان اولین قدم، ما تمام بخشهای جزئی - رنگها، شعاعها (Radiuses)، سایهها (Shadows) و غیره را به کلاسهای مستقل تقسیم کردیم. قطعاً، کدهای دیزاین سیستم پیادهسازی شده به پیادهسازی طراح بستگی دارد.
همانطور که میبینید، طراح اجزای اتمی را برای ما تقسیم کرده است.
من تمام کد را ذکر نخواهم کرد؛ اینها قطعه کد (Snippets) خواهند بود. آنها مانند مثالهای زیر هستند:
شما میتوانید اجزای اتمی بیشتری در پروژههای خود داشته باشید.
من تعدادی از کامپوننتهایمان را به شما نشان خواهم داد - مانند دکمهها و فیلد متن (TextField). سایر کامپوننتها نیز به همین روش توسعه داده شدهاند.
من برای هر یک از کامپوننتهایمان یک کلاس تم جدید نوشتهام تا آنها را تمیزتر نگه دارم. مطمئناً، این توسط طراح ما نیز ارائه شده است.
به یاد داشته باشید که کلاسهای تم از ThemeExtension مشتق شدهاند، به این ترتیب، ما میتوانیم آنها را به عنوان اکستنشنهای تم ثبت کنیم و با کلاس تم از آنها استفاده کنیم.
برای مثال، میتوانیم کلاسهای تم را برای دکمهها و فیلدهای متن بررسی کنیم:
به علاوه، ما یک کلاس AppTypography داریم که اندازههای فونت را به عنوان یک تم مستقل جمعآوری میکند.
توسعه کامپوننت به طرح ارائه شده توسط طراح بستگی دارد. در واقع، تمام مواردی که در بالا توسعه دادیم به آن وابسته است. برای مثال، در مورد ما، دکمههای متنی نسخههای زیادی دارند، مانند اندازه، دکوراسیون و غیره.
بنابراین، ما یک کلاس پایه برای دکمههای متنی خود ایجاد کردهایم. قطعه کد آن به شرح زیر است:
این AppButtonSize یک enum ساده است که توسط ما ارائه شده است:
ما یک typedef ساده با نام IconBuilder ارائه کردهایم. دلیل این کار این است که در برخی موارد، نیاز به تغییر رنگ یک آیکون در وضعیت داخلی دکمه وجود دارد (رنگهای وضعیت فوکوس، هاور و سایر وضعیتها قابل اعمال به رنگ آیکون هستند).
در نهایت، با کمک کلاس پایه AppTextButton، میتوانیم کلاسهای فرزند خود را ایجاد کنیم. بنابراین، کدهای دکمههای متنی Primary، Secondary و Outlined ما به شکل زیر خواهند بود:
برای فیلد متن، ما دوباره یک کلاس مستقل AppTextField ایجاد کردهایم.
اکستنشن برای دریافت تمها با context برای دریافت تمها با context، ما یک کلاس اکستنشن ساده ایجاد کردهایم:
در اینجا، AppTheme کلاسی ساده و تغییرناپذیر (به این معنی که پس از ایجاد، قابل تغییر نیست :immutable class ) از نوع ThemeExtension است و تمام تمها را برای برنامه ما فراهم میسازد.
روند دشواری نیست. اگر با InheritedWidget آشنا باشید، میتوانید این مرحله را به راحتی درک کنید. به همین دلیل، ما یک InheritedWidget ساده به نام ThemeScope ایجاد کردیم تا سیستم طراحی خود را برای یک پروژه جدید فراهم کنیم.
برای مدیریت فرآیند تغییر حالت بین حالتهای تاریک، روشن و سیستم، میتوانید یک کنترلر و مقداردهی اولیه ساده به صورت زیر بنویسید:
برای تغییر ThemeMode خود در هر جایی، میتوانید تابع ThemeScopeWidget.of(context).changeTo را فراخوانی کنید!
ما این پیادهسازی سیستم طراحی را به عنوان یک پکیج مستقل نوشتیم و از آن در برنامههای مختلف استفاده کردیم. ابتدا باید wrapper خود را مقداردهی اولیه کنیم:
void main() async { WidgetsFlutterBinding.ensureInitialized(); final app = await ThemeScopeWidget.initialize(const MyApp()); runApp(app); }
ما گزینه دیگری برای ارائه داریم:
void main() async { WidgetsFlutterBinding.ensureInitialized(); final preferences = await SharedPreferences.getInstance(); runApp( ThemeScopeWidget( preferences: preferences, child: const MyApp(), ), ); }
و در MaterialApp، باید به عنوان یک extension ثبت شود:
final theme = ThemeScope.of(context); return MaterialApp( title: 'Flutter App', themeMode: theme.themeMode, theme: ThemeData(extensions: [theme.appTheme]), darkTheme: ThemeData(extensions: [theme.appTheme]), home: const MyHomePage(title: 'Flutter Demo Home Page'), );
چندین متد extension وجود دارد که به توسعهدهندگان اجازه میدهد به هر تم و تایپوگرافی و فقط چند خط کد دسترسی داشته باشند.
context.buttonTheme.linkHover; context.checkboxTheme.disabled; context.typography.titleSmall;
برای تغییر تم برنامه، فقط باید تابع زیر فراخوانی شود:
final themeScope = ThemeScopeWidget.of(context); themeScope.changeTo(ThemeMode.light);
به طور کلی، assets بخشی از سیستم طراحی هستند. بنابراین، ما یک پکیج مستقل ایجاد کردیم که PNGها، SVGها و غیره را برای هر پروژه به عنوان یک پکیج ذخیره و منتشر میکند.
بنابراین، همانطور که میبینید، پکیج assets فونتها، تصاویر رستر و برداری را ذخیره میکند.
چرا آنها را در پکیجهای مختلف تقسیم کردیم؟
برای بهینهسازی SVGها، از روش جدیدی استفاده کردهایم، به طوری که تمام SVGها در پکیج vectors در زمان بیلد به نسخه بهینه کامپایل میشوند.
و ما به SSOT (منبع واحد حقیقت) برای دریافت assets خود نیاز داریم:
شما میتوانید کلاس گرافیکهای رستر و برداری را نیز جدا کنید.
به خاطر داشته باشید که وقتی از گرافیک رستر در هر پروژهای به عنوان پکیج استفاده میکنید (شما پکیج asset را در pubspec تعریف کرده و از آن استفاده میکنید)، باید فیلد package را تعریف کنید:
Image.asset(AppAssets.sittingSad, package: 'assets')
و اگر میخواهید فونت را از پکیج دیگری export کنید، باید فونتهای خود را درون پوشه lib تعریف کنید. برای اطلاعات بیشتر، میتوانید مقاله "Export fonts from a package" را از مستندات فلاتر بررسی کنید.
https://docs.flutter.dev/cookbook/design/package-fonts
برای این منظور، ما از Widgetbook استفاده میکنیم. این موضوع بسیار گستردهای برای نوشتن است. برای جلوگیری از طولانیتر شدن مقاله، من در مورد این موضوع به تفصیل ننوشتم. این ابزار مستندات بسیار خوبی دارد که میتوانید آن را بررسی کنید.
به پایان رسید. اگر از مقاله من خوشتان آمد، فراموش نکنید که تشویق کنید!