ایجاد منوهای کشویی (Drawers) در فلاتر (Flutter) — به زبان ساده

۳۵۲ بازدید
آخرین به‌روزرسانی: ۱۸ شهریور ۱۴۰۲
زمان مطالعه: ۶ دقیقه
ایجاد منوهای کشویی (Drawers) در فلاتر (Flutter) — به زبان ساده

فلاتر یک SDK برای ساخت اپلیکیشن‌های موبایل است که از سوی گوگل ارائه شده و به ایجاد اپلیکیشن‌های مدرن همراه برای iOS و اندروید با استفاده از کدبیس (تقریباً) یکسان کمک می‌کند. فلاتر در زمینه محیط‌های توسعه اپلیکیشن‌های موبایل چند پلتفرمی یک تازه‌وارد محسوب می‌شود و برخلاف دیگر فریمورک‌ها مانند React Native از جاوا اسکریپت استفاده نمی‌کند، بلکه از DART به عنوان زبان برنامه‌نویسی خود بهره جسته است. در این مطلب به معرفی روش ایجاد منوهای کشویی در فلاتر می‌پردازیم.

اگر می‌خواهید با فریمورک فلاتر بیشتر آشنا شوید، پیشنهاد می‌کنیم ابتدا مطلب جامع گوگل فلاتر (Flutter) از صفر تا صد — ساخت اپلیکیشن به کمک ویجت را مطالعه کنید.

منوی کشویی در اپلیکیشن‌های همراه، یک صفحه کناری است که عموماً شامل آیتم‌های منو است و در زمان باز شدن حدود نیمی از صفحه را اشغال می‌کند. اگر تاکنون از اپلیکیشن‌هایی مانند توییتر یا Gmail استفاده کرده باشید، حتماً می‌دانید که در مورد چه چیزی صحبت می‌کنیم.

ایجاد یک منوی کشویی خالی

برای ساخت یک منوی کشویی ابتدا باید یک منوی خالی ایجاد کنیم. به این منظور همانند همه اپلیکیشن‌های فلاتر که از طراحی متریال برخوردار هستند، یک MaterialApp پایه ایجاد خواهیم کرد. این MaterialApp زمینه‌ای است که یک Scaffold را با Drawer در خود جای خواهد داد.

کد یک MaterialApp پایه به صورت زیر است:

1class MyApp extends StatelessWidget {
2  @override
3  Widget build (BuildContext ctxt) {
4    return new MaterialApp(
5      home: new DWidget()
6    );
7  }
8}

در کد فوق، DWidget یک ویجت است که منوی کشویی ما را در خود جای خواهد داد. لازم به ذکر است که drawers بخشی از Scaffold به همراه appBar و body هستند. زمانی که drawer را به Scaffold اضافه کردید، یک آیتم منوی سه خطی روی گوشه چپ-بالای نوار اپلیکیشن ایجاد می‌کند که با کلیک روی آن می‌توانید صفحه drawer را مشاهده کنید.

کد ابتدایی آن به صوت زیر است:

1class DWidget extends StatelessWidget {
2  @override
3  Widget build (BuildContext ctxt) {
4    return new Scaffold(
5      drawer: new Drawer(
6        child: new Text("\n\n\nDrawer Is Here"),
7      ),
8      appBar: new AppBar(
9        title: new Text("Drawer Demo"),
10      ),
11      body: new Text("Drawer Body"),
12    );
13  }
14}

این کد یک اپلیکیشن می‌سازد که یک منوی کشویی خالی ابتدایی مانند تصویر زیر ایجاد می‌کند:

منوهای کشویی
یک منوی کشویی خالی

همان طور که احتمالاً متوجه شده‌اید، drawer مقادیر :child (و نه :children) می‌پذیرد و این بدان معنی است که هر زمان می‌توانیم تنها یک ویجت درون drawer خود داشته باشیم.

برای این که بتوانیم بیش از یک ویجت داشته باشیم، باید از ویجت‌هایی مانند Column استفاده کنیم که قادر به نگهداری از چند ویجت فرزند هستند. کد drawer زمانی که حاوی ویجت Column باشد به صورت زیر خواهد بود:

1drawer: new Drawer(
2  child: new Column(
3    children: <Widget>[
4      new Text("\n\n\n\Drawer Is Here => 1"),
5      new Text("Drawer Is Here => 2"),
6      new Text("Drawer Is Here => 3"),
7    ],
8  )
9),

این کد سه خط متن را در drawer نمایش می‌دهد.

افزودن هدر Drawer

اکنون می‌دانیم که drawer-ها چه هستند و چگونه ایجاد می‌شوند. با این وجود اگر بخواهیم منوهای کشویی خود را با منوهای کشویی اپلیکیشن‌های توییتر و جیمیل مقایسه کنیم، متوجه خواهیم شد که آن drawer-ها همواره به همراه یک هدر ارائه می‌شوند که تقریباً 20 درصد از فضای فوقانی منو را اشغال می‌کند.

در فلاتر، می‌توانیم هدر مشابهی را با استفاده از ویجت DrawerHeader ایجاد کنیم. این ویجت یک child می‌گیرد و امکان تزیین هدر را به ما می‌دهد. در مثالی که در ادامه ارائه شده است از DrawerHeader استفاده کرده‌ایم، به طوری که می‌توانیم مرز کامل ویجت را تمییز دهیم. کد DrawerHeader به صورت است:

1drawer: new Drawer(
2  child:new DrawerHeader(
3    child: new Text("DRAWER HEADER.."),
4    decoration: new BoxDecoration(
5      color: Colors.orange
6    ),
7  )
8),

اکنون منوی کشویی ما به صورت زیر در آمده است:

منوهای کشویی

البته مطمئناً از این که می‌بینید هدر تمام فضای منو را اشغال کرده است شگفت‌زده شده‌اید، در حالی که به طور معمول باید 20 درصد فضای فوقانی منو را اشغال کند. دلیل وقوع این وضعیت آن است که child در drawer تنها یک DrawerHeader دارد و هیچ عنصر دیگری هنوز اضافه نشده است.

جابجایی هدر Drawer به سمت بالا

برای جابجایی هدر drawer به سمت بالای منوی کشویی، باید از ویجت‌هایی مانند Column یا ListView استفاده کنیم که شامل چندین ویجت هستند. ما قصد داریم از ListView در اینجا استفاده کنیم چون Column همه فضای موجود را به صوت یکسان اشغال نمی‌کند و بدین ترتیب بخش‌هایی از فضای اشغال نشده روی صفحه باقی می‌گذارد. روش استفاده از ListView درون یک Drawer به صورت زیر است:

1drawer: new Drawer(
2  child: new ListView(
3    children: <Widget>[
4      new DrawerHeader(
5        child: new Text("DRAWER HEADER.."),
6        decoration: new BoxDecoration(
7            color: Colors.orange
8        ),
9      )
10    ],
11  )
12),

نتیجه نوشتن کد فوق در اپلیکیشن حاصل، به صورت زیر خواهد بود:

منوهای کشویی

اکنون به چیزی که به دنبالش بودیم، دست یافتیم. این وضعیت به هدر منوهای کشویی اپلیکیشن‌هایی مانند جیمیل و توییتر نیز شبیه شده است.

اینک می‌توانیم هدر را به هر ترتیبی که می‌خواهیم تزیین کنیم و به این منظور آیتم‌ها و لینک‌های زیادی وجود دارند. در مورد تزیین هدر در مطالب بعدی صبحت خواهیم کرد؛ در این نوشته توجه خود را معطوف به تکمیل کارکرد منوی کشویی و افزودن برخی آیتم‌های کاربردی می‌کنیم.

افزودن آیتم‌های کاربردی در منوی کشویی

از آنجا که می‌خواهیم برخی کاربردها در زمان انتخاب (یا تپ کردن) آیتم‌های منوی کشویی اجرا شوند باید از ویجت‌هایی استفاده کنیم که بتوانند متد onTap را مدیریت کنند. در غیر این صوت باید یک کانتینر پیرامون ویجت‌هایی که ژست‌ها را مدیریت می‌کنند ایجاد کنیم.

با این وجود، استفاده از دستگیره توکار onTap در این مثال ارجحیت دارد، زیرا استفاده از آن آسان‌تر است. ویجتی که می‌توان درون ListView استفاده کرد ListTile نام دارد. در ادامه چند آیتم را با استفاده از ListTile ایجاد می‌کنیم و اکشن‌های متناظر را با استفاده از متد ()onTap اضافه می‌کنیم. اکشن‌های زیادی وجود دارند که می‌توان روی ()onTAP اضافه کرد و در اغلب موارد هدف ما بارگذاری یک صفحه جدید با ()onTAP است.

بارگذاری صفحه جدید

در این بخش چند صفحه (یعنی ویجت) ایجاد می‌کنیم و آن‌ها را در نتیجه یک اکشن از سوی کاربر نهایی روی منوی کشویی بارگذاری می‌کنیم.

1class FirstPage extends StatelessWidget {
2  @override
3  Widget build(BuildContext ctxt) {
4    return new Scaffold(
5      appBar: new AppBar(title: new Text("First Page"),),
6      body: new Text("I belongs to First Page"),
7    );
8  }
9}
10
11class SecondPage extends StatelessWidget {
12  @override
13  Widget build(BuildContext ctxt) {
14    return new Scaffold(
15      appBar: new AppBar(title: new Text("Second Page"),),
16      body: new Text("I belongs to Second Page"),
17    );
18  }
19}

این صفحه‌ها را با اکشن ()onTap روی LostTile بارگذاری می‌کنیم. بدین ترتیب کد کامل منوی کشویی به صورت زیر درمی‌آید:

1drawer: new Drawer(
2  child: new ListView(
3    children: <Widget>[
4      new DrawerHeader(
5        child: new Text("DRAWER HEADER.."),
6        decoration: new BoxDecoration(
7            color: Colors.orange
8        ),
9      ),
10      new ListTile(
11        title: new Text("Item => 1"),
12        onTap: () { 
13          Navigator.push(ctxt,
14              new MaterialPageRoute(builder: (ctxt) => new FirstPage()));
15        },
16      ),
17      new ListTile(
18        title: new Text("Item => 2"),
19        onTap: () {
20          Navigator.push(ctxt,
21              new MaterialPageRoute(builder: (ctxt) => new SecondPage()));
22        },
23      ),
24    ],
25  )
26),

روش کارکرد اکشن‌ها در اپلیکیشن در این زمان به صورت زیر است:

منوهای کشویی

عدم نمایش منوی کشویی

اینک ما موفق شدیم صفحه‌های جدیدی را با کلیک روی آیتم‌های منوی کشویی بارگذاری کنیم؛ با این وجود زمانی که تلاش کنیم به صفحه اصلی بازگردیم، می‌بینیم که منوی کشویی همچنان در آنجا حضور دارد. این وضعیت در تصویر فوق نیز مشخص است. این وضعیت آزاردهنده‌ای است، زیرا ما نمی‌خواهیم منوی کشویی در آنجا باقی بماند؛ مگر این که آن‌ها را به طور صریح مجدداً بارگذاری کنیم.

برای رفع این مشکل باید پیش از بارگذاری صفحه حدید از سوی ()Navigator.pop، منوی کشویی را حذف کنیم. بدین منظور باید کد ()onTap را به صورت زیر بنویسیم:

1onTap: () {
2  Navigator.pop(ctxt);
3  Navigator.push(ctxt,
4      new MaterialPageRoute(builder: (ctxt) => new FirstPage()));
5},

بدین ترتیب هنگامی که صفحه نهایی باز می‌شود، منوی کشویی در صفحه اصلی باقی نمی‌ماند.

منوهای کشویی

فعال کردن منوی کشویی در تمامی صفحات

در زمان طراحی اپلیکیشن، عموماً قصدمان بر این است که اکشن‌های رایج را روی منوی کشویی قرار دهیم و لذا منوی کشویی باید در همه صفحه‌های اپلیکیشن حضور داشته باشد. این کار از طریق اطمینان یافتن از این که منوهای کشویی روی همه Scaffold-ها در همه صفحه‌های اپلیکیشن وجود دارند، میسر خواهد بود.

معنی عملی گفته فوق این است که می‌توانیم کد drawer را در ویجت‌های «بی‌حالت» (Stateless) مجزا به صورت زیر داشته باشیم:

1class DrawerOnly extends StatelessWidget {
2  @override
3  Widget build (BuildContext ctxt) {
4    return new Drawer(
5        child: new ListView(
6          children: <Widget>[
7            new DrawerHeader(
8              child: new Text("DRAWER HEADER.."),
9              decoration: new BoxDecoration(
10                  color: Colors.orange
11              ),
12            ),
13            new ListTile(
14              title: new Text("Item => 1"),
15              onTap: () {
16                Navigator.pop(ctxt);
17                Navigator.push(ctxt,
18                    new MaterialPageRoute(builder: (ctxt) => new FirstPage()));
19              },
20            ),
21            new ListTile(
22              title: new Text("Item => 2"),
23              onTap: () {
24                Navigator.pop(ctxt);
25                Navigator.push(ctxt,
26                    new MaterialPageRoute(builder: (ctxt) => new SecondPage()));
27              },
28            ),
29          ],
30        )
31    );
32  }
33}

و از کد زیر درون ویجت‌های خود به همراه Scaffold استفاده کنیم:

1class DWidget extends StatelessWidget {
2  @override
3  Widget build (BuildContext ctxt) {
4    return new Scaffold(
5      drawer: new DrawerOnly(),   // New Line
6      appBar: new AppBar(
7        title: new Text("Drawer Demo"),
8      ),
9      body: new Text("Drawer Body"),
10    );
11  }
12}
13
14class FirstPage extends StatelessWidget {
15  @override
16  Widget build(BuildContext ctxt) {
17    return new Scaffold(
18      drawer: new DrawerOnly(),    // new Line
19      appBar: new AppBar(title: new Text("First Page"),),
20      body: new Text("I belongs to First Page"),
21    );
22  }
23}
24
25class SecondPage extends StatelessWidget {
26  @override
27  Widget build(BuildContext ctxt) {
28    return new Scaffold(
29      drawer: new DrawerOnly(),    // New Line
30      appBar: new AppBar(title: new Text("Second Page"),),
31      body: new Text("I belongs to Second Page"),
32    );
33  }
34}

اپلیکیشن حاصل، منوهای کشویی خواهد داشت که روی همه صفحه‌ها در دسترس ما قرار دارند:

منوهای کشویی
منوهای کشویی در همه صفحه‌ها

بدین ترتیب به پایان این نوشته با موضوع معرفی منوهای کشویی در اپلیکیشن‌های فلاتر می‌رسیم. امیدواریم از مطالعه این مطلب بهره آموزشی لازم را کسب کرده باشید. شما می‌توانید هرگونه دیدگاه یا پیشنهاد خود را در بخش نظرات این نوشته با ما و دیگر خوانندگان مجله فرادرس در میان بگذارید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۲ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
proandroiddev
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *