Flutter Navigasyon Tipleri 💫 🌌 ✨
Tags: flutter, navigation, dart, mobile
Published: 2022-02-12 22:20:47

Navigasyon bir ekrandan diğerine gezinmeyi sağlayan yönteme verilen isimdir.

**Flutter'da ekranlar arasında gezinmek bir çok seçenek vardır bunlar:**

**• MaterialPageRoute ile doğrudan gezinme.**
**• Route Map ile statik navigasyon**
**• Generated Routes ile dinamik navigasyon**


## 1. MaterialPageRoute ile Doğrudan Gezinme

Navigator'ın bir örneğine erişir ve yeni bir MaterialPageRoute'u içeri gönderirsiniz. Rota, navigasyon yığınının üstünde yeni bir Widget oluşturur.

```
Navigator.push(context, MaterialPageRoute<void>(
  builder: (BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('My Page')),
      body: Center(
        child: TextButton(
          child: Text('POP'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  },
));
```



```
Navigator.push(
   context,
   MaterialPageRoute(
     builder: (BuildContext context) => LobbyScreen(),
     ),
);
```

`MaterialPageRoute`, yönlendirmekten daha fazlasından sorumludur. Geçişi kontrol eder ve istediğiniz zaman geri dönebilmeniz için eski rotayı bellekte tutar. Bir önceki sayfaya geri dönebilmek için de Navigator.pop() yöntemini kullanırız. Bu yöntem, ilk Widget'ı yığından kaldırır.


## 2. Route Map ile Statik Navigasyon

`Provider` veya `BloC` pattern gibi bir state yönetimi aracı kullanıyorsanız bu tercih edilen yoldur. Farklı WidgetBuilder methodlarını tanımlayan ve navigasyonla ilgilenen String key'ler ile bir Map oluşturma seçeneğiniz vardır.

```
void main() {
  runApp(MaterialApp(
    home: MyAppHome(), // becomes the route named '/'
    routes: <String, WidgetBuilder> {
      '/a': (BuildContext context) => MyPage(title: 'page A'),
      '/b': (BuildContext context) => MyPage(title: 'page B'),
      '/c': (BuildContext context) => MyPage(title: 'page C'),
    },
  ));
}
```
Bir rotayı ada göre göstermek için aşağıdaki yöntemi kullanın:

`Navigator.pushNamed(context, '/b');`


```
return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.light(),
      initialRoute: LoginScreen.route,
      routes: {
        LobbyScreen.route: (context) => LobbyScreen(),
        LoginScreen.route: (context) => LoginScreen(),
        GameScreen.route: (context) => GameScreen(),
      },
    );
```

`Navigator.pushNamed(context, LobbyScreen.route);`


Statik "route", belirli Widget'lara giden yolu tanımlayan string içeren bir değişkendir.
Route'larınızdan biri örneğin eğik çizgi içeriyorsa, en az bir yolu "/" ile sağlamanız gerektiğini unutmayın.

Tek dezavantajı, argüman iletememenizdir.
Argüman iletme dinamik navigasyon tarafında ele alınacaktır.

3. onGeneratedRoute ile Dinamik Navigasyon

onGeneratedRoute, rotalar oluşturabilme ve iletilen bağımsız değişkenlere erişebilme avantajına sahiptir.

```
 onGenerateRoute: (settings) {
        switch (settings.name) {
          case LoginScreen.route:
            return MaterialPageRoute(builder: (_) => LoginScreen());
            break;
          case LobbyScreen.route:
            return MaterialPageRoute(builder: (_) => LobbyScreen());
            break;
          case GameScreen.route:
            return MaterialPageRoute(builder: (_) => GameScreen());
            break;
          default:
            return MaterialPageRoute(builder: (_) => LoginScreen());
        }
      }
```

arguments parametresi ile yeni rotaya iletmek istediğiniz argümanları gönderebilirsiniz.


Aşağıdaki örneğin işlevi  LobbyScreen.route route'una user-msg adında değeri "Thank you for reading!" olan bir argüman iletmektir.

```
onPressed: () {
  Navigator.pushNamed(
    context,
    LobbyScreen.route,
    arguments: {"user-msg": "Thank you for reading!"},
    );
}
```



```
onGenerateRoute: (settings) {
        switch (settings.name) {
          case LoginScreen.route:
            return MaterialPageRoute(builder: (_) => LoginScreen());
            break;
          case LobbyScreen.route:
            return MaterialPageRoute(builder: (_) =>
                LobbyScreen(
                    settings.arguments
                ));
            break;
          case GameScreen.route:
            return MaterialPageRoute(builder: (_) => GameScreen());
            break;
          default:
            return MaterialPageRoute(builder: (_) => LoginScreen());
        }
      },
```

Gönderdiğimiz argümana ulaşmak için:  arguments["user-msg"] biçimini kullanırız.

```

class LobbyScreen extends StatelessWidget {
  static const String route = "lobby-new";
  final Map<String, String> arguments;

  LobbyScreen(this.arguments);

  @override
  Widget build(BuildContext context) {
    ...
    Text(
      arguments["user-msg"],
      style: GoogleFonts.sawarabiGothic(fontSize: 34.0),
      textAlign: TextAlign.center,
    )
    ...
  }
}
```


## Rotalar bir değer döndürebilir

Aşağıdaki örnekte Tamam'a basıldığında value değişkenine true değeri atanır. Kullanıcı geri düğmesine basarsa value değişkeninin değeri null olur.

Bir ekrandan diğerine değer döndürmek için navigasyon kullanıldığında rotanın type parametresi pop sonucunun türüyle aynı olmalıdır. 

```
bool value = await Navigator.push(context, MaterialPageRoute<bool>(
  builder: (BuildContext context) {
    return Center(
      child: GestureDetector(
        child: Text('Tamam'),
        onTap: () { Navigator.pop(context, true); }
      ),
    );
  }
));
```

Tür belirtmemeyi tercih ederseniz void kullanabilirsiniz.

`MaterialPageRoute<void>MaterialPageRoute`

Popup routes:

showDialog , showMenu ve showModalBottomSheet gibi işlevler, itilen rotanın geleceğini (Future) yukarıda açıklandığı gibi döndürür. Arayanlar, rota açıldığında bir işlem yapmak veya rotanın değerini almak için döndürülen değeri bekleyebilir.

`PopupMenuButton` ve `DropdownButton` gibi açılır pencereler oluşturan widget'lar da vardır. Bu widget'lar, `PopupRoute'un` dahili alt sınıflarını oluşturur ve bunları göstermek ve kapatmak için Navigator'ın **push** ve **pop** methodlarını kullanır.

## Custom routes

**PageRouteBuilder** sınıfı, geri aramalar açısından özel bir rota tanımlamayı mümkün kılar. 

Aşağıda rota göründüğünde veya kaybolduğunda çocuğunu döndüren ve solduran bir örnek görüyorsunuz.Bu rota, `opaque: false` olduğu için bir popup route'ın yaptığı gibi tüm ekranı gizlemez.


```
Navigator.push(context, PageRouteBuilder(
  opaque: false,
  pageBuilder: (BuildContext context, _, __) {
    return Center(child: Text('My PageRoute'));
  },
  transitionsBuilder: (___, Animation<double> animation, ____, Widget child) {
    return FadeTransition(
      opacity: animation,
      child: RotationTransition(
        turns: Tween<double>(begin: 0.5, end: 1.0).animate(animation),
        child: child,
      ),
    );
  }
));
```



references:
https://api.flutter.dev/flutter/widgets/Navigator-class.html
https://medium.com/flutter-community/everything-you-need-to-know-about-flutter-navigation-d0c5e549b3c