Навигация по страницам | Flutter

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Навигация по страницам | Flutter
Навигация по страницам | Flutter

Привет, если вы на пути изучения Flutter/Dart или вам просто интересно почитать про путь изучения, подписывайтесь на мой канал в telegram, буду рад вас видеть! А сегодня поговорим про организацию данных на экране во Flutter!

Предыдущая статья: Организация данных на экране | Flutter

Содержание:

1. Навигация по страницам с Routes (Imperative)
2. Навигация по страницам с Routes (Declarative)
3. Реализация Navigation Drawer
4. Работа с вкладками
5. Добавление нижней панели навигации
6. Использование ключей для передачи информации

В этой статье мы рассмотрим, как использовать распространенные методы навигации по страницам. Навигация по страницам - очень распространенный вариант использования для разработчиков. К счастью, Flutter упрощает нам создание интерфейса.

Для начала мы сосредоточимся на распространенных шаблонах навигации, с которыми вы столкнетесь как разработчик Flutter. Вы узнаете, как:

  • Использовать Routes для перемещения между страницами

  • Добавить виджет Drawer навигации

  • Добавьте виджет интерфейса вкладок

  • Добавьте виджет нижней навигации

  • Передавайте данные с помощью Keys

Возможность перемещаться между страницами с помощью встроенной навигации сделает ваши приложения более профессиональными. Flutter предоставляет несколько способов навигации между информационными страницами, поэтому стоит знать, как использовать их в ваших собственных приложениях. К концу этой статьи вы ознакомитесь с основами общей навигации по страницам с использованием Routes.

Навигация по страницам с Routes (Imperative)

Проблема

Вам нужен способ перемещаться между несколькими страницами, используя определенные навигационные инструкции.

Решение

Используйте Flutter navigation. Flutter navigation использует маршруты, которые обеспечивают механизм перехода между страницами. Маршрут относится к адресу страницы, к которой требуется получить доступ. Маршрутизация между страницами требует использования MaterialPageRoute, который используется для добавления новой страницы в стек приложений, заменяя текущую страницу.

Вот пример того, как выполнять навигацию между двумя разными страницами:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);
  final List<String> items = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
  ];
  
  @override
  Widget build(BuildContext context) {
    const title = 'MyAwesomeApp';
    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(title),
        ),
        body: ListView.builder(
          itemCount: items.length,
          itemBuilder: (context, index) {
            return MyListView(items[index]);
          },
        ),
      ),
    );
  }
}

class MyListView extends StatelessWidget {
  const MyListView(this.title);
  final String title;
  
  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(title),
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => MyDetails(title),
          ),
        );
      },
    );
  }
}

class MyDetails extends StatelessWidget {
  const MyDetails(this.itemTitle);
  final String itemTitle;
  
  @override
  Widget build(BuildContext context) {
    const title = 'Details Page';
    return Scaffold(
      appBar: AppBar(
        title: const Text(title),
      ),
      body: SafeArea(
        top: false,
        bottom: false,
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: [
              SizedBox(
                height: 338.0,
                width: 800.0,
                child: Card(
                  clipBehavior: Clip.antiAlias,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      // Divider(),
                      Padding(
                        padding: const EdgeInsets.all(10.0),
                        child: Text(itemTitle),
                      )
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Обсуждение

В примере событие onTap настроено для каждого элемента списка, что означает, когда мы выбираем отдельный элемент в списке, будет сгенерировано событие. Событие связано с Navigator.push, чтобы запросить отображение новой страницы.

При использовании Navigator V1 с императивной маршрутизацией обход значительно упрощается. Механизм императивной навигации использует стек для перемещения по соответствующей странице, позволяя вам перемещаться между страницами. На рисунке 12-1 навигация между страницами явно задана с помощью MaterialPageRoute.

 Рисунок 12-1. Пример класса MaterialPageRoute
Рисунок 12-1. Пример класса MaterialPageRoute

Использование MaterialApp автоматически создаст необходимые значки навигации. В этом случае стрелка назад отображается на экране сведений без какого-либо дополнительного кодирования. Убедитесь, что определение виджета Scaffold, добавленное на Details Page, не переопределяет MaterialApp.

Navigator.push реализует механизм стека, при котором новые экраны добавляются и удаляются по мере перехода пользователя между ними. Маршрутизация между экранами обрабатывается автоматически, поэтому вам, как разработчику, просто нужно указать страницу, которая будет использоваться в текущем контексте сборки. При возврате с новой страницы приложение запустит механизм pop для перехода на предыдущую страницу:

onTap: () {
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => MyDetails(title),
    ),
  );
},

Декларативная маршрутизация (Navigator V2) предоставляет более сложный механизм, который отслеживает состояние навигации. В этом режиме вы можете представить, что Flutter ведет себя аналогично навигации по веб-страницам. Подобный подход позволяет вам переходить между ссылками и динамически отслеживать размещение.

Навигация по страницам с Routes (Declarative)

Проблема

Вам нужен способ перехода к определенному пути к странице на основе установленного рабочего процесса маршрутизации приложения.

Решение

Используйте Flutter navigation. Flutter navigation позволяет разработчикам определять используемые маршруты, создавая декларативный подход для перемещения между экранами. Используйте этот подход, когда вам нужно следовать определенному рабочему процессу, к которому необходимо применить определенный поток, например, процесс регистрации.

Вот пример того, как использовать декларативную маршрутизацию между несколькими страницами в соответствии с определенным рабочим процессом:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Code Sample for Navigator',
      // MaterialApp contains our top-level Navigator
      initialRoute: '/signup',
      routes: <String, WidgetBuilder>{
        '/': (BuildContext context) => const HomePage(),
        '/signup': (BuildContext context) => const SignUpPage(),
      },
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return DefaultTextStyle(
      style: Theme.of(context).textTheme.headline4!,
      child: Container(
        color: Colors.white,
        alignment: Alignment.center,
        child: const Text('Home Page'),
      ),
    );
  }
}

class SignUpPage extends StatelessWidget {
  const SignUpPage({super.key});

  @override
  Widget build(BuildContext context) {
    // SignUpPage builds its own Navigator, which ends up being a nested
    // Navigator in our app.
    return Navigator(
      initialRoute: 'signup/personal_info',
      onGenerateRoute: (RouteSettings settings) {
        WidgetBuilder builder;
        switch (settings.name) {
          case 'signup/personal_info':
            // Assume CollectPersonalInfoPage collects personal info and then
            // navigates to 'signup/choose_credentials'.
            builder = (BuildContext context) => const CollectPersonalInfoPage();
            break;
          case 'signup/choose_credentials':
            // Assume ChooseCredentialsPage collects new credentials and then
            // invokes 'onSignupComplete()'.
            builder = (BuildContext _) => ChooseCredentialsPage(
                  onSignupComplete: () {
                    // Referencing Navigator.of(context) from here refers to the
                    // top-level Navigator because SignUpPage is above the
                    // nested Navigator that it created. Therefore, this pop()
                    // will pop the entire "sign-up" journey and return to the
                    // "" route, AKA HomePage.
                    Navigator.of(context).pop();
                  },
                );
            break;
          default:
            throw Exception('Invalid route: ${settings.name}');
        }
        return MaterialPageRoute<void>(builder: builder, settings: settings);
      },
    );
  }
}

class ChooseCredentialsPage extends StatelessWidget {
  const ChooseCredentialsPage({
    super.key,
    required this.onSignupComplete,
  });
  final VoidCallback onSignupComplete;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onSignupComplete,
      child: DefaultTextStyle(
        style: Theme.of(context).textTheme.headline4!,
        child: Container(
          color: Colors.pinkAccent,
          alignment: Alignment.center,
          child: const Text('Choose Credentials Page'),
        ),
      ),
    );
  }
}

class CollectPersonalInfoPage extends StatelessWidget {
  const CollectPersonalInfoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return DefaultTextStyle(
      style: Theme.of(context).textTheme.headline4!,
      child: Container(
        color: Colors.white,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              "Name: Max, Address: Fury Road",
              style: TextStyle(fontSize: 20, color: Colors.black87),
            ),
            const SizedBox(height: 10.0),
            GestureDetector(
              onTap: () {
                // This moves from the personal info page to the credentials page,
                // replacing this page with that one.
                Navigator.of(context)
                    .pushReplacementNamed('signup/choose_credentials');
              },
              child: const SizedBox(
                child: Text(
                  'Link: Page',
                  style: TextStyle(
                      fontSize: 20,
                      color: Colors.blue,
                      decoration: TextDecoration.underline),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Обсуждение

В примере определено, что приложение следует указанному пользователю пути при доступе к приложению, как показано на рисунке 12-2.

В примере используются три отдельных экрана для имитирования путешествия пользователя, связанного с вводом информации, проверкой учетных данных и, наконец, доступом к главному экрану приложения. Для перехода к следующему экрану необходимо выполнить условие. Если пользователь не может выполнить это условие, он не сможет перейти к следующему экрану.

Приложение поддерживает маршруты, определяемые навигатором. При таком подходе навигация по экрану более предсказуема для обхода на основе ссылок. Хотя реализация более сложная, чем Navigator V1, она обеспечивает большую гибкость для маршрутизации внутри приложения.

 Рисунок 12-2. Пример маршрутизации Navigator V2
Рисунок 12-2. Пример маршрутизации Navigator V2

Реализация Navigation Drawer

Проблема

Вам нужен способ создать закадровое навигационное меню.

Решение

Используйте виджет Drawer для размещения ряда навигационных точек. Виджет Drawer можно рассматривать как меню с подпунктами. В примере кода вы будете использовать три различных параметра, настроенных для выполнения навигации. Добавление панели в ваше приложение обеспечивает простой механизм навигации между параметрами.

Вот пример использования панели навигации для обеспечения доступа к меню, используемому для прямого перехода к информации о приложении за пределами экрана:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    const title = 'Drawer demo';
    return MaterialApp(
      title: title,
      home: Scaffold(
        body: DemoPageOne(),
      ),
    );
  }
}

class DemoPageOne extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Page One"),
      ),
      body: const Center(
        child: Text('Demo: Page One'),
      ),
      drawer: const MyDrawerWidget(),
    );
  }
}

class DemoPageTwo extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Page Two"),
      ),
      body: const Center(
        child: Text('Demo: Page Two'),
      ),
      drawer: const MyDrawerWidget(),
    );
  }
}

class DemoPageThree extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Page Three"),
      ),
      body: const Center(
        child: Text('Demo: Page Three'),
      ),
      drawer: const MyDrawerWidget(),
    );
  }
}

class DemoPageFour extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Page Four"),
      ),
      body: const Center(
        child: Text('Demo: Page Four'),
      ),
      endDrawer: const MyDrawerWidget(),
    );
  }
}

class MyDrawerWidget extends StatelessWidget {
  const MyDrawerWidget({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: ListView(
        children: [
          const DrawerHeader(
            child: Icon(Icons.home, size: 35),
          ),
          ListTile(
            leading: const Icon(Icons.home),
            title: const Text('Drawer Item #1'),
            onTap: () {
              Navigator.of(context).push(
                MaterialPageRoute(builder: (context) => DemoPageOne()),
              );
            },
          ),
          ListTile(
            leading: const Icon(Icons.info),
            title: const Text('Drawer Item #2'),
            onTap: () {
              Navigator.of(context).push(
                MaterialPageRoute(builder: (context) => DemoPageTwo()),
              );
            },
          ),
          ListTile(
              leading: const Icon(Icons.favorite),
              title: const Text('Drawer Item #3'),
              onTap: () {
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (context) => DemoPageThree()),
                );
              }),
          ListTile(
              leading: const Icon(Icons.list),
              title: const Text('Drawer Item #4'),
              onTap: () {
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (context) => DemoPageFour()),
                );
              }),
        ],
      ),
    );
  }
}

Обсуждение

В примере приложение определяет Drawer, который содержит четыре элемента, представляющие отдельные страницы в приложении Flutter. Выбор элемента Drawer приведет пользователя к странице, относящейся к пункту меню.

Реализация виджета Drawer включает в себя ряд элементов. Вариант использования Drawer обычно заключается в том, что приложение было разделено на несколько маршрутов (т.е. страниц, как показано на рисунке 12-3).

 Рисунок 12-3. Пример виджета Drawer
Рисунок 12-3. Пример виджета Drawer

Заголовок Drawer (т.е. DrawerHeader) используется для хранения информации, связанной с приложением. По соглашению, это может быть изображение, такое как аватар, представляющий пользователя, или текст:

const DrawerHeader(
  child: Icon(Icons.home, size: 35),
),

Как правило, Drawer открывается с левой стороны; однако это настраивается разработчиком. Drawer можно настроить так, чтобы в качестве точки привязки использовалась левая или правая сторона экрана. Используйте свойство Scaffold endDrawer, чтобы изменить положение Drawer по умолчанию с левой стороны и открыть его с правой стороны экрана:

return Scaffold(
  appBar: AppBar(
    title: const Text("Page Four"),
    ),
  body: const Center(
	child: Text('Demo: Page Four'),
	),
  endDrawer: const MyDrawerWidget(),
);

Просмотрите код для DemoPageFour, чтобы увидеть это в действии. При использовании этой страницы также обратите внимание, что виджет Scaffold автоматически обрабатывает переход на предыдущую страницу.

Выбор страницы может отличаться от информации, отображаемой на странице. Например, панель содержит ряд элементов, относящихся к выбранной странице. Каждый пункт меню будет вызывать определенный маршрут страницы с содержимым, специфичным для этого пункта.

В примере панель инструментов также использует ListView с дочерними элементами ListTile для отображения доступных опций. Каждый ListTile вызывает отдельную функцию для отображения экранного представления. В ListTile вы заметите, что поддерживаются значок, заголовок и подзаголовок для обеспечения визуальной обратной связи с пользователем. Чтобы пользователь мог выбирать каждый элемент, добавлен детектор жестов. Добавление функциональности onTap может быть объединено с навигацией для перехода на определенную страницу:

ListTile(
  leading: const Icon(Icons.list),
  title: const Text('Drawer Item #4'),
    onTap: () {
      Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => DemoPageFour()),
   );
}),

Добавление навигации по Drawer в ваше приложение не требует слишком больших усилий, но помните, что такая навигация подходит не для каждого случая. Если вам требуется иерархическая навигация (например, страница 1 переходит на страницу 2, а затем на страницу 3), рассмотрите альтернативный метод маршрутизации между страницами.

Работа с вкладками

Проблема

Вы хотите использовать вкладки для отображения различного контента.

Решение

Используйте панель вкладок для отображения нескольких страниц, разделенных определенными категориями.

Вот пример, в котором виджет панели вкладок используется для отображения информации для различных элементов, относящихся к фиктивному приложению финансовых услуг:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter and Dart',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        tabBarTheme: const TabBarTheme(
          labelColor: Colors.white,
          labelStyle: TextStyle(color: Colors.grey),
// color for text
        ),
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter and Dart HomePage'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;
  const MyHomePage({
    Key? key,
    required this.title,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: DefaultTabController(
        length: 4,
        child: Scaffold(
          appBar: AppBar(
            title: const Text('MyAwesomeTabBar'),
            bottom: const TabBar(
// indicatorColor: Colors.black,
              tabs: [
                Tab(
                  icon: Icon(Icons.home, color: Colors.white),
                  child: Text('Home',
                      style: TextStyle(fontWeight: FontWeight.bold)),
                ),
                Tab(
                  icon: Icon(Icons.account_balance, color: Colors.white),
                  child: Text('Account',
                      style: TextStyle(fontWeight: FontWeight.bold)),
                ),
                Tab(
                  icon: Icon(Icons.calculate, color: Colors.white),
                  child: Text('Payments',
                      style: TextStyle(fontWeight: FontWeight.bold)),
                ),
                Tab(
                  icon: Icon(Icons.credit_score, color: Colors.white),
                  child: Text('Card',
                      style: TextStyle(fontWeight: FontWeight.bold)),
                ),
              ],
            ),
          ),
          body: const TabBarView(
            children: [
              SizedBox(
                child: Center(
                  child: Text('Home Page Tab 1'),
                ),
              ),
              SizedBox(
                child: Center(
                  child: Text('Account Page Tab 2'),
                ),
              ),
              SizedBox(
                child: Center(
                  child: Text('Payments Page Tab 3'),
                ),
              ),
              SizedBox(
                child: Center(
                  child: Text('Card Page Tab 4'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Обсуждение

В примере приложение определяет несколько страниц вкладок, каждая из которых связана с отдельной страницей. Выбор элемента вкладки переключит фокус на соответствующие страницы, связанные с активной вкладкой.

Типичный вариант использования панели вкладок - отображение информации о странице. В этом сценарии на каждой странице есть значок/текст, указывающий на характер отображаемой информации, как показано на рисунке 12-4.

 Рисунок 12-4. Пример панели вкладок и виджета TabBarView
Рисунок 12-4. Пример панели вкладок и виджета TabBarView

Настройки ThemeData могут влиять на цвет панели вкладок по умолчанию. Добавьте настройку темы панели вкладок, чтобы разрешить использование обновленной цветовой схемы. Например, чтобы изменить цвет надписи, добавьте параметр labelColor.

Цвета панели вкладок на отдельном уровне также можно изменить, применив цвет на уровне вкладок:

return MaterialApp(
  title: 'Flutter and Dart Title Demo',
  debugShowCheckedModeBanner: false,
  theme: ThemeData(
    tabBarTheme: const TabBarTheme(
      labelColor: Colors.white,
    ),
      primarySwatch: Colors.blue,
	),
    home: const MyHomePage(title: 'Flutter and Dart HomePage'),
);

В примере кода были использованы оба подхода, чтобы проиллюстрировать, как это работает. В примере обратите внимание, как панель вкладок связана со свойством AppBar bottom. Выполнение этого приведет к отображению панели вкладок в нижней части заголовка приложения.

В дополнение к панели вкладок, TabBarView может использоваться для отображения содержимого, относящегося к конкретной вкладке. Чтобы включить содержимое под панелью вкладок, используйте этот виджет в свойство body. Убедитесь, что объявлено такое же количество TabBarViews, как и у виджета TabBar. При выборе каждой вкладки будет отображаться соответствующий вид, заполняющий доступное окно просмотра.

Добавление нижней панели навигации

Проблема

Вы хотите обеспечить навигацию пользователя в нижней части экрана.

Решение

Используйте bottom navigation виджет для создания общего элемента дизайна, обычно основанного на значках.

Вот пример, демонстрирующий, как интегрировать это решение в ваше приложение Flutter:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
        title: "Bottom Navigation Widget", home: MyBottomNavigationWidget());
  }
}

final List<Widget> _navigationPages = [
  const Center(child: Text('Page: Home')),
  const Center(child: Text('Page: News')),
  const Center(child: Text('Demo: Favorites')),
  const Center(child: Text('Demo: List')),
];

class MyBottomNavigationWidget extends StatefulWidget {
  const MyBottomNavigationWidget({Key? key}) : super(key: key);
  
  @override
  State<MyBottomNavigationWidget> createState() => _MyBottomNavigationWidget();
}

class _MyBottomNavigationWidget extends State<MyBottomNavigationWidget> {
  final appTitle = 'Bottom Navigation Widget';
  int _itemSelected = 0;
  
	void _bottomBarNavigation(int index) {
    setState(() {
      _itemSelected = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(appTitle),
      ),
      body: _navigationPages[_itemSelected],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _itemSelected,
        onTap: _bottomBarNavigation,
        type: BottomNavigationBarType.fixed,
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(icon: Icon(Icons.info), label: 'News'),
          BottomNavigationBarItem(
              icon: Icon(Icons.favorite), label: 'Favorites'),
          BottomNavigationBarItem(icon: Icon(Icons.list), label: 'List'),
        ],
      ),
    );
  }
}

Обсуждение

В этом примере мы используем виджет с отслеживанием состояния, чтобы сохранить состояние виджета. В этом случае он сохранит выбранный BottomNavigationBarItem. На рисунке 12-5 показана панель навигации, где код будет отображать отдельную страницу для каждого выбранного элемента в нижней панели навигации.

 Рисунок 12-5. Пример виджета BottomNavigationBar
Рисунок 12-5. Пример виджета BottomNavigationBar

При использовании нижней панели навигации каждый пункт меню можно настроить так, чтобы при нажатии на него выполнялось определенное действие. В примере приложения отображается страница с названием выбранного пункта. Виджет с отслеживанием состояния является неотъемлемой частью реализации, поскольку он используется для хранения значения текущего пункта. Когда пользователь выбирает элемент, код вызывает set state для обновления до текущего выбора (т.е. свойству currentIndex присваивается значение _itemSelected).

Тип панели навигации может быть определен несколькими способами. Fixed - это параметр по умолчанию, который обеспечивает согласованное равноудаленное отображение каждого значка на экране. Установите свойство type, чтобы указать, какую конфигурацию применять, например, type: BottomNativationBarType.Fixed. Использование этой опции означает, что вы просите Flutter управлять размещением значков четырех или менее элементов. Если вы решите использовать опцию shifting, это означает, что значки размещаются в соответствии с вашими критериями и обеспечивают приятную анимацию затухания при использовании этой опции.

Один из распространенных способов использования нижней панели навигации заключается в представлении различных видов на экране. Если каждый элемент навигации представляет собой отдельную страницу, это расширяет общие возможности приложения. Когда пользователь выбирает значок навигации, он перенаправляется на соответствующую отображаемую страницу. Помните об использовании этого параметра в более сложных сценариях с иерархией. Хотя этот параметр предлагает простой способ просмотра данных, добавление большого количества элементов (например, более пяти) может быстро привести к путанице.

Использование ключей для передачи информации

Проблема

Вам нужен способ передачи информации между виджетами.

Решение

Используйте ключи для передачи информации между виджетами. Ключи обычно используются для передачи состояния в виде пары ключ/значение.

Вот пример, демонстрирующий передачу информации с использованием ключей и именованных параметров:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    const paramTitle = 'My Title';
    const paramName = 'My Name';
    
		return MaterialApp(
      title: paramTitle,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(paramTitle),
        ),
        body: const MyTextWidget(name: paramName, title: paramTitle),
      ),
    );
  }
}

class MyTextWidget extends StatelessWidget {
  final String title;
  final String name;
  const MyTextWidget({Key? key, required this.title, required this.name})
      : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text("$title $name"),
    );
  }
}

Обсуждение

В этом примере мы используем ключи для передачи информации между родительским классом и дочерним. Как показано на рисунке 12-6, в класс MyTextWidget необходимо отправить две части информации.

 Рисунок 12-6. Пример передачи ключевой информации
Рисунок 12-6. Пример передачи ключевой информации

Ключи предоставляют простой механизм для передачи информации и помогают отображать правильное состояние. Для достижения этого используется пара ключ/значение, которая должна быть однозначно адресуемой. На высоком уровне подклассы должны использовать либо LocalKey, либо GlobalKey.

Локальный ключ ограничен своим родительским ключом, что означает, что он должен использоваться совместно с элементами для передачи данных. Локальный ключ обычно используется при передаче информации через элементы в дереве виджетов.

Глобальный ключ требует уникальности во всем приложении, что означает, что его нельзя дублировать. В ситуации, когда нецелесообразно координировать локальный ключ, используйте глобальный ключ для управления желаемым состоянием. Чтобы узнать больше об использовании ключей во Flutter, я настоятельно рекомендую посмотреть эпизод Flutter Widgets 101 “Когда использовать ключи” от команды Flutter.

Ключ может использоваться не только для сохранения состояния и передачи информации между классами. Существует ряд опций, которые можно использовать для типов ключей во Flutter:

Ключ

Назначение

Local

Различать дочерние элементы

Value

Использовать значение ключа

Object

Использовать объект для уникальной ссылки на элемент

Unique

Убедитесь, что каждый ключ уникален

PageStorageKey

Удерживайте местоположение прокрутки пользователя, чтобы сохранить позиционное состояние на всех страницах

Global

Доступ к информации во всем приложении

При использовании объекта с отслеживанием состояния обратите внимание, что глобальный ключ расширяет тип state и, таким образом, предоставляет доступ к связанному состоянию приложения.

Источник: https://habr.com/ru/articles/798239/


Интересные статьи

Интересные статьи

Hola, Amigos! На связи Саша Чаплыгин, Flutter-dev. В этой публикации вы познакомитесь с методиками для разработчиков Flutter, которые помогут вам улучшить качество программного кода, его читаемость, п...
Продолжаем обсуждать, что нового появилось в версии Flutter 3. Начало здесь.
Почему Flutter использует язык Dart? Основные преимущества языка Dart.Сложность: Новичок. Многие лингвисты считают, что естественный язык, на котором говорит человек, влияет на то, как он думает...
Привет! В данном цикле статей я хотел бы показать, как может происходить создание приложений с использованием Flutter. У меня есть несколько Open Source решений, которые будут использованы в данном пр...
Думаю, многие разрабочики хотя бы раз в жизни хотели поделиться своими наработками с сообществом. Уж точно все - пользовались тем, чем делятся другие. Мое мнение на этот ...