021-88881776

آموزش پیمایش (Navigation) و مسیرها (Routes) در Flutter

در آموزش Flutter، یکی از مباحث کلیدی و ضروری، پیمایش (Navigation) و مسیرها (Routes) در Flutter است که به شما امکان می‌دهد تا تجربه کاربری روان و بهینه‌ای را ارائه دهید. در این مقاله، به بررسی جامع و کامل پیمایش (Navigation) و مسیرها (Routes) در Flutter خواهیم پرداخت و تمامی جنبه‌های این موضوع را از سطح مبتدی تا پیشرفته پوشش می‌دهیم.

پیمایش در Flutter

پیمایش (Navigation) و مسیرها (Routes) در Flutter به فرآیندی اشاره دارد که کاربران بتوانند بین صفحات مختلف اپلیکیشن شما حرکت کنند. در Flutter، هر صفحه معمولاً به عنوان یک ویجت جداگانه تعریف می‌شود و پیمایش (Navigation) و مسیرها (Routes) در Flutter این امکان را فراهم می‌کند تا به سادگی بین این ویجت‌ها جابجا شوید. این فرآیند نقش بسیار مهمی در تجربه کاربری اپلیکیشن دارد و به توسعه‌دهندگان اجازه می‌دهد تا ساختار اپلیکیشنی منظم و قابل نگهداری ایجاد کنند.

اهمیت پیمایش در اپلیکیشن‌های موبایل

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

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

مفهوم مسیرها (Routes) در Flutter

در پیمایش (Navigation) و مسیرها (Routes) در Flutter، مسیرها به عنوان شناسه‌های یکتا برای صفحات مختلف اپلیکیشن عمل می‌کنند. هر مسیر می‌تواند به یک ویجت خاص اشاره داشته باشد که نمایانگر یک صفحه یا بخش از اپلیکیشن است. مسیرها می‌توانند به صورت مستقیم یا نام‌گذاری شده تعریف شوند:

مسیرهای مستقیم (Direct Routes): مسیرهایی که به طور مستقیم به یک ویجت مشخص اشاره دارند.
مسیرهای نام‌گذاری شده (Named Routes): مسیرهایی که با یک نام مشخص تعریف می‌شوند و مدیریت آنها در پروژه‌های بزرگ‌تر ساده‌تر است.

نحوه عملکرد Navigator در Flutter

در پیمایش (Navigation) و مسیرها (Routes) در Flutter، کلاس Navigator نقش کلیدی را ایفا می‌کند. Navigator یک استک (Stack) از مسیرها را مدیریت می‌کند که به شما امکان می‌دهد صفحات را به صورت داینامیک به اپلیکیشن اضافه یا از آن حذف کنید. اصول اولیه عملکرد Navigator به شرح زیر است:

Push: اضافه کردن یک مسیر جدید به بالای استک و نمایش آن به کاربر.
Pop: حذف مسیر بالای استک و بازگشت به مسیر قبلی.

تفاوت بین Push و PushReplacement

علاوه بر Navigator.push و Navigator.pop، Flutter امکانات دیگری نیز برای مدیریت مسیرها ارائه می‌دهد:

Navigator.pushReplacement: جایگزین کردن مسیر فعلی با مسیر جدید بدون نگه داشتن مسیر قبلی در استک.
Navigator.pushAndRemoveUntil: اضافه کردن مسیر جدید و حذف تمامی مسیرهای قبلی تا رسیدن به یک شرط مشخص.

مثال عملی از پیمایش ساده

برای درک بهتر پیمایش (Navigation) و مسیرها (Routes) در Flutter، بیایید یک مثال ساده را بررسی کنیم:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'پیمایش ساده',
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اول'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('رفتن به صفحه دوم'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondPage()),
            );
          },
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('بازگشت به صفحه اول'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

در این مثال:

FirstPage: صفحه اول اپلیکیشن که شامل یک دکمه برای رفتن به صفحه دوم است.
SecondPage: صفحه دوم اپلیکیشن که شامل یک دکمه برای بازگشت به صفحه اول است.
با استفاده از Navigator.push، کاربر به صفحه دوم منتقل می‌شود و با Navigator.pop می‌تواند به صفحه اول بازگردد.

مدیریت پیچیده‌تر مسیرها با استفاده از RouteGenerator

برای پروژه‌های بزرگ‌تر، مدیریت مسیرها به صورت مستقیم می‌تواند پیچیده و ناخوانا شود. در این موارد، استفاده از یک RouteGenerator می‌تواند کمک‌کننده باشد. RouteGenerator به شما امکان می‌دهد تا تمامی مسیرهای اپلیکیشن را در یک مکان مرکزی مدیریت کنید.

مثال RouteGenerator:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Route Generator Example',
      initialRoute: '/',
      onGenerateRoute: RouteGenerator.generateRoute,
    );
  }
}

class RouteGenerator {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(builder: (_) => FirstPage());
      case '/second':
        return MaterialPageRoute(builder: (_) => SecondPage());
      default:
        return MaterialPageRoute(builder: (_) => UndefinedPage());
    }
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اول'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('رفتن به صفحه دوم'),
          onPressed: () {
            Navigator.pushNamed(context, '/second');
          },
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('بازگشت به صفحه اول'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

class UndefinedPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه نامشخص'),
      ),
      body: Center(
        child: Text('صفحه مورد نظر یافت نشد!'),
      ),
    );
  }
}

در این مثال:

RouteGenerator: تمامی مسیرهای اپلیکیشن را مدیریت می‌کند و صفحات مربوطه را بر اساس نام مسیر بازمی‌گرداند.
UndefinedPage: صفحه‌ای که در صورت وارد شدن به مسیر نامشخص نمایش داده می‌شود.

پیمایش (Navigation) و مسیرها (Routes) در Flutter ابزارهای قدرتمندی هستند که به توسعه‌دهندگان امکان می‌دهند اپلیکیشن‌های پیچیده و منظم را با ساختار مناسب ایجاد کنند. با درک عمیق‌تر از مفاهیم پایه و پیشرفته پیمایش، می‌توانید تجربه کاربری بهتری را برای کاربران خود فراهم کنید و اپلیکیشنی با قابلیت نگهداری و توسعه آسان‌تر ایجاد نمایید.

استفاده از Navigator.push و Navigator.pop

یکی از ساده‌ترین و پرکاربردترین روش‌ها برای مدیریت پیمایش (Navigation) و مسیرها (Routes) در Flutter، استفاده از متدهای Navigator.push و Navigator.pop است. این دو متد به شما امکان می‌دهند به راحتی بین صفحات مختلف اپلیکیشن خود حرکت کنید و تجربه کاربری بهتری را ارائه دهید.

مفهوم Navigator.push و Navigator.pop

Navigator.push: این متد برای انتقال به یک صفحه جدید استفاده می‌شود. با استفاده از Navigator.push، یک مسیر جدید به استک (Stack) مسیرها اضافه می‌شود و صفحه جدید به نمایش در می‌آید.

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

نحوه کارکرد Navigator.push و Navigator.pop

در پیمایش (Navigation) و مسیرها (Routes) در Flutter، Navigator یک استک از مسیرها را مدیریت می‌کند. وقتی از Navigator.push برای انتقال به یک صفحه جدید استفاده می‌کنید، آن صفحه به بالای استک اضافه می‌شود. به همین ترتیب، با استفاده از Navigator.pop، آخرین مسیر از استک حذف شده و کاربر به مسیر قبلی بازمی‌گردد.

مثال عملی

برای درک بهتر نحوه استفاده از Navigator.push و Navigator.pop، بیایید یک مثال عملی را بررسی کنیم:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'پیمایش ساده با Navigator',
      home: HomePage(),
    );
  }
}

// صفحه اصلی
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اصلی'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('رفتن به صفحه دوم'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondPage()),
            );
          },
        ),
      ),
    );
  }
}

// صفحه دوم
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('بازگشت به صفحه اصلی'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

توضیحات کد:
صفحه اصلی (HomePage):

دارای یک دکمه با متن “رفتن به صفحه دوم” است.
با فشردن دکمه، متد Navigator.push فراخوانی می‌شود که صفحه دوم را به استک مسیرها اضافه می‌کند و به صفحه دوم منتقل می‌شود.
صفحه دوم (SecondPage):

دارای یک دکمه با متن “بازگشت به صفحه اصلی” است.
با فشردن دکمه، متد Navigator.pop فراخوانی می‌شود که آخرین مسیر (صفحه دوم) را از استک حذف کرده و کاربر را به صفحه اصلی بازمی‌گرداند.

نکات کلیدی در استفاده از Navigator.push و Navigator.pop

Context مناسب:

برای استفاده از Navigator.push و Navigator.pop باید context مناسبی داشته باشید. معمولاً در داخل ویجت‌های صفحه استفاده می‌شود.
استفاده از MaterialPageRoute:

MaterialPageRoute یک کلاس مسیر (Route) است که به شما اجازه می‌دهد صفحه جدید را با انیمیشن‌های پیش‌فرض Flutter نمایش دهید.
می‌توانید از کلاس‌های دیگر مسیر مانند CupertinoPageRoute برای انیمیشن‌های مخصوص iOS استفاده کنید.

بازگشت به صفحه قبلی:

استفاده از Navigator.pop به طور خودکار صفحه فعلی را از استک حذف می‌کند و کاربر را به صفحه قبلی بازمی‌گرداند.
همچنین می‌توانید داده‌ای را هنگام بازگشت از صفحه دوم به صفحه اصلی ارسال کنید.

ارسال داده با Navigator.push و Navigator.pop

یکی از قابلیت‌های مهم در پیمایش (Navigation) و مسیرها (Routes) در Flutter، ارسال داده بین صفحات مختلف است. می‌توانید داده‌ای را از صفحه اصلی به صفحه دوم ارسال کرده و بالعکس دریافت کنید.

مثال ارسال داده:

// ارسال داده از صفحه اصلی به صفحه دوم
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => SecondPage(data: 'سلام از صفحه اصلی'),
  ),
);

دریافت داده در صفحه دوم:

class SecondPage extends StatelessWidget {
  final String data;

  SecondPage({required this.data});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: Text(data),
      ),
    );
  }
}

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

استفاده از Navigator.pushReplacement

گاهی اوقات ممکن است بخواهید صفحه فعلی را با صفحه جدید جایگزین کنید، بدون اینکه صفحه فعلی در استک مسیرها باقی بماند. برای این منظور می‌توانید از Navigator.pushReplacement استفاده کنید.

مثال:

Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (context) => NewPage()),
);

در این حالت، صفحه فعلی از استک حذف شده و صفحه جدید جایگزین آن می‌شود.

مدیریت چندین مسیر با Navigato

در پروژه‌های بزرگ‌تر، ممکن است نیاز به مدیریت چندین مسیر و انتقالات پیچیده بین صفحات داشته باشید. در این موارد، استفاده از Navigator به همراه روش‌های مختلف مدیریت مسیرها می‌تواند بسیار مفید باشد.

مثال انتقال به چندین صفحه:

// انتقال از صفحه اول به صفحه دوم و سپس به صفحه سوم
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
).then((_) {
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => ThirdPage()),
  );
});

در این مثال، بعد از بازگشت از صفحه دوم، به طور خودکار به صفحه سوم منتقل می‌شوید. استفاده از Navigator.push و Navigator.pop یکی از پایه‌های اصلی در پیمایش (Navigation) و مسیرها (Routes) در Flutter است. با درک و تسلط بر این متدها، می‌توانید به راحتی بین صفحات مختلف اپلیکیشن خود حرکت کنید و تجربه کاربری بهتری را برای کاربران فراهم کنید. همچنین، با استفاده از قابلیت‌های پیشرفته‌تر مانند ارسال داده و جایگزینی مسیرها، می‌توانید اپلیکیشن‌های پیچیده‌تر و حرفه‌ای‌تری را توسعه دهید.

مدیریت مسیرها با نام (Named Routes)

برای پروژه‌های بزرگ‌تر، استفاده از مسیرهای نام‌گذاری شده (Named Routes) می‌تواند مدیریت پیمایش (Navigation) و مسیرها (Routes) در Flutter را ساده‌تر و سازمان‌یافته‌تر کند. در این روش، به هر مسیر یک نام مشخص اختصاص داده می‌شود و از این نام‌ها برای پیمایش بین صفحات استفاده می‌شود. این رویکرد باعث می‌شود که کد شما خواناتر و نگهداری آن آسان‌تر شود، به‌ویژه زمانی که تعداد صفحات اپلیکیشن افزایش می‌یابد.

مزایای استفاده از مسیرهای نام‌گذاری شده

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

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

مدیریت آسان‌تر در پروژه‌های بزرگ: در پروژه‌های با تعداد زیادی صفحه، مسیرهای نام‌گذاری شده به کاهش پیچیدگی و افزایش قابلیت نگهداری کمک می‌کنند.

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

نحوه تعریف مسیرهای نام‌گذاری شده

برای استفاده از مسیرهای نام‌گذاری شده در Flutter، باید آن‌ها را در پارامتر routes از ویجت MaterialApp تعریف کنید. به این صورت:

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'پیمایش با مسیرهای نام‌گذاری شده',
      initialRoute: '/',
      routes: {
        '/': (context) => HomePage(),
        '/second': (context) => SecondPage(),
      },
    );
  }
}

در این مثال:

مسیر ‘/’ به ویجت HomePage اختصاص داده شده است که به عنوان مسیر اولیه (initialRoute) تعیین شده است.
مسیر ‘/second’ به ویجت SecondPage اختصاص داده شده است.

استفاده از Navigator.pushNamed برای پیمایش

پس از تعریف مسیرهای نام‌گذاری شده، می‌توانید از متد Navigator.pushNamed برای پیمایش به صفحات مختلف استفاده کنید. به عنوان مثال:

// صفحه اصلی
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اصلی'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('رفتن به صفحه دوم'),
          onPressed: () {
            Navigator.pushNamed(context, '/second');
          },
        ),
      ),
    );
  }
}

// صفحه دوم
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('بازگشت به صفحه اصلی'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

در این مثال:

با فشردن دکمه در HomePage، متد Navigator.pushNamed فراخوانی شده و به مسیر ‘/second’ هدایت می‌شویم.
در SecondPage، با فشردن دکمه بازگشت به صفحه اصلی انجام می‌شود.

ارسال داده با مسیرهای نام‌گذاری شده

یکی از قابلیت‌های مهم در پیمایش (Navigation) و مسیرها (Routes) در Flutter، ارسال داده بین صفحات است. با مسیرهای نام‌گذاری شده نیز می‌توانید این کار را انجام دهید. برای این منظور، می‌توانید از آرگومان‌های مسیر (arguments) استفاده کنید.

تعریف داده برای ارسال:

// صفحه اصلی
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اصلی'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('رفتن به صفحه دوم با داده'),
          onPressed: () {
            Navigator.pushNamed(
              context,
              '/second',
              arguments: 'سلام از صفحه اصلی',
            );
          },
        ),
      ),
    );
  }
}

دریافت داده در صفحه مقصد:

// صفحه دوم
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // دریافت آرگومان‌ها
    final args = ModalRoute.of(context)!.settings.arguments as String;

    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(args),
            SizedBox(height: 20),
            ElevatedButton(
              child: Text('بازگشت به صفحه اصلی'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),
    );
  }
}

در این مثال:

در HomePage، با فراخوانی Navigator.pushNamed و ارسال آرگومان ‘سلام از صفحه اصلی’، داده‌ای به SecondPage ارسال می‌شود.
در SecondPage، با استفاده از ModalRoute.of(context)!.settings.arguments، داده دریافت شده و نمایش داده می‌شود.

مدیریت مسیرهای پیچیده‌تر با RouteGenerator

در پروژه‌های بزرگ‌تر، تعریف تمامی مسیرها به صورت مستقیم در MaterialApp می‌تواند باعث افزایش پیچیدگی شود. برای مدیریت بهتر مسیرها، می‌توانید از یک کلاس RouteGenerator استفاده کنید که تمامی مسیرها را در یک مکان مرکزی مدیریت می‌کند.

تعریف RouteGenerator:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Route Generator Example',
      initialRoute: '/',
      onGenerateRoute: RouteGenerator.generateRoute,
    );
  }
}

class RouteGenerator {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(builder: (_) => HomePage());
      case '/second':
        // دریافت آرگومان‌ها
        final args = settings.arguments as String;
        return MaterialPageRoute(builder: (_) => SecondPage(data: args));
      default:
        // صفحه مسیر نامشخص
        return MaterialPageRoute(builder: (_) => UndefinedPage());
    }
  }
}

// صفحه اصلی
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اصلی'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('رفتن به صفحه دوم با داده'),
          onPressed: () {
            Navigator.pushNamed(
              context,
              '/second',
              arguments: 'سلام از صفحه اصلی',
            );
          },
        ),
      ),
    );
  }
}

// صفحه دوم
class SecondPage extends StatelessWidget {
  final String data;

  SecondPage({required this.data});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(data),
            SizedBox(height: 20),
            ElevatedButton(
              child: Text('بازگشت به صفحه اصلی'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),
    );
  }
}

// صفحه مسیر نامشخص
class UndefinedPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه نامشخص'),
      ),
      body: Center(
        child: Text('صفحه مورد نظر یافت نشد!'),
      ),
    );
  }
}

در این مثال:

کلاس RouteGenerator تمامی مسیرهای اپلیکیشن را مدیریت می‌کند.
در متد generateRoute، مسیرها بر اساس نام آن‌ها مشخص می‌شوند و صفحه مربوطه بازگردانده می‌شود.
در صورت وارد شدن به مسیر نامشخص، صفحه UndefinedPage نمایش داده می‌شود.

مدیریت ارورهای مسیر نامشخص

در مواقعی که کاربر به یک مسیر نامشخص هدایت می‌شود، می‌توانید یک صفحه خطا نمایش دهید تا تجربه کاربری مناسبی را فراهم کنید. در مثال قبلی، کلاس UndefinedPage برای این منظور تعریف شده است.

نکات کلیدی در استفاده از مسیرهای نام‌گذاری شده

تعریف مسیرها در MaterialApp: حتماً تمامی مسیرهای نام‌گذاری شده را در MaterialApp یا CupertinoApp تعریف کنید تا اپلیکیشن بتواند به درستی به آن‌ها هدایت شود.

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

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

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

استفاده از RouteGenerator برای پروژه‌های بزرگ: در پروژه‌های با تعداد زیادی مسیر، استفاده از یک کلاس مدیریت مسیر مانند RouteGenerator می‌تواند به سازمان‌دهی بهتر کد کمک کند.

استفاده از مسیرهای نام‌گذاری شده (Named Routes) در پیمایش (Navigation) و مسیرها (Routes) در Flutter، به ویژه در پروژه‌های بزرگ‌تر، مزایای فراوانی دارد. با تعریف مسیرها به صورت مرکزی و استفاده از نام‌های معنادار، می‌توانید کدی خوانا، سازمان‌یافته و قابل نگهداری ایجاد کنید. همچنین، قابلیت ارسال داده بین صفحات و مدیریت ارورهای مسیر نامشخص، تجربه کاربری بهتری را برای کاربران اپلیکیشن شما فراهم می‌کند. با تسلط بر این روش، می‌توانید اپلیکیشن‌های پیچیده‌تر و حرفه‌ای‌تری را با Flutter توسعه دهید.

Navigation Drawer و Bottom Navigation

برای ایجاد ناوبری چند صفحه‌ای در اپلیکیشن‌های Flutter، می‌توانید از Navigation Drawer و Bottom Navigation استفاده کنید. این دو روش به شما امکان می‌دهند تا به راحتی بین بخش‌های مختلف اپلیکیشن جابجا شوید و تجربه کاربری بهتری را ارائه دهید. در این بخش، به تفصیل به هر یک از این روش‌ها پرداخته و نحوه پیاده‌سازی آن‌ها را با مثال‌های عملی بررسی می‌کنیم.

ساخت منوی کناری (Drawer)

Navigation Drawer یک منوی کناری است که معمولاً از سمت چپ صفحه باز می‌شود و شامل گزینه‌های مختلفی برای پیمایش به صفحات مختلف اپلیکیشن است. این منو به کاربران امکان می‌دهد به سرعت به بخش‌های مختلف اپلیکیشن دسترسی پیدا کنند بدون اینکه نیاز به باز کردن چندین صفحه داشته باشند.

مزایای استفاده از Navigation Drawer

فضای کم‌حجم: منوی کناری فضای کمی از صفحه نمایش را اشغال می‌کند و می‌تواند تعداد زیادی گزینه را در خود جای دهد.
دسترسی سریع: کاربران می‌توانند به سرعت به بخش‌های مختلف اپلیکیشن دسترسی پیدا کنند.
سازگاری با طراحی‌های مختلف: Navigation Drawer با انواع طراحی‌های اپلیکیشن سازگار است و می‌تواند به راحتی با استایل‌های مختلف هماهنگ شود.

مثال عملی: ایجاد Navigation Drawer

برای درک بهتر نحوه پیاده‌سازی Navigation Drawer در پیمایش (Navigation) و مسیرها (Routes) در Flutter، بیایید یک مثال عملی را بررسی کنیم.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'پیمایش با Navigation Drawer',
      initialRoute: '/',
      routes: {
        '/': (context) => HomePage(),
        '/second': (context) => SecondPage(),
      },
    );
  }
}

// صفحه اصلی
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اصلی'),
      ),
      drawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: <Widget>[
            DrawerHeader(
              child: Text(
                'منوی کناری',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                ),
              ),
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
            ),
            ListTile(
              leading: Icon(Icons.home),
              title: Text('صفحه اول'),
              onTap: () {
                Navigator.pushNamed(context, '/');
              },
            ),
            ListTile(
              leading: Icon(Icons.business),
              title: Text('صفحه دوم'),
              onTap: () {
                Navigator.pushNamed(context, '/second');
              },
            ),
          ],
        ),
      ),
      body: Center(
        child: Text('محتوای صفحه اصلی'),
      ),
    );
  }
}

// صفحه دوم
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دوم'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('بازگشت به صفحه اصلی'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

توضیحات کد:
تعریف Drawer:

در ویجت HomePage، از ویژگی drawer در Scaffold استفاده شده است.
Drawer شامل یک ListView است که شامل DrawerHeader و چند ListTile برای گزینه‌های مختلف منو می‌باشد.
DrawerHeader:

قسمت بالایی منو که معمولاً شامل لوگو یا عنوان منو است.
در این مثال، یک متن ساده با پس‌زمینه آبی نمایش داده شده است.
ListTile:

هر ListTile نمایانگر یک گزینه در منو است.
با فشردن هر گزینه، متد Navigator.pushNamed فراخوانی شده و به صفحه مربوطه هدایت می‌شوید.
بازگشت از صفحه دوم:

در SecondPage، با فشردن دکمه “بازگشت به صفحه اصلی”، متد Navigator.pop فراخوانی شده و به صفحه اصلی بازمی‌گردید.

نکات کلیدی در استفاده از Navigation Drawer

استفاده از ListTile با آیکون‌ها:

افزودن آیکون به هر گزینه منو می‌تواند ظاهر جذاب‌تری به منو بدهد و به کاربران در شناسایی گزینه‌ها کمک کند.
مدیریت مسیرها:

استفاده از مسیرهای نام‌گذاری شده (Named Routes) با Navigator.pushNamed باعث می‌شود که مدیریت مسیرها در پروژه‌های بزرگ‌تر ساده‌تر شود.
قفل‌گذاری Drawer:

در برخی موارد، ممکن است بخواهید دسترسی به Drawer را در برخی صفحات محدود کنید. برای این منظور می‌توانید ویژگی‌های Scaffold را تنظیم کنید.
استفاده از Drawer در صفحات مختلف:

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

پیاده‌سازی Bottom Navigation Bar برای چند صفحه

Bottom Navigation Bar یک نوار ناوبری در پایین صفحه است که به کاربران امکان می‌دهد بین چندین صفحه اصلی جابجا شوند. این روش به ویژه در اپلیکیشن‌هایی که چندین بخش اصلی دارند، بسیار مفید است و تجربه کاربری بهتری را فراهم می‌کند.

مزایای استفاده از Bottom Navigation Bar

دسترسی سریع: کاربران می‌توانند به راحتی بین بخش‌های اصلی اپلیکیشن جابجا شوند.
طراحی جذاب: Bottom Navigation Bar می‌تواند ظاهر جذابی به اپلیکیشن بدهد و با طراحی‌های مختلف هماهنگ شود.
پشتیبانی از چندین صفحه: این نوار ناوبری به شما امکان می‌دهد تا چندین صفحه اصلی را مدیریت کنید بدون اینکه نیاز به پیمایش پیچیده داشته باشید.

مثال عملی: پیاده‌سازی Bottom Navigation Bar

برای پیاده‌سازی Bottom Navigation Bar در پیمایش (Navigation) و مسیرها (Routes) در Flutter، می‌توانیم از ویجت BottomNavigationBar استفاده کنیم. در این مثال، به بررسی نحوه پیاده‌سازی یک نوار ناوبری با سه صفحه مختلف می‌پردازیم.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'پیمایش با Bottom Navigation Bar',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _selectedIndex = 0;

  // لیست صفحات برای Bottom Navigation Bar
  static List<Widget> _widgetOptions = <Widget>[
    HomePage(),
    SecondPage(),
    ThirdPage(),
  ];

  // تابع برای مدیریت انتخاب آیتم‌های نوار ناوبری
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bottom Navigation Bar'),
      ),
      body: _widgetOptions.elementAt(_selectedIndex),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'خانه',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'صفحه دوم',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'صفحه سوم',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.blue,
        onTap: _onItemTapped,
      ),
    );
  }
}

// صفحه اول
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'صفحه اول',
        style: TextStyle(fontSize: 24),
      ),
    );
  }
}

// صفحه دوم
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'صفحه دوم',
        style: TextStyle(fontSize: 24),
      ),
    );
  }
}

// صفحه سوم
class ThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'صفحه سوم',
        style: TextStyle(fontSize: 24),
      ),
    );
  }
}

توضیحات کد:
ویجت StatefulWidget:

از StatefulWidget استفاده شده است تا بتوان وضعیت انتخاب شده را مدیریت کرد.
متغیر _selectedIndex وضعیت فعلی انتخاب شده را نگه می‌دارد.
لیست صفحات:

لیستی از ویجت‌ها (_widgetOptions) تعریف شده است که شامل صفحات مختلف اپلیکیشن است.
با تغییر _selectedIndex، صفحه مربوطه در body نمایش داده می‌شود.
BottomNavigationBar:

شامل سه آیتم (BottomNavigationBarItem) است که هر کدام یک آیکون و یک برچسب دارند.
ویژگی currentIndex نشان‌دهنده آیتم فعلی انتخاب شده است.
متد onTap به تغییر وضعیت انتخاب شده واکنش نشان می‌دهد.
تابع _onItemTapped:

با فشردن هر آیتم در نوار ناوبری، مقدار _selectedIndex به روز شده و صفحه مربوطه نمایش داده می‌شود.

نکات کلیدی در استفاده از Bottom Navigation Bar

تعداد آیتم‌ها:

توصیه می‌شود تعداد آیتم‌های Bottom Navigation Bar محدود به 3 تا 5 آیتم باشد تا خوانایی و دسترسی آسان حفظ شود.
استفاده از آیکون‌های مناسب:

انتخاب آیکون‌های مناسب و معنادار برای هر آیتم، به کاربران در درک بهتر عملکرد هر بخش کمک می‌کند.
سفارشی‌سازی ظاهر:

می‌توانید ظاهر Bottom Navigation Bar را با تنظیم رنگ‌ها، اندازه‌ها و انیمیشن‌ها سفارشی کنید تا با طراحی کلی اپلیکیشن هماهنگ شود.
مدیریت صفحات بهینه:

برای بهبود عملکرد اپلیکیشن، مطمئن شوید که صفحات بهینه و سبک باشند تا هنگام جابجایی بین آن‌ها، تأخیر و مشکلاتی به وجود نیاید.

ترکیب Navigation Drawer و Bottom Navigation Bar

در برخی موارد، ممکن است نیاز باشد که هر دو روش Navigation Drawer و Bottom Navigation Bar را در یک اپلیکیشن ترکیب کنید. این ترکیب می‌تواند تجربه کاربری بهتری را فراهم کند، به شرطی که به درستی پیاده‌سازی شود.

مثال ترکیبی:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ترکیب Drawer و Bottom Navigation',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _selectedIndex = 0;

  static List<Widget> _widgetOptions = <Widget>[
    HomePage(),
    SecondPage(),
    ThirdPage(),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  // تابع برای انتخاب آیتم‌های Drawer
  void _onDrawerItemTapped(String routeName) {
    Navigator.pop(context); // بستن Drawer
    Navigator.pushNamed(context, routeName);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ترکیب Drawer و Bottom Navigation'),
      ),
      drawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: <Widget>[
            DrawerHeader(
              child: Text(
                'منوی کناری',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                ),
              ),
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
            ),
            ListTile(
              leading: Icon(Icons.home),
              title: Text('صفحه اول'),
              onTap: () {
                _onDrawerItemTapped('/');
              },
            ),
            ListTile(
              leading: Icon(Icons.business),
              title: Text('صفحه دوم'),
              onTap: () {
                _onDrawerItemTapped('/second');
              },
            ),
            ListTile(
              leading: Icon(Icons.school),
              title: Text('صفحه سوم'),
              onTap: () {
                _onDrawerItemTapped('/third');
              },
            ),
          ],
        ),
      ),
      body: _widgetOptions.elementAt(_selectedIndex),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'خانه',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'صفحه دوم',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'صفحه سوم',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.blue,
        onTap: _onItemTapped,
      ),
    );
  }
}

// صفحه اول
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'صفحه اول',
        style: TextStyle(fontSize: 24),
      ),
    );
  }
}

// صفحه دوم
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'صفحه دوم',
        style: TextStyle(fontSize: 24),
      ),
    );
  }
}

// صفحه سوم
class ThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'صفحه سوم',
        style: TextStyle(fontSize: 24),
      ),
    );
  }
}

توضیحات کد ترکیبی:
Navigation Drawer:

منوی کناری شامل سه گزینه برای پیمایش به سه صفحه مختلف است.
با فشردن هر گزینه، ابتدا Drawer بسته می‌شود و سپس به صفحه مورد نظر هدایت می‌شود.
Bottom Navigation Bar:

شامل سه آیتم است که هر کدام به یک صفحه مختلف اشاره دارند.
با فشردن هر آیتم، صفحه مربوطه در body نمایش داده می‌شود.
ترکیب دو روش ناوبری:

کاربران می‌توانند از هر دو روش ناوبری استفاده کنند، به طوری که Drawer برای دسترسی به صفحات غیر اصلی و Bottom Navigation Bar برای دسترسی سریع به صفحات اصلی استفاده شود.

نکات کلیدی در ترکیب Drawer و Bottom Navigation Bar

هماهنگی بین دو روش ناوبری:

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

اطمینان حاصل کنید که انتخاب یک گزینه در Drawer یا Bottom Navigation Bar به درستی به صفحه مربوطه هدایت می‌شود و وضعیت انتخاب شده به روز می‌شود.
طراحی یکنواخت:

طراحی نوار ناوبری و Drawer باید با یکدیگر هماهنگ باشد تا تجربه کاربری یکنواخت و جذابی را فراهم کنند.

استفاده از Navigation Drawer و Bottom Navigation در پیمایش (Navigation) و مسیرها (Routes) در Flutter، به ویژه در اپلیکیشن‌های بزرگ‌تر، امکان مدیریت موثر و سازمان‌یافته صفحات را فراهم می‌کند. Navigation Drawer برای دسترسی به بخش‌های غیر اصلی اپلیکیشن و Bottom Navigation Bar برای دسترسی سریع به صفحات اصلی بسیار مناسب هستند. با ترکیب این دو روش، می‌توانید تجربه کاربری بهتری را ارائه دهید و اپلیکیشنی با ساختار منظم و قابل نگهداری ایجاد کنید.

Navigation پیشرفته

در پیمایش (Navigation) و مسیرها (Routes) در Flutter، Navigation پیشرفته به تکنیک‌ها و روش‌هایی اشاره دارد که به توسعه‌دهندگان امکان می‌دهد کنترل بیشتری روی نحوه پیمایش کاربران بین صفحات مختلف اپلیکیشن داشته باشند. این شامل مدیریت تاریخچه (Stack)، ارسال و دریافت داده بین صفحات، و استفاده از دیپ لینک‌ها (Deep Links) می‌شود. در این بخش، به تفصیل به مدیریت تاریخچه (Stack) می‌پردازیم و نحوه پیاده‌سازی آن را با مثال‌های عملی بررسی می‌کنیم.

مدیریت تاریخچه (Stack)

مدیریت تاریخچه (Stack) در پیمایش (Navigation) و مسیرها (Routes) در Flutter به معنای کنترل دقیق‌تر روی مسیرهای پیمایش کاربران است. Flutter از یک ساختار داده‌ای به نام استک (Stack) برای مدیریت مسیرها استفاده می‌کند. هر بار که کاربر به یک صفحه جدید منتقل می‌شود، این صفحه به بالای استک اضافه می‌شود و با بازگشت، آخرین صفحه از استک حذف می‌شود.

مفهوم Stack در Navigator

Navigator در Flutter به عنوان یک استک عمل می‌کند که مسیرهای پیمایش را مدیریت می‌کند. اصول اولیه عملکرد Navigator به شرح زیر است:

Push: اضافه کردن یک مسیر جدید به بالای استک و نمایش آن به کاربر.
Pop: حذف مسیر بالای استک و بازگشت به مسیر قبلی.
این ساختار به شما امکان می‌دهد تا مسیرهای پیچیده‌تری را مدیریت کرده و کنترل بیشتری روی تاریخچه پیمایش داشته باشید.

مثال عملی از مدیریت تاریخچه با Navigator.push و Navigator.pop

برای درک بهتر نحوه کارکرد Stack در پیمایش (Navigation) و مسیرها (Routes) در Flutter، بیایید یک مثال ساده را بررسی کنیم:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'مدیریت تاریخچه با Navigator',
      home: HomePage(),
    );
  }
}

// صفحه اصلی
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اصلی'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('رفتن به صفحه جدید'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => NewPage()),
            );
          },
        ),
      ),
    );
  }
}

// صفحه جدید
class NewPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه جدید'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('بازگشت به صفحه اصلی'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

توضیحات کد:
صفحه اصلی (HomePage):

دارای یک دکمه با متن “رفتن به صفحه جدید” است.
با فشردن دکمه، متد Navigator.push فراخوانی شده و صفحه جدید (NewPage) به استک مسیرها اضافه می‌شود.
صفحه جدید (NewPage):

دارای یک دکمه با متن “بازگشت به صفحه اصلی” است.
با فشردن دکمه، متد Navigator.pop فراخوانی شده و آخرین مسیر (صفحه جدید) از استک حذف می‌شود، به این ترتیب کاربر به صفحه اصلی بازمی‌گردد.

کنترل پیچیدگی‌های مسیرهای پیمایش

در پروژه‌های بزرگ‌تر، ممکن است نیاز به مدیریت پیچیده‌تری روی مسیرها داشته باشید. Flutter امکاناتی مانند Navigator.pushReplacement و Navigator.pushAndRemoveUntil را فراهم می‌کند تا بتوانید مسیرها را به طور دقیق‌تری کنترل کنید.

استفاده از Navigator.pushReplacement

Navigator.pushReplacement به شما امکان می‌دهد مسیر فعلی را با مسیر جدید جایگزین کنید بدون اینکه مسیر قبلی در استک باقی بماند.

مثال:

Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (context) => ReplacementPage()),
);

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

استفاده از Navigator.pushAndRemoveUntil

Navigator.pushAndRemoveUntil به شما اجازه می‌دهد مسیر جدید را اضافه کرده و تمامی مسیرهای قبلی را تا رسیدن به یک شرط مشخص حذف کنید.

مثال:

Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(builder: (context) => NewPage()),
  ModalRoute.withName('/'),
);

در این مثال، به NewPage منتقل می‌شویم و تمامی مسیرهای قبلی تا مسیر ‘/’ (صفحه اصلی) حذف می‌شوند.

مدیریت صفحات چندگانه با استفاده از Stack

با استفاده از Stack، می‌توانید مسیرهای پیمایش پیچیده‌تری را پیاده‌سازی کنید که شامل چندین صفحه و شرایط مختلف برای بازگشت به صفحات قبلی است.

مثال: انتقال از صفحه اول به صفحه دوم و سپس به صفحه سوم:

// انتقال از صفحه اول به صفحه دوم
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
).then((_) {
  // پس از بازگشت از صفحه دوم، انتقال به صفحه سوم
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => ThirdPage()),
  );
});

در این مثال، پس از بازگشت از SecondPage به HomePage، به طور خودکار به ThirdPage منتقل می‌شویم.

نکات کلیدی در مدیریت تاریخچه (Stack)

کنترل دقیق بر مسیرها:

با استفاده از متدهای مختلف Navigator می‌توانید نحوه افزودن و حذف مسیرها را کنترل کنید.
بازگشت سفارشی:

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

با استفاده از آرگومان‌ها می‌توانید داده‌هایی را بین مسیرها ارسال و دریافت کنید.
حفظ وضعیت صفحات:

با استفاده از ویجت‌های Stateful، می‌توانید وضعیت صفحات را در حین پیمایش حفظ کنید.

ارسال و دریافت داده بین صفحات با استفاده از Stack

یکی از قابلیت‌های مهم در پیمایش (Navigation) و مسیرها (Routes) در Flutter، امکان ارسال داده بین صفحات مختلف است. این کار معمولاً هنگام استفاده از Navigator.push انجام می‌شود.

مثال ارسال داده:

// انتقال به صفحه جدید با ارسال داده
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => NewPage(data: 'سلام از صفحه اصلی'),
  ),
);

دریافت داده در صفحه جدید:

class NewPage extends StatelessWidget {
  final String data;

  NewPage({required this.data});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه جدید'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(data),
            SizedBox(height: 20),
            ElevatedButton(
              child: Text('بازگشت به صفحه اصلی'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),
    );
  }
}

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

مدیریت دیپ لینک (Deep Link)

دیپ لینک (Deep Link) به شما امکان می‌دهد کاربران را مستقیماً به صفحات خاصی از اپلیکیشن هدایت کنید، حتی اگر اپلیکیشن باز نباشد. این قابلیت در پیمایش (Navigation) و مسیرها (Routes) در Flutter بسیار مفید است و می‌تواند تجربه کاربری بهتری را فراهم کند.

مثال پیاده‌سازی دیپ لینک با استفاده از بسته uni_links:

اضافه کردن بسته به pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  uni_links: ^0.5.1

استفاده از بسته در کد:

import 'package:flutter/material.dart';
import 'package:uni_links/uni_links.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _link = 'No link received yet';

  @override
  void initState() {
    super.initState();
    initDeepLinks();
  }

  void initDeepLinks() async {
    try {
      final initialLink = await getInitialLink();
      if (initialLink != null) {
        setState(() {
          _link = initialLink;
        });
        // پردازش لینک و پیمایش به صفحه مورد نظر
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => DeepLinkPage(link: initialLink)),
        );
      }
    } catch (e) {
      print('خطا در دریافت دیپ لینک: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'دیپ لینک در Flutter',
      home: HomePage(),
    );
  }
}

// صفحه اصلی
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه اصلی'),
      ),
      body: Center(
        child: Text('در انتظار دیپ لینک...'),
      ),
    );
  }
}

// صفحه دیپ لینک
class DeepLinkPage extends StatelessWidget {
  final String link;

  DeepLinkPage({required this.link});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('صفحه دیپ لینک'),
      ),
      body: Center(
        child: Text(
          'دریافت لینک: $link',
          style: TextStyle(fontSize: 20),
        ),
      ),
    );
  }
}

توضیحات کد دیپ لینک:اضافه کردن بسته uni_links:

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

در متد initDeepLinks، لینک اولیه دریافت شده و در صورت وجود، به صفحه مربوطه هدایت می‌شود.
صفحه دیپ لینک:

صفحه‌ای که لینک دریافتی را نمایش می‌دهد و می‌تواند بر اساس لینک، عملکردهای مختلفی انجام دهد.

نکات کلیدی در مدیریت تاریخچه (Stack)

استفاده از Context مناسب:

برای استفاده از متدهای Navigator باید context مناسبی داشته باشید. معمولاً در داخل ویجت‌های صفحه استفاده می‌شود.
انتخاب صحیح نوع Route:

MaterialPageRoute برای انیمیشن‌های پیش‌فرض Flutter مناسب است. در صورت نیاز به انیمیشن‌های خاص، می‌توانید از کلاس‌های مسیر دیگر مانند CupertinoPageRoute استفاده کنید.
مدیریت بازگشت به صفحه‌های قبلی:

با استفاده از Navigator.pop می‌توانید به صفحات قبلی بازگردید. همچنین می‌توانید داده‌هایی را هنگام بازگشت ارسال کنید.
استفاده از RouteObserver:

برای نظارت بر تغییرات مسیرها و مدیریت بهتر تاریخچه، می‌توانید از RouteObserver استفاده کنید.
پرهیز از استفاده مکرر از Navigator.push:

در پروژه‌های بزرگ‌تر، استفاده مکرر از Navigator.push بدون مدیریت مناسب می‌تواند منجر به ایجاد استک مسیرهای بسیار بلند شود که ممکن است باعث مشکلات عملکردی شود.
مدیریت تاریخچه (Stack) در پیمایش (Navigation) و مسیرها (Routes) در Flutter ابزاری قدرتمند است که به توسعه‌دهندگان امکان می‌دهد کنترل دقیقی روی مسیرهای پیمایش کاربران داشته باشند. با استفاده از متدهای مختلف Navigator و درک عمیق‌تر از نحوه عملکرد استک مسیرها، می‌توانید اپلیکیشن‌های پیچیده‌تر و با تجربه کاربری بهتری را ایجاد کنید. همچنین، ترکیب این تکنیک‌ها با قابلیت‌های پیشرفته‌تر مانند ارسال داده و دیپ لینک‌ها، به شما کمک می‌کند تا اپلیکیشنی حرفه‌ای و منعطف ارائه دهید.

نتیجه‌گیری

در این مقاله به بررسی جامع پیمایش (Navigation) و مسیرها (Routes) در Flutter پرداختیم و تمامی جنبه‌های این موضوع را از سطح مبتدی تا پیشرفته پوشش دادیم. پیمایش (Navigation) و مسیرها (Routes) در Flutter ابزاری قدرتمند هستند که به توسعه‌دهندگان امکان می‌دهند اپلیکیشن‌های منظم، قابل نگهداری و با تجربه کاربری عالی ایجاد کنند. از ساده‌ترین روش‌ها مانند استفاده از Navigator.push و Navigator.pop تا روش‌های پیشرفته‌تر مانند مدیریت تاریخچه با Stack و پیاده‌سازی دیپ لینک‌ها، هر کدام نقش مهمی در بهبود عملکرد و ساختار اپلیکیشن‌های Flutter ایفا می‌کنند.

استفاده از مسیرهای نام‌گذاری شده (Named Routes) در پروژه‌های بزرگ‌تر، سازمان‌دهی بهتر کد و افزایش خوانایی آن را فراهم می‌کند. همچنین، ابزارهایی مانند Navigation Drawer و Bottom Navigation به شما امکان می‌دهند تا ناوبری چند صفحه‌ای را به صورت کارآمد و کاربرپسند پیاده‌سازی کنید. مدیریت تاریخچه با Stack و ارسال داده بین صفحات نیز از دیگر قابلیت‌های مهم پیمایش (Navigation) و مسیرها (Routes) در Flutter است که به توسعه‌دهندگان اجازه می‌دهد کنترل دقیقی بر مسیرهای پیمایش کاربران داشته باشند.

آموزش پیمایش (Navigation) و مسیرها (Routes) در Flutter

دیدگاه های شما

دیدگاهتان را بنویسید

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