مرتضی نظری
خواندن ۵ دقیقه·۲ ماه پیش

سیستم طراحی از صفر در فلاتر

به این مقاله توی مدیوم برخورد کردم و دیدم چقدر مفید هست. برای همین تصمیم گرفتم که اینو ترجمه کنم.

https://medium.com/flutter-community/design-system-from-scratch-in-flutter-bc2aebb8bb02

یک نکته مهم. چون تمام کد ها توی gist روی اینجا embed شده‌اند باید صبر کنید تا کد ها به نمایش داده شوند

طراحی سیستم از صفر در فلاتر

در ابتدا، راه‌حل‌های متعددی برای ایجاد یک دیزاین سیستم برای اپلیکیشن شما در فلاتر وجود دارد. من می‌خواهم تجربه‌ام را در مورد دیزاین سیستم، که قبلاً در پروژه‌هایمان پیاده‌سازی کرده‌ایم، به اشتراک بگذارم.




چرا به یک دیزاین سیستم نیاز داریم؟

در مثال ما، ما آن را برای به اشتراک گذاشتن کد طراحی خود بین اپلیکیشن‌های موبایل، وب و دسکتاپ به کار بردیم. در نتیجه، این یک پکیج مستقل است که به تنهایی کار می‌کند. ما می‌توانیم آن را در چند مرحله به هر پروژه‌ای تزریق کنیم (Inject).




بیایید با اجزای اتمی(Atomic parts) شروع کنیم.

به عنوان اولین قدم، ما تمام بخش‌های جزئی - رنگ‌ها، شعاع‌ها (Radiuses)، سایه‌ها (Shadows) و غیره را به کلاس‌های مستقل تقسیم کردیم. قطعاً، کدهای دیزاین سیستم پیاده‌سازی شده به پیاده‌سازی طراح بستگی دارد.

طراحی شده توسط gadirli
طراحی شده توسط gadirli

همانطور که می‌بینید، طراح اجزای اتمی را برای ما تقسیم کرده است.

من تمام کد را ذکر نخواهم کرد؛ اینها قطعه کد (Snippets) خواهند بود. آنها مانند مثال‌های زیر هستند:


https://gist.github.com/mortezanazari-hub/6713c526da7d586b1a5f170c59520654
https://gist.github.com/mortezanazari-hub/bfca2eb586535892e902037fc909c5a1
https://gist.github.com/mortezanazari-hub/7f2cef00d9f598530c6dfbad68f4d9c8
https://gist.github.com/mortezanazari-hub/ebdb1180a12a47989ad350b727bc6e5a
شما می‌توانید اجزای اتمی بیشتری در پروژه‌های خود داشته باشید.

مرحله‌ی بعدی - کامپوننت‌ها

من تعدادی از کامپوننت‌هایمان را به شما نشان خواهم داد - مانند دکمه‌ها و فیلد متن (TextField). سایر کامپوننت‌ها نیز به همین روش توسعه داده شده‌اند.



توسعه‌ی تم برای کامپوننت

من برای هر یک از کامپوننت‌هایمان یک کلاس تم جدید نوشته‌ام تا آن‌ها را تمیزتر نگه دارم. مطمئناً، این توسط طراح ما نیز ارائه شده است.

به یاد داشته باشید که کلاس‌های تم از ThemeExtension مشتق شده‌اند، به این ترتیب، ما می‌توانیم آن‌ها را به عنوان اکستنشن‌های تم ثبت کنیم و با کلاس تم از آن‌ها استفاده کنیم.

برای مثال، می‌توانیم کلاس‌های تم را برای دکمه‌ها و فیلدهای متن بررسی کنیم:

https://gist.github.com/mortezanazari-hub/a29aaf9fe87a305d7c21c912195d19c8
https://gist.github.com/mortezanazari-hub/ab2d23f60c7f24251d7e1b83910cd65a

به علاوه، ما یک کلاس AppTypography داریم که اندازه‌های فونت را به عنوان یک تم مستقل جمع‌آوری می‌کند.

https://gist.github.com/mortezanazari-hub/fb957c57ecff231dc188f63c1fd06c85



بعد از همه اینها... کامپوننت‌ها

توسعه کامپوننت به طرح ارائه شده توسط طراح بستگی دارد. در واقع، تمام مواردی که در بالا توسعه دادیم به آن وابسته است. برای مثال، در مورد ما، دکمه‌های متنی نسخه‌های زیادی دارند، مانند اندازه، دکوراسیون و غیره.

ما دکمه های زیادی داشتیم، اما من برخی از آنها را به اشتراک گذاشته ام (دکمه های متنی)
ما دکمه های زیادی داشتیم، اما من برخی از آنها را به اشتراک گذاشته ام (دکمه های متنی)

بنابراین، ما یک کلاس پایه برای دکمه‌های متنی خود ایجاد کرده‌ایم. قطعه کد آن به شرح زیر است:

https://gist.github.com/mortezanazari-hub/512457adaaa44aea8e3c2cfc494064ac

این AppButtonSize یک enum ساده است که توسط ما ارائه شده است:

https://gist.github.com/mortezanazari-hub/a7882e6e38d2eca8ec2528031cf06981

ما یک typedef ساده با نام IconBuilder ارائه کرده‌ایم. دلیل این کار این است که در برخی موارد، نیاز به تغییر رنگ یک آیکون در وضعیت داخلی دکمه وجود دارد (رنگ‌های وضعیت فوکوس، هاور و سایر وضعیت‌ها قابل اعمال به رنگ آیکون هستند).

https://gist.github.com/mortezanazari-hub/9d95f96108890b2013297e3a532d9711

در نهایت، با کمک کلاس پایه AppTextButton، می‌توانیم کلاس‌های فرزند خود را ایجاد کنیم. بنابراین، کدهای دکمه‌های متنی Primary، Secondary و Outlined ما به شکل زیر خواهند بود:

https://gist.github.com/mortezanazari-hub/dccc6d8dd635ed20ac6a1e1465259ede
https://gist.github.com/mortezanazari-hub/f9769d6976fff10888c4026281bf8065
https://gist.github.com/mortezanazari-hub/05c65e207a05378f35b5d0bf73808215

برای فیلد متن، ما دوباره یک کلاس مستقل AppTextField ایجاد کرده‌ایم.

https://gist.github.com/mortezanazari-hub/cc3baf24bcd57dfd7ed69aa537f6b556




اکستنشن برای دریافت تم‌ها با context برای دریافت تم‌ها با context، ما یک کلاس اکستنشن ساده ایجاد کرده‌ایم:

https://gist.github.com/mortezanazari-hub/d81512b91fbf46ec41c1793c14ff229a



خب... در اینجا منظور از AppTheme چیست؟

در اینجا، AppTheme کلاسی ساده و تغییرناپذیر (به این معنی که پس از ایجاد، قابل تغییر نیست :immutable class ) از نوع ThemeExtension است و تمام تم‌ها را برای برنامه ما فراهم می‌سازد.

https://gist.github.com/mortezanazari-hub/7a8385fcb4e94101c9313b88a918fca8



چگونه تم خود را برای یک پروژه جدید فراهم خواهیم کرد؟

روند دشواری نیست. اگر با InheritedWidget آشنا باشید، می‌توانید این مرحله را به راحتی درک کنید. به همین دلیل، ما یک InheritedWidget ساده به نام ThemeScope ایجاد کردیم تا سیستم طراحی خود را برای یک پروژه جدید فراهم کنیم.

https://gist.github.com/mortezanazari-hub/df05a20910a6953e407adfe3bd9315ca



مدیریت ThemeMode

برای مدیریت فرآیند تغییر حالت بین حالت‌های تاریک، روشن و سیستم، می‌توانید یک کنترلر و مقداردهی اولیه ساده به صورت زیر بنویسید:

https://gist.github.com/mortezanazari-hub/e98eedd88e2880eac8f01b3a3ca1afd9

برای تغییر 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 چی؟

به طور کلی، assets بخشی از سیستم طراحی هستند. بنابراین، ما یک پکیج مستقل ایجاد کردیم که PNGها، SVGها و غیره را برای هر پروژه به عنوان یک پکیج ذخیره و منتشر می‌کند.

بنابراین، همانطور که می‌بینید، پکیج assets فونت‌ها، تصاویر رستر و برداری را ذخیره می‌کند.

  • منظور از رستر(raster)، PNGها، JPEGها و غیره است.
  • منظور از بردار(vector)، SVGها است.

چرا آنها را در پکیج‌های مختلف تقسیم کردیم؟

برای بهینه‌سازی SVGها، از روش جدیدی استفاده کرده‌ایم، به طوری که تمام SVGها در پکیج vectors در زمان بیلد به نسخه بهینه کامپایل می‌شوند.

و ما به SSOT (منبع واحد حقیقت) برای دریافت assets خود نیاز داریم:

https://gist.github.com/mortezanazari-hub/a645f3d9bcdea1de08cf620b215671d4
شما می‌توانید کلاس گرافیک‌های رستر و برداری را نیز جدا کنید.

به خاطر داشته باشید که وقتی از گرافیک رستر در هر پروژه‌ای به عنوان پکیج استفاده می‌کنید (شما پکیج 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 استفاده می‌کنیم. این موضوع بسیار گسترده‌ای برای نوشتن است. برای جلوگیری از طولانی‌تر شدن مقاله، من در مورد این موضوع به تفصیل ننوشتم. این ابزار مستندات بسیار خوبی دارد که می‌توانید آن را بررسی کنید.



به پایان رسید. اگر از مقاله من خوشتان آمد، فراموش نکنید که تشویق کنید!


یک برنامه نویس نوب! که فلاتر و سی شارپ رو خیلی دوست داره!
شاید از این پست‌ها خوشتان بیاید