به عنوان یک توسعه دهنده که اپلیکیشن های مختلفی را در اپ استور ها دارد و مشغول بهینه سازی و رسیدگی به هزاران کاربر هست خیلی سخت میشود فریمورک و تکنولوژی هایی که هروز معرفی می شوند را بررسی کرد.
اما تغییرات و امکاناتی که تیم فلاتر ارائه میدهند به اندازه کافی جذابیت دارند که هر برنامه نویسی را وادار به امتحان کردن آنها بکنند.
در این مطلب قصد داریم راجب ویجت جدیدی که در نسخه Flutter 1.7 به نام NavigationRail معرفی شد صحبت کنیم.
اولین نسخه پایدار فلاتر در سال 2020 شامل ویژگی های بسیار جدیدی بود از بهینه شدن برنامه های نوشته شده تا معرفی ابزار های جدید.
اما جذاب ترین بخش آن معرفی کامپوننت جدید متریال دیزاین به نام NavigationRail بود که میتواند جایگزین BottomNavigationBar شود.
این ویجت در چپ یا راست صفحه به شکل عمودی قرار میگیرد و برای جا به جایی بین صفحات با فرگمنت های استفاده می شود.
برای درک بهتر میتونید تصاویر زیر را که توسط بعضی از طراحان تهیه شده است مشاهده کنید.
از NavigationRail در داخل بدنه ویجت Scafold و معمولا انتها یا ابتدای Row استفاده می شود.
در این حالت منوی ما و محتوای اصلی صفحه توسط یک خط عمودی جدا می شود.
همچنین برای ایجاد سایه و زیبا تر کردن طراحی میتونید از ویژگی elevation نیز در نویگشن ریل استفاده کنید.
نکته ای که نباید فراموش کنید در اینجا قرار دادن محتویات اصلی صفحه در ویجت Expanded است که مشکلی بابت نمایش عناصر نداشته باشید.
نحوه استفاده را در کد های زیر میتونید ببینید.
Scaffold(
body: Row(
children: <Widget>[
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.selected,
destinations: [
NavigationRailDestination(
icon: Icon(Icons.favorite_border),
selectedIcon: Icon(Icons.favorite),
label: Text('First'),
),
NavigationRailDestination(
icon: Icon(Icons.bookmark_border),
selectedIcon: Icon(Icons.book),
label: Text('Second'),
),
NavigationRailDestination(
icon: Icon(Icons.star_border),
selectedIcon: Icon(Icons.star),
label: Text('Third'),
),
],
),
VerticalDivider(thickness: 1, width: 1),
// This is the main content.
Expanded(
child: Center(
child: Text('selectedIndex: $_selectedIndex'),
),
)
],
),
);
برای اینکه بتونیم از هر ویجت استفاده کنیم باید با ویژگی و امکاناتی که دارد به طور کامل آشنا شویم.
اما قبل از بررسی ویژگی ها, یک کلاس هست که باید معرفی کنیم به اسم NavigationRailDestination.
این کلاس یک کلاس مدل است که برای ساخت آیتم های NavigationRail استفاده می شود.
همچنین این کلاس دیتای مقصدی که قصد رفتن به آن دارید را نیز نگهداری میکند.
کلاس NavigationRailDestination شامل سه ویژگی است که باهم بررسی میکنیم.
یک آبجکت معمولی از کلاس NavigationRailDestination به شکل زیر می باشد.
NavigationRailDestination(
icon: Icon(Icons.favorite_border),
selectedIcon: Icon(Icons.favorite),
label: Text('First'),
),
اما بریم سراغ ویژگی های کلاس NavigationRail که قرار بود بررسی کنیم.
با هم دیگه ویژگی های مهم NavigationRail و بررسی کردیم و برای جمع بندی با یک مثال کارمون و تموم میکنیم.
ابتدا پیش نمایش کاری که انجام میدهیم و در تصویر زیر مشاهده میکنید.
برای طراحی منو صفحه بالا میتونید از کد زیر استفاده کنید.
import 'package:flutter/material.dart';
class ScreenOne extends StatefulWidget {
ScreenOne({Key key}) : super(key: key);
@override
_ScreenOneState createState() => _ScreenOneState();
}
class _ScreenOneState extends State<ScreenOne> {
int _selectedIndex = 0;
final padding = 8.0;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff28292E),
body: Row(
children: <Widget>[
NavigationRail(
minWidth: 56.0,
groupAlignment: 1.0,
backgroundColor: Color(0xff2D3035),
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.all,
leading: Column(
children: <Widget>[
SizedBox(
height: 8,
),
Center(
child: CircleAvatar(
radius: 16,
backgroundImage: NetworkImage(
"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"),
),
),
SizedBox(
height: 108,
),
RotatedBox(
quarterTurns: -1,
child: IconButton(
icon: Icon(Icons.tune),
color: Color(0xffFCCFA8),
onPressed: () {},
),
)
],
),
selectedLabelTextStyle: TextStyle(
color: Color(0xffFCCFA8),
fontSize: 13,
letterSpacing: 0.8,
decoration: TextDecoration.underline,
decorationThickness: 2.0,
),
unselectedLabelTextStyle: TextStyle(
fontSize: 13,
letterSpacing: 0.8,
),
destinations: [
buildRotatedTextRailDestination("Popular", padding),
buildRotatedTextRailDestination("Favourites", padding),
buildRotatedTextRailDestination("Inspiration", padding),
buildRotatedTextRailDestination("All", padding),
],
),
// This is the main content.
ContentSpace(_selectedIndex)
],
),
);
}
}
NavigationRailDestination buildRotatedTextRailDestination(
String text, double padding) {
return NavigationRailDestination(
icon: SizedBox.shrink(),
label: Padding(
padding: EdgeInsets.symmetric(vertical: padding),
child: RotatedBox(
quarterTurns: -1,
child: Text(text),
),
),
);
}
class ContentSpace extends StatelessWidget {
final int _selectedIndex;
ContentSpace(this._selectedIndex);
final List<String> images = [
"https://images.unsplash.com/photo-1524758631624-e2822e304c36?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
"https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
"https://images.unsplash.com/photo-1538688525198-9b88f6f53126?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1267&q=80",
"https://images.unsplash.com/photo-1513161455079-7dc1de15ef3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80",
"https://images.unsplash.com/photo-1544457070-4cd773b4d71e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=843&q=80",
"https://images.unsplash.com/photo-1532323544230-7191fd51bc1b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80",
"https://images.unsplash.com/photo-1549488344-cbb6c34cf08b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80",
];
final List<String> titles = [
"Popular\nIdeas",
"Favourites",
"Inspiration\nIdeas",
"All"
];
@override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(24, 8, 0, 0),
child: MediaQuery.removePadding(
removeTop: true,
context: context,
child: ListView(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.calendar_today),
onPressed: () {},
),
],
),
SizedBox(
height: 24,
),
Text(titles[_selectedIndex],
style: Theme.of(context).textTheme.headline4),
SizedBox(
height: 24,
),
for (var i in images) ImageCard(i),
],
),
),
),
);
}
}
class ImageCard extends StatelessWidget {
final uri;
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.fromLTRB(0, 0, 24, 24),
child: Image.network(uri),
clipBehavior: Clip.antiAliasWithSaveLayer,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
);
}
const ImageCard(this.uri);
}