آموزش گوگل فلاتر (Flutter ): ساخت اپلیکیشن دستورهای آشپزی – (بخش اول)


اگر تاکنون هرگز به برنامهنویسی برای تلفن همراه و حصوصاً آموزش گوگل فلاتر نپرداختهاید، اینک زمان آن فرارسیده است که از لاک دفاعی خود خارج شده و پا به دنیای کاملاً جدیدی بگذارید. اگر فکر میکنید این کار به تلاش و صرف زمان زیادی نیاز دارد، مشخص است که هنوز نام فریمورک فلاتر به گوشتان نخورده است. فلاتر راهحلی عالی برای ایجاد اپلیکیشنهای موبایل برای اندروید و iOS محسوب میشود. بدین ترتیب با یک کد واحد میتوانید اپلیکیشن خود را روی هر دو پلتفرم اجرا کنید و این عالی است.
در این سری از مقالات شیوه ایجاد یک اپلیکیشن دستور آشپزی با استفاده از دارت (Dart) و فلاتر (Flutter) را آموزش میدهیم تا ببینید این کار تا چه حد آسان است. برای استفاده از این سری مقالات نیاز به هیچ تجربه قبلی در این دو فریمورک ندارید. کافی است که با مبانی مقدماتی برنامهنویسی شیءگرا آشنا باشید و درکی اولیه از ابزارهای خط فرمان نیز داشته باشید.
ما در این سلسله مطالب موارد زیر را خواهیم آموخت:
- ایجاد یک رابط کاربری
- احراز هویت کاربر از طریق Firebase Authentication و گوگل
- دریافت و ذخیرهسازی دادهها با استفاده از Cloud Firestore
اپلیکیشن ما در نهایت به صورت زیر خواهد بود:
پیش از شروع به پیادهسازی اپلیکیشن، ابتدا باید فلاتر را نصب کنیم. بدین منظور بهتر است از یکی از راهنماهایی که تیم فلاتر ارائه کرده (+) استفاده کنید. فلاتر برای پلتفرمهای ویندوز، مکاواس و لینوکس عرضه شده است.
اگر دوست دارید از یک IDE برای توسعه اپلیکیشن در فلاتر استفاده کنید، میتوانید از Android Studio، IntelliJ یا VS Code بهره بگیرید. ما استفاده از VS Code را ترجیح میدهیم، زیرا سبک و ساده است و امکاناتی برای سفارشیسازی ارائه کرده است. اما این یک ترجیح شخصی است و شما میتوانید هر IDE که دوست دارید را انتخاب کنید.
ما در ادامه این مقاله اقدام به ایجاد یک اپلیکیشن جدید و پیادهسازی رابط کاربری صفحه ورود میکنیم که شامل دکمه «ورود با حساب گوگل» و صفحه اصلی شامل ناوبری نمای برگهای است و میتوانید تصاویری از آن را در بخش فوق ببینید. نتیجه تلاشهایمان در بخش اول این سلسله مقالات را در این ریپو گیتهاب (+) میتوانید مشاهده کنید.
ایجاد UI برای نمای ورود (login)
در این بخش مراحل مورد نیاز برای پیادهسازی رابط کاربری ورود به اپلیکیشن را بررسی میکنیم.
مراحل اولیه
برای آغاز توسعه اپلیکیشن باید ابتدا یک app جدید ایجاد کنیم. به این منظور باید به آن دایرکتوری بروید که میخواهید دستور flutter create recipes_app را در خط فرمان اجرا کنید.

اینک ما موفق شدهایم نخستین اپلیکیشن فلاتر خود را ایجاد کنیم. فکر میکنید این برنامه چه شکل و شمایلی دارد؟ با اجرای دستورالعملهایی که در خروجی flutter create میبینید، میتوانید شیوه اجرای اپلیکیشن روی دستگاه خود را مشاهده کنید.
در گام نخست باید کمی کد خود را سازماندهی کنیم. به این منظور باید همه کدهای موجود در main.dart در دایرکتوری lib را با قطعه کد زیر جایگزین کنید به طوری که تابع main فقط اپلیکیشن را اجرا کند و شامل چیزی به جز موارد زیر نباشد:
import 'package:flutter/material.dart'; import 'package:recipes_app/app.dart'; void main() => runApp( new RecipesApp(), );
ممکن است متوجه شوید که IDE چیزی در مورد فایل app.dart و کلاس RecipesApp نمیداند. به منظور اصلاح این وضعیت باید فایل add.dart را در دایرکتوری lib ایجاد کرده و کلاس RecipesApp را پیادهسازی کنید. این همان کلاسی است که مسیرهای صفحات اپلیکیشن خود را در آن تعریف میکنیم. ما به این مسیرها برای ناوبری بین صفحههای مختلف در مراحل بعدی پروژه نیاز خواهیم داشت:
import 'package:flutter/material.dart'; import 'package:recipes_app/ui/screens/login.dart'; class RecipesApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Recipes', initialRoute: '/login', routes: { // If you're using navigation routes, Flutter needs a base route. // We're going to change this route once we're ready with // implementation of HomeScreen. '/': (context) => LoginScreen(), '/login': (context) => LoginScreen(), }, ); } }
همان طور که میبینید کلاس RecipesApp ما از StatelessWidget ارثبری میکند. در فلاتر همه چیز یک ویجت محسوب میشود. شما میتوانید از ویجتهای بیحالت و یا ویجتهای باحالت استفاده کنید. در صورتی که میخواهید یک ویجت پیادهسازی کنید که هیچ وابستگی نداشته و در طی چرخه عمر تغییری نیابد، در این صورت باید از یک ویجت بیحالت استفاده کنید. ویجتهای باحالت اساساً متضاد ویجتهای بیحالت هستند. ما در مورد این ویجتها در بخش بعدی این مقاله یعنی زمانی که نیاز به پیادهسازیشان در اپلیکیشن خود خواهیم یافت، صحبت میکنیم. اینک به مرحله بعدی میرویم.
پیادهسازی صفحه ورود
اینک آماده هستیم که ویجت دیگری را بسازیم. یک دایرکتوری به نام ui در دایرکتوری lib بسازید. این ویجت به ما کمک میکند که هنگام باز کردن پروژه بعد از مدت زمان طولانی، بتوانیم سریعاً نمایی کلی از پروژه داشته باشیم. علاوه بر آن یافتن مسیرها در پروژه برای همه افراد آسان خواهد شد. ما قصد داریم همه کدهای مربوط به رابط کاربری را درون این دایرکتوری ذخیره کنیم. اکنون یک دایرکتوری به نام screens درون دایرکتوری ui ایجاد میکنیم. این همان جایی است که ماژولهایی را برای پیادهسازی ویجتهای screen قرار میدهیم.

ابتدا با ایجاد یک قالب ساده برای ویجت LoginScreen خود در مسیر lib/ui/screens/login.dart آغاز میکنیم:
import 'package:flutter/material.dart'; class LoginScreen extends StatelessWidget { @override Widget build(BuildContext context) { // Private methods within build method help us to // organize our code and recognize structure of widget // that we're building: Text _buildText() { return Text( 'Recipes', textAlign: TextAlign.center, ); } return Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ _buildText(), // Space between "Recipes" and the button: SizedBox(height: 50.0), MaterialButton( color: Colors.white, child: Text("Sign In with Google"), onPressed: () => print("Button pressed."), ) ], ), ), ); } }
نتیجه کار چندان هیجان انگیز نیست:
این صفحه را گام به گام تغییر میدهیم.
ابتدا پسزمینه آبی رنگ را با استفاده از یک تصویر تغییر میدهیم. رنگ آبی در مشخصات backgroundColor درون Scaffold در متد build تعریف شده است. برای توسعه صفحهای که شامل اکتیویتی UI باشد، باید از Scaffold به عنوان ویجت والد استفاده کنیم. از آنجا که سازنده کلاس Scaffold تنها منتظر یک ویجت منفرد در مشخصه body است، یک شیء Center را به آن ارسال میکنیم که شامل یک column است که امکان ارسال فهرستی از ویجتها به مشخصه children را فراهم میسازد:
بنابراین برای تغییر دادن رنگ پسزمینه صفحه به یک تصویر، باید ابتدا یک فایل تصویر را در پروژه خود قرار دهیم. یک دایرکتوری به نام assets در دایرکتوری ریشه پروژه خود ایجاد کنید و فایل تصویر مورد نظر خود را در آنجا قرار دهید. تصویری که ما استفاده کردهایم را در این لینک (+) میتوانید بیابید.
ما قصد داریم از دایرکتوری assets برای ذخیرهسازی همه فایلهایی که اپلیکیشن ما در زمان اجرا نیاز خواهد داشت استفاده کنیم. از آنجا که در مورد مثال ما، همه این فایلها به صورت تصویر هستند، لازم نیست هیچ دایرکتوری فرعی در دایرکتوری assets ایجاد کنیم.
اکنون میتوانیم فایلهای خود را در بخش flutter فایل pubspec.yaml در ریشه پروژه اضافه کنیم:
flutter: uses-material-design: true # New: assets: - assets/brooke-lark-385507-unsplash.jpg
همه دادهها و وابستگیهای متای اپلیکیشن در pubspec.yaml تعریف میشوند. این وابستگیها باید به صورت بسته، فونت یا تصویر باشند.
برای تنظیم تصویر به صورت تصویر پسزمینه در صفحه ورودی، میتوانیم ویجت Center خود را درون Container پوشش دهیم و از آن به عنوان یک مشخصه Decoration استفاده کنیم.
اگر در مورد استفاده از ویجتهای داخلی فلاتر یا مشخصههای آنها مطمئن نباشید، میتوانید از مستندات فلاتر (+) یا کاتالوگ ویجتهای فلاتر (+) برای مشاهده جایگزینهای ویجتها استفاده کنید و ببینید که آیا در مسیر دسترسی حرکت میکنید یا نه.
در مستندات ویجت Container اشاره شده است که به منظور نمایش تصویری در پسزمینه ویجت child استفاده میشود.
در ادامه پیادهسازی بهروز شده از متد build را در کلاس LoginScreen مشاهده میکنید:
// ... @override Widget build(BuildContext context) { // New private method which includes the background image: BoxDecoration _buildBackground() { return BoxDecoration( image: DecorationImage( image: AssetImage("assets/brooke-lark-385507-unsplash.jpg"), fit: BoxFit.cover, ), ); } Text _buildText() { return Text( 'Recipes', textAlign: TextAlign.center, ); } return Scaffold( // We do not use backgroundColor property anymore. // New Container widget wraps our Center widget: body: Container( decoration: _buildBackground(), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ _buildText(), SizedBox(height: 50.0), MaterialButton( color: Colors.white, child: Text("Sign In with Google"), onPressed: () => print("Button pressed."), ), ], ), ), ), ); }
نتیجه کار همچنان چندان رضایتبخش نیست؛ اما اکنون ما با روش گنجاندن فایل تصویر در پروژه آشنا شدیم و میتوانیم تصویرها را به عنوان پسزمینه صفحه قرار دهیم.
استفاده از قالبها
همان طور که مشاهده میکنید وقتی اپلیکیشن خود را در وضعیت کنونی اجرا میکنیم، متنی به صورت «Recipes» در صفحه ورود نمایش مییابد؛ اما ظاهر آن چندان جذاب نیست. ما میخواهیم ظاهر آن را بهبود ببخشیم؛ اما بیش از حد هم جذاب نباشد. در ادامه به تغییر سبکبندی متن پرداختهایم.
دو گزینه به این منظور وجود دارد:
گزینه اول
// We override default style by using style property // and TextStyle widget, which defines text style: Text( 'Recipes', style: TextStyle( fontFamily: 'Merriweather', fontSize: 40.0, color: const Color(0xFF807A6B), ), textAlign: TextAlign.center, )
گزینه دوم
// We use style property and a theme: Text( 'Recipes', style: Theme.of(context).textTheme.headline, textAlign: TextAlign.center, )
ما در گزینه دوم از یک قالب (theme) استفاده کردهایم.
استفاده از قالب در فلاتر به این معنی است که یک ویجت ThemeData تعریف میشود که به وسیله آن میتوان سبکهای همه ویجتهای دیگر را به اشتراک گذاشت. اگر به یک سبک نیاز داشته باشیم، میتوانیم ویجت ThemeData خود را تغییر دهیم و آن را روی ویجتی که به یک سبک نیاز دارد اعمال کنیم. بزرگترین مزیت استفاده از یک قالب، ظرفیت استفاده مجدد از آن است. کافی است سبکی را تنها یک بار ایجاد کنیم و سپس اگر نیاز به تغییر داشته باشد کافی است یک بار آن را تغییر دهیم.
به منظور ایجاد یک پروژه کاملاً سامانیافته باید یک قالب را در جایی پیادهسازی کنیم که همه بتوانند آن را بیایند و این جا مسیر lib/ui/ است. یک فایل را در این مسیر به نام با مسمای theme.dart ایجاد میکنیم.
پیادهسازی فایل theme.dart به صورت زیر است:
import 'package:flutter/material.dart'; ThemeData buildTheme() { // We're going to define all of our font styles // in this method: TextTheme _buildTextTheme(TextTheme base) { return base.copyWith( headline: base.headline.copyWith( fontFamily: 'Merriweather', fontSize: 40.0, color: const Color(0xFF807a6b), ), ); } // We want to override a default light blue theme. final ThemeData base = ThemeData.light(); // And apply changes on it: return base.copyWith( textTheme: _buildTextTheme(base.textTheme), ); }
بنابراین تا به این جا تنها یک قالب تعریف کردهایم. ما نمیتوانیم هنوز از آن در پروژه خود استفاده کنیم. برای اشتراک قالب در میان همه ویجتها در اپلیکیشن باید آن قالب را در ویجت MaterialApp به کار بگیریم که از سوی متد build در کلاس RecipesApp در فایل app.dart بازگشت مییابد:
import 'package:flutter/material.dart'; import 'package:recipes/ui/screens/login.dart'; import 'package:recipes_app/ui/theme.dart'; // New code class RecipesApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Recipes', theme: buildTheme(), // New code initialRoute: '/login', routes: { '/': (context) => LoginScreen(), '/login': (context) => LoginScreen(), }, ); } }
اکنون میتوانیم به سبکهای تعریف شده در متد buildTheme در همه ویجتها به ترتیبی دسترسی داشته باشیم که قطعه کد موجود در گزینه 2 فوق را ببینیم.
همان طور که متوجه شدید ما از فونت Merriweather در ویجت ThemeData استفاده کردهایم. در این مرحله، این فونت هنوز در پروژه قرار نگرفته است. شما میتوانید آن را از مخزن فونتهای گوگل (+) دانلود کنید. زمانی که فونت را به دست آوردید، یک دایرکتوری به نام fonts در ریشه پروژه ایجاد کنید و فونت مورد نظر به نام Merriweather-Regular.ttf را درون آن قرار دهید تا به پروژه اضافه شود. سپس فایل pubspec.yaml را ویرایش کنید:
flutter: uses-material-design: true assets: - assets/brooke-lark-385507-unsplash.jpg fonts: # New - family: Merriweather fonts: - asset: fonts/Merriweather-Regular.ttf
اینک نگاهی به نتیجه کارهایمان میاندازیم:
در این مرحله صفحه ورودی ظاهر مناسبی یافته است؛ اما احتمالاً متوجه شدهاید که سبک دکمه Sign In with Google همچنان اعمال نشده است.
دکمه Sign In with Google
در این مرحله ویجت سفارشی بعدی خود را پیادهسازی میکنیم. ما قصد داریم دکمه را با در نظر گرفتن «راهنماییهای برندسازی ثبت نام» ارائه شده از سوی گوگل (+) پیادهسازی کنیم. پیش از افزودن ویجت سفارشی به پروژه باید فونت Roboto و لوگوی G گوگل را به پروژه خود اضافه کنیم.

در مرحله بعدی یک دایرکتوری به نام widgets در دایرکتوری ui میسازیم و کد زیر را در فایل جدیدی به نام google_sign_in_button.dart قرار میدهیم.
دقت کنید که ما میتوانیم یک callback تابع به نام onPressed را در سازنده کلاس GoogleSignInButton ارسال کنیم. در این مورد نیاز به پیادهسازی متدهای خصوصی buildLogo_ و buildText_ در متد build ویجت خود جهت بهبود خوانایی کد اقدام میکنیم:
import 'package:flutter/material.dart'; class GoogleSignInButton extends StatelessWidget { GoogleSignInButton({this.onPressed}); final Function onPressed; @override Widget build(BuildContext context) { Image _buildLogo() { return Image.asset( "assets/g-logo.png", height: 18.0, width: 18.0, ); } Opacity _buildText() { return Opacity( opacity: 0.54, child: Text( "Sign in with Google", style: TextStyle( fontFamily: 'Roboto-Medium', color: Colors.black, ), ), ); } return MaterialButton( height: 40.0, onPressed: this.onPressed, color: Colors.white, child: Row( mainAxisSize: MainAxisSize.min, children: <Widget>[ _buildLogo(), SizedBox(width: 24.0), _buildText(), ], ), ); } }
تا به این جا همه چیز خوب بوده است؛ اما اگر بخواهیم از ویجت سفارشی GoogleSignInButton استفاده کنیم چطور؟ به این منظور باید MaterialButton را در فایل login.dart با withGoogleSignInButton عوض کنیم:
import 'package:flutter/material.dart'; import 'package:recipes_app/ui/widgets/google_sign_in_button.dart'; // New code class LoginScreen extends StatelessWidget { @override Widget build(BuildContext context) { BoxDecoration _buildBackground() { return BoxDecoration( image: DecorationImage( image: AssetImage("assets/brooke-lark-385507-unsplash.jpg"), fit: BoxFit.cover, ), ); } Text _buildText() { return Text( 'Recipes', style: Theme.of(context).textTheme.headline, textAlign: TextAlign.center, ); } return Scaffold( body: Container( decoration: _buildBackground(), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ _buildText(), SizedBox(height: 50.0), // Passing function callback as constructor argument: GoogleSignInButton( // New code onPressed: () => print("Button pressed."), // New code ), // New code ], ), ), ), ); } }
رفتن به صفحه اصلی اپلیکیشن
ناوبری بین صفحات مختلف در فلاتر کاملاً ساده است. آیا به خاطر دارید چگونه در بخش ابتدایی این مقاله مسیرهایی را بین صفحههای مختلف تعریف کردیم؟ ما قصد داریم از این مسیرها برای ناوبری بین صفحه ورود و صفحه اصلی اپلیکیشن استفاده کنیم.
زمانی که به کد موجود در فایل app.dart نگاه میکنیم، مشخص است که اپلیکیشن Recipes دو مسیر دارد:
- / – این مسیر پایه است که به ویجت LoginScreen ارجاع دارد.
- login/ – مسیر دوم است که این نیز به ویجت LoginScreen ارجاع دارد.
مسیر نخست را تغییر میدهیم تا به ویجت HomeScreen اشاره کند. البته این ویجت هنوز وجود ندارد؛ اما جای نگرانی نیست چون در مرحله بعدی آن را ایجاد خواهیم کرد.
// ... routes: { '/': (context) => HomeScreen(), // New code '/login': (context) => LoginScreen(), }, // ...
از آنجا که اکثر دغدغه ما در این مقاله در مورد پیادهسازی رابط کاربری بوده است، میخواهیم کاربر را پس از زدن روی ویجت GoogleSignInButton به صفحه اصلی اپلیکیشن هدایت کنیم. بدین منظور باید callback تابع ارسالی به سازنده GoogleSignInButton درون فایل login.dart را به تابعی تغییر دهیم که از مسیر پایه استفاده کرده و کاربر را به صفحه جدیدی ببرد.
به این منظور از ویجت Navigator (+) استفاده میکنیم. این ویجت مسیرهای منتهی به ویجتها را مدیریت میکند و متدهای بسیار مفیدی ارائه کرده است. یکی از این متدها pushReplacementNamed است که در مثال زیر با آن سر و کار داریم. در ادامه شیوه استفاده از ویجت Navigator با مسیر تعریف شده در مرحله بعدی را میبینید:
// ... GoogleSignInButton( onPressed: () => // We replace the current page. // After navigating to the replacement, it's not possible // to go back to the previous screen: Navigator.of(context).pushReplacementNamed('/'), ), // ...
این همه آن چیزی است که برای رفتن از صفحه ورود به صفحه اصلی نیاز داریم.
در مورد مثال ما، مقصود این است که امکان بازگشت به صفحه ورود پس از انجام ناوبری فوق را داشته باشیم. در موارد دیگر از pushNamed استفاده میشود که صفحه کنونی را تعویض نمیکند و کاربر امکان سوئیچ به صفحه قبلی را دارد. به طور جایگزین میتوانید نگاهی به راهنمای «ناوبری به صفحه جدید و بازگشت» (+) داشته باشید که چگونگی ناوبری بین ویجتها بدون تعریف مسیر را نشان میدهد.
پیادهسازی صفحه اصلی
اگر از یک IDE برای پیادهسازی اپلیکیشن Recipes استفاده میکنید، احتمالاً با هشداری مبنی بر عدم یافتن ویجت HomeScreen مواجه شدهاید:
این نکته صحیحی است و در گام بعدی یک فایل جدید به نام home.dart در دایرکتوری lib/ui/screens ایجاد میکنیم:

سپس کد زیر را در این فایل قرار میدهیم. این فایل ویجت HomeScreen را پیادهسازی میکند که شامل بک نوار برگه با چهار برگه است که به صورت آیکونهایی هستند. این نوار برگه در واقع ابزار اصلی ناوبری در اپلیکیشن ما خواهد بود. فعلاً ما آیکونهایی را به عنوان placeholder برای محتوای برگهها قرار میدهیم:
import 'package:flutter/material.dart'; class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { double _iconSize = 20.0; return DefaultTabController( length: 4, child: Scaffold( appBar: AppBar( backgroundColor: Colors.white, elevation: 2.0, bottom: TabBar( labelColor: Theme.of(context).indicatorColor, tabs: [ Tab(icon: Icon(Icons.restaurant, size: _iconSize)), Tab(icon: Icon(Icons.local_drink, size: _iconSize)), Tab(icon: Icon(Icons.favorite, size: _iconSize)), Tab(icon: Icon(Icons.settings, size: _iconSize)), ], ), ), body: Padding( padding: EdgeInsets.all(5.0), child: TabBarView( // Placeholders for content of the tabs: children: [ Center(child: Icon(Icons.restaurant)), Center(child: Icon(Icons.local_drink)), Center(child: Icon(Icons.favorite)), Center(child: Icon(Icons.settings)), ], ), ), ), ); } }
نتیجه به صورت زیر خواهد بود:
نوار برگه ما قطعاً خیلی عریض است. برای تغییر عرضان باید ویجت قبلاً تعریف شده AppBar را درون یک ویجت PreferredSize قرار دهیم. بدین ترتیب میتوانیم ارتفاع جدیدی برای نوار برگهها تعریف کنیم:
// ... appBar: PreferredSize( // New code // We set Size equal to passed height (50.0) and infinite width: preferredSize: Size.fromHeight(50.0), // New code child: AppBar( backgroundColor: Colors.white, elevation: 2.0, bottom: TabBar( labelColor: Theme.of(context).indicatorColor, tabs: [ Tab(icon: Icon(Icons.restaurant, size: _iconSize)), Tab(icon: Icon(Icons.local_drink, size: _iconSize)), Tab(icon: Icon(Icons.favorite, size: _iconSize)), Tab(icon: Icon(Icons.settings, size: _iconSize)), ], ), ), ), // New code // ...
اکنون نوار برگهها ظاهر بهتری دارد و نتیجه نهایی چیزی شبیه زیر خواهد بود:
سخن پایانی
همه آنچه در این مقاله آموختیم را در نکات زیر میتوان جمعبندی نمود:
- روش نوشتن و استفاده از ویجتهای سفارشی که از StatelessWidget ارثبری میکنند و در طی زمان اجرا تغییر نمییابند.
- شیوه ساخت لیآوتهایی درون ویجتهای سفارشی با استفاده از ویجتهای فلاتر مانند Center، Column، Row، SizedBox، Container.
- چگونگی استفاده از ویجت ThemeData برای اشتراکگذاری سبکها در فلاتر
- چگونگی ناوبری بین ویجتها با استفاده از ویجت Navigator
- این که در فلاتر همه چیز یک ویجت محسوب میشود.
برای مطالعه بخش دوم این آموزش میتوانید به این لینک رجوع کنید: آموزش گوگل فلاتر (Flutter ): ساخت اپلیکیشن دستورهای آشپزی — (بخش دوم)
اگر این مطلب برایتان مفید بوده است، آموزشهای زیر را نیز به شما پیشنهاد میکنیم:
- مجموعه آموزشهای برنامهنویسی اندروید
- گوگل فلاتر (Flutter) از صفر تا صد — ساخت اپلیکیشن به کمک ویجت
- مجموعه آموزشهای برنامهنویسی
- آموزش فلاتر (Flutter): توسعه اپلیکیشن برای صفحات نمایش با ابعاد مختلف
- آموزش ListView و ScrollPhysics در فلاتر (Flutter) — از صفر تا صد
- کار با متریال دیزاین در برنامه نویسی اندروید — بخش اول
==
سلام خداقوت و خسته نباشید
خواستم تشکر کنم بابت نحوه ی آموزش، توضیحات ساده و موثر هستند.