Как сделать кнопку выбора flutter

Обновлено: 04.07.2024

0) вопрос Как получить доступ к виджету, что бы изменить в нем текст, например аналог идентификатора или ключ?

1) вопрос Как правильно использовать событие onPressed ?

или присваиваем ему ссылку на метод

или в самом событии пишем код

2) вопрос не получается изменять текст при нажатии на кнопку.

Только изучаю Flutter, пытаюсь разобраться. Спасибо.

1 ответ 1

Чтобы ответить на ваш вопрос, необходимо узнать что такое StatelessWidget и StatefulWidget (и какая между ними разница).

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

StatefulWidget – рекомендуется для изменяемых виджетов, с изменяемым внутренним состоянием.

Исходя из этого мы понимаем: чтобы изменить данные внутри StatelessWidget, необходимо создать конструктор этого класса с необходимыми для нас полями. Пример:

При вызове MyWidget(". ") текст будет меняться. Но если вам необходимо изменять ваши данные без ручного участия (с использованием внутреннего состояния), например при нажатии на кнопку, то следует использовать StatefulWidget. Для примера возьмём ваш код:

Напоследок соединим два примера в один:

Ответ на 0 вопрос:

Ответ на 1 вопрос: обычно используют либо 1 либо 3 вариант, выбор между ними: от количества кода (если 1-2 строчки можно и 3 вариант выбрать. Если больше, то 1).

Flutter быстро становится одним из самых популярных фреймворков для разработки кросс платформенных мобильных приложений. Большинство разработчиков Android и iOS сегодня начинают соглашаться с тем, что это более быстрая и перспективная альтернатива другим кросс платформенным фреймворкам, таким как React Native и NativeScript.

Google из кожи вон лезет, чтобы привлечь к нему больше разработчиков. Например на Google I/O в этом году было несколько углубленных сессий, сосредоточенных на разработке с помощью него приложений, отвечающих принципам Material Design. Во время одной из сессий Google также объявил, что Flutter станет первоклассной платформой для Material Design.

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

Необходимые условия

Чтобы эта серия уроков была для вас наиболее полезна, вам понадобится:

  • последняя версия Android Studio
  • устройство или эмулятор для запуска Android API версии 21 или выше

1. Настройки Android Studio

После установки нескольких небольших плагинов, вы можете использовать для разработки Flutter приложений Android Studio - IDE, к которой наиболее привыкли разработчики нативных Android приложений.

Сперва запустите Android Studio и выберете пункт меню Configure > Plugins (Конфигурация > Плагины) в приветственном окне.

В появившимся диалоговом окне нажмите кнопку Browse Repositories (Обзор репозиториев) и найдите плагин Flutter.

Browse repositories dialog
Browse repositories dialog
Browse repositories dialog

Когда нашли плагин, нажмите кнопку Install (Установить) для него. После этого вам будет задан вопрос о том, стоит ли также установить и плагин Dart. Нажмите Yes (Да) для продолжения.

Plugin dependencies dialog
Plugin dependencies dialog
Plugin dependencies dialog

После установки обоих плагинов нажмите кнопку Restart Android Studio (Перезапустить Android Studio) для завершения настроек.

2. Создание нового проекта

После перезапуска вы сможете увидеть кнопку Start a new Flutter project (Начать новый проект Flutter) в приветственном окне Android Studio. Нажмите ее для создания вашего первого проекта Flutter.

В следующем окне выберете опцию Flutter Application (Приложение Flutter) нажмите Next (Далее)

Create Flutter project dialog
Create Flutter project dialog
Create Flutter project dialog

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

Flutter project configuration dialog
Flutter project configuration dialog
Flutter project configuration dialog

Плагин Flutter не включает в себя Flutter SDK. Поэтому вам нужно установить SDK отдельно. Это можно сделать, нажав кнопку Install SDK (Установить SDK) в текущем окне.

В зависимости от скорости вашего соединения для завершения установки может потребоваться достаточно много времени. После успешного окончания вы сможете нажать кнопку Next (Далее) для завершения создания проекта.

3. Добавление точки входа

На протяжении этого урока вы будете писать код в файле lib/main.dart. По умолчанию он будет содержать некоторые примеры кода, которые вам не понадобятся. Так что перед началом редактирования удалите все его содержимое.

Фреймворк Flutter использует язык программирования Dart, который легко выучить и чей синтаксис очень похож на синтаксис Java и C. По примеру многих самостоятельных программ на Java и C, для Flutter необходима специальная функция main() , которая служит точкой входа для всего приложения.

Соответственно, добавьте следующий код в файл main.dart:

На данном этапе вы можете нажать Shift + F10, чтобы скомпилировать и запустить приложение. Если не возникло ошибок на предыдущих шагах, вы должны увидеть, что приложение отобразит пустой белый холст на вашем устройстве.

4. Использование виджетов, не имеющих указания состояния

Все Flutter приложения состоят из одного или более виджетов - экземпляров классов, которые позволяют рисовать текст и изображения на экране. Обычно вам не придется программировать какой-либо низкоуровневый виджет с нуля, поскольку фреймворк поставляется с широким спектром готовых красивых виджетов, которые поддерживают языки разработки платформ Android и iOS.

Чтобы иметь возможность использовать основные виджеты в вашем приложении, импортируйте библиотеку widgets , добавив следующий код в начало файла main.dart:

Простейшие виджеты, которые можно создать - это виджеты без указания состояния. Как вы уже догадались, с ними не связано состояние и таким образом они являются статическими. Они идеально подходят для отображения меток, названий и других элементов пользовательского интерфейса, содержание которых вряд ли изменится во время работы приложения. Для создания статического виджета, необходимо расширить класс StatelessWidget и переопределить его метод build() . В следующем примере кода показано, как:

Как вы можете видеть в приведенном выше коде, метод build() должен возвращать объект Widget . Вы можете выбрать и возвращать любой из десятков готовых виджетов, доступных в Flutter. Например, если вы хотите отобразить строку текста, можно создать и возвратить виджет Text , как показано ниже:

Обратите внимание, что вы всегда должны задавать направление текста при использовании виджета Text .

Однако, если вы запустите приложение прямо сейчас, вы не сможете увидеть текст. Это потому, что вы до сих пор не вызвали этот статический виджет. Итак, перейдите в метод main() , вызовите виджет внутри него и передайте его методу runApp() . Вот как:

В тот момент, как вы добавите приведенный выше код и сохраните ваш проект, Android Studio должна автоматически перезагрузить приложение на вашем устройстве, что позволит увидеть текст.

Если вы хотите отобразить изображение вместо текста, вы можете просто заменить виджет Text на виджет Image внутри метода build() вашего класса. Следующий код показывает, как создать виджет Image , который загружает и отображает удаленное изображение:

И снова, после сохранения вашего проекта, вы должны увидеть что-то вроде этого на вашем устройстве:

5. Создание деревьев виджетов

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

Flutter предлагает несколько виджетов, которые могут выступать в качестве контейнеров для других виджетов. Наиболее часто используемыми из них являются виджеты Row и Column . Как следует из названия, виджет Row позволяет размещать несколько виджетов рядом друг с другом, а виджет Column поможет вам разместить виджеты один под другим. Они незаменимы при создании многоуровневых деревьев виджетов.

Следующий код показывает, как использовать виджет Column для создания дерева виджетов, которое имеет два дочерних элемента: виджет Text и виджет Image .

Теперь приложение должно выглядеть следующим образом:

Кроме того, есть виджеты, которые служат для правильного расположения другого виджета. К примеру, виджет Center помогает вам расположить виджет по центру. Аналогично виджет Container позволяет добавлять отступы и поля для виджетов.

Следующий код показывает, как отцентрировать виджет Column , который вы только что создали, внедрив его внутрь виджета Center :

В приведенном выше коде обратите внимание, что виджет Column использует дополнительное свойство под названием mainAxisSize , значение которого задано в min . Это необходимо потому, что, прежде чем отцентрировать столбец, вы должны сделать его высоту равной сумме высот всех его дочерних элементов. Без такого свойства виджет Column будет иметь такой же размер, как экран устройства, и виджет Center не будет иметь никакого эффекта на него.

6. Использование виджетов Material Design

Все это время вы использовали основные виджеты, которые являются частью библиотеки widgets . Flutter имеет альтернативную библиотеку под названием material , которая предлагает виджеты Material Design. Чтобы использовать ее в вашем приложении, измените инструкцию, которая импортирует библиотеку widgets следующим образом:

Далее, чтобы применить стиль Material Design к вашим виджетам, вы должны иметь виджет MaterialApp в верхней части вашего дерева виджетов. Необходимо также внедрить все ранее созданные виджеты внутрь виджета Scaffold , который может служить в качестве домашнего экрана виджета MaterialApp .

Кроме того, поскольку большинство приложений Material Design имеют панель приложения, можно дополнительно указать в качестве значения свойства appBar виджета Scaffold новый виджет AppBar .

Следующий код показывает, как лаконично выполнить все эти задачи:

Приложение должно теперь выглядеть гораздо лучше.

7. Использование виджетов с указанием состояния

Статические виджеты являются неизменяемыми. Код, который вы написали в предыдущих шагах, не имеет простого способа изменить содержимое виджета Text или виджета Image . Почему? Потому что фреймворк Flutter отдает предпочтение реактивному программированию над императивным программированием. Следовательно большинство его виджетов не имеют методов установки значений, которые позволяют обновлять их содержимое во время выполнения программы. Например, виджет Text не имеет метода setText() , который позволил бы изменить отображаемый текст.

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

Чтобы создать виджет с указанием состояния, необходимо расширить класс StatefulWidget и переопределить его метод createState() .

Далее необходимо создать новый пользовательский класс State , который содержит переменные, которые формируют состояние такого виджета. Кроме того, внутри класса необходимо переопределить метод build() для возвращения вашего дерева виджетов.

Следующий код показывает, как создать класс State , содержащий одну переменную url :

Ради примера создадим дерево виджетов Material Design, содержащее виджет Image , который отображает случайное изображение, и виджет RaisedButton , который пользователь может нажать, чтобы загрузить новое случайное изображение. В следующем коде показано, как:

Обратите внимание, что конструктор виджета Image теперь принимает переменную url в качестве аргумента, вместо строкового значения. Это позволяет фреймворку использовать последнее значение переменной при каждом отображении виджета Image .

Также, обратите внимание, что виджет RaisedButton имеет атрибут onPressed , который указывает на регистратор события changeURL() . Сам метод еще не существует, так что создадим его.

Внутри метода вы должны, конечно, изменить значение переменной url . Однако вы не должны изменять его напрямую. Если вы это делаете, фреймворк Flutter не будет уведомлен об изменении. Для правильного обновления состояния виджета, вы всегда должны делать все ваши изменения внутри метода setState() .

Следующий код показывает, как сделать это с помощью штампа времени для построения уникальной строки запроса:

Теперь ваш пользовательский класс State готов. Все, что вам нужно сделать дальше — это создать его экземпляр и вернуть его из метода createState() вашего виджета с отслеживанием состояния.

Если передать методу runApp() экземпляр вашего виджета с отслеживанием состояния, перезагрузить приложение и нажать на кнопку несколько раз, вы должны увидеть, как каждый раз отображается новая фотография.

Заключение

Теперь вы знаете, как работать с виджетами как без указания состояния, так и с указанием состояния в приложениях Flutter. Вы также узнали, как применять к ним тему оформления Material Design, динамически изменять их содержимое и делать их интерактивными.

Стоит отметить, что Flutter не использует родные виджеты какой-либо мобильной платформы. Он создает все виджеты сам, используя высоко-производительный 2D графический движок Skia, который широко использует ресурсы GPU. В результате Flutter приложения часто выдают около 60 кадров в секунду и являются очень плавными и отзывчивыми в работе.

Чтобы узнать больше о виджетах в Flutter, обратитесь к официальной документации.

Я не могу найти ни одного примера, который показывает, как создать круг IconButton , похожий на FloatingActionButton . Кто-нибудь может подсказать, как/что нужно для создания пользовательской кнопки, такой как FloatingActionButton ?

Пример:

enter image description here

Я думаю, что лучше подходит RawMaterialButton.

Вы можете использовать InkWell , чтобы сделать это:

Прямоугольная область материала, который реагирует на прикосновение.

Ниже приведен пример использования InkWell . Обратите внимание: вам не нужно StatefulWidget , чтобы сделать это. Я использовал это, чтобы изменить состояние графа.

Если вы хотите воспользоваться преимуществами splashColor , highlightColor , оберните виджет InkWell , используя виджет Material с кругом типа материала. А затем удалите decoration в виджете Container .

Ключи во Flutter

Во Flutter есть много разных виджетов, но если вы посмотрите на свойства любого из них, вы, скорее всего, найдете параметр key (ключ).

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

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

Что такое ключи?

Если мы посмотрим на определение слова, Key написанное в официальной документации Flutter, оно гласит:

Ключ - это идентификатор для виджетов, элементов и семантических узлов.

Это означает, что Flutter различает виджеты и место их размещения в дереве виджетов по ключам. Но это еще не все.

Ключи сохраняют, состояние (state) когда вы перемещаетесь по дереву виджетов.

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

Сейчас давайте разберем разные типы ключей один за другим.

UniqueKey

UniqueKey используется для уникальной идентификации каждого виджета вашего приложения.

UniqueKey также сохраняет состояние при перемещении виджетов в дереве виджетов.

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

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

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

Разберем один пример:

Я собираюсь создать программу обмена смайликами, в которой на экране будут отображаться два смайлика и кнопка под ними, которая будет менять положение смайликов при нажатии.

Как и следовало ожидать, смайлы поменяются местами, когда мы нажмем кнопку.

Но проблема возникнет, если мы попытаемся преобразовать Stateless виджет в Stateful виджет и сохранить значение в state.

Смайлы не переключаются

Это произошло потому, что под капотом Flutter различает виджеты по типу (runtimeType) и по ключу.

В Stateful в нашем списке два виджета для смайлов. Когда мы меняем позиции смайликов, нажав на кнопку, Flutter видит в дереве виджетов и дереве элементов два виджета с одинаковым типом.

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

tree

Состояние начальное

После нажатия Flutter проверит типы виджетов.

tree 2

Состояние после нажатия кнопки

Когда я нажал на кнопку, Flutter обходит ElementTree, проверяет тип 😎 Text Element из ElementTree и видит, что он такой же , как 🤠 Text Widget, и поэтому ничего обновлять не будет.

Но. но если мы назовем эти два Stateful виджета по-разному. Тогда не будет проблем. Потому что обоих будут разные идентификаторы / ключи.

Чтобы обновить виджеты, которые имеют тот же тип внутри списка, мы должны присвоить UniqueKey всем виджетам.

Все снова работает

Что же произошло, - когда флаттер попытался сравнить типы виджетов они оказались одинаковыми. Но когда он начал сопоставлять ключи, они оказались разными. Флаттер понял, что это разные виджеты, изменил ссылки в дереве элементов и обновил приложение.

Обновление дерева виджетов Ключи не совпали Обновление дерева виджетов Замена элементов в дереве элементов

Куда ставить ключи

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

Объясню на примере:

Здесь я использовал предыдущий пример. Просто добавил цвет фона, который генерируется случайным образом.

Пока все работает:

Пока все работает

Теперь давайте обернем наши GetEmoji виджеты в Container.

А теперь давайте снова запустим приложение.

Вроде работает, но не корректно

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

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

Но, мы уже присвоили ключ виджету, правильно? Да, и проблема не в ключах, а в расположении самих ключей.

Так, что же происходит?

Вот структура дерева виджетов и элементов:

new tree

Дерево виджетов и элементов

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

На втором уровне Flutter замечает, что ключ 😎 Container Element не соответствует ключу виджета, поэтому он деактивирует этот 😎 Container Element, разрывая эти соединения.

Поскольку он не может найти на этом уровне Container Element с этим значением ключа, он создает новый и инициализирует новое состояние, в данном случае создавая виджет со случайным цветом фона.

tree upd

Решить эту проблему можно добавив key в Padding виджет.

Итак, мораль этой истории такова: ключи нужно добавлять выше по дереву виджетов.

ValueKey :

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

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

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

Пример

Нажимаем кнопку Remove Favourite Framework field.

Если вы заметили, мы получили Flutter в текстовом поле "Любимый язык" вместо Dart.

Примечание: это произойдет только в том случае, если вы используете несколько виджетов с отслеживанием состояния одного типа.

Мы должны предоставить этим виджетам уникальные значения, которые помогут флаттеру понять, что они разные.

Мы можем предоставить уникальные значения с помощью ValueKey .

Теперь, как мы видим, поле "Favorite Language" сохранило свое реальное значение, как и ожидалось.

В этом примере Flutter сначала проверит типы этих двух виджетов, одинаковы они или нет. Затем он проверит ключи, и обнаружив, что они разные Flutter обновит состояние и ссылки соответственно.

С ValueKey можно использовать любой тип уникальных значений: String, int, double, Objects и т.д.

Но все виджеты должны иметь уникальные значения. Это следует иметь в виду. Иначе ничего не получится.

Одна важная вещь, когда у нас есть список виджетов внутри Listview, Column или Row, постарайтесь не использовать в ключах значения index, поступающие из списка.

ObjectKey:

Ключ, который использует ссылку определенного типа для идентификации.

Я создал Список объектов SuperHero из класса SuperHero.

Эта программа поменяет местами первые два элемента в superHeroList.

Но если мы попытаемся поменять местами эти два элемента, что-то пойдет не так: вы увидите, что текст элемента меняется местами, а цвет - нет. А он тоже должен измениться, правда? Потому что цвет также связан с этим элементом списка.

Как мы обсуждали выше, флаттер не может различить виджеты одинаковых типов.

Тогда какое решение?

Вы можете подумать, что мы можем использовать ValueKey, верно? И да, вы правы, мы можем использовать ValueKey для различения виджетов в списке. Но есть один нюанс. Посмотрим, что будет, если мы используем ValueKey.

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

Но, что если теперь усложним и добавим в наш список Object.

Тогда на выходе получим:

Пример 6

И Flutter выдаст ошибку, примерно такую:

Ошибка

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

В данном случае мы добавили два одинаковых объекта с одинаковым значением. Вот почему Flutter выдает ошибку: " Эй, я нашел повторяющиеся ключи".

В таких случаях мы должны использовать ObjectKey .

Как следует из определения ObjectKey , этот ключ будет различать элементы на основе ссылок.

Давайте попробуем добавить ObjectKey :

И как только мы добавим, ObjectKey мы сможем увидеть результат. Теперь все работает нормально.

PageStorageKey

PageStorageKey в основном используется для сохранения позиции прокрутки прокручиваемых виджетов, таких как ListView или GridView и т.д.

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

Давайте рассмотрим пример, чтобы понять, как мы можем использовать PageStorageKey в приложении.

Здесь я создал простой Listview:

А теперь остановим список на середине и перейдем на другую вкладку.

Видите? Позиция списка не сохранилась.

Давайте решим эту проблему добавив PageStorageKey в ListView.

Теперь все отлично работает!

Это все, что вам нужно сделать, чтобы сохранить место прокрутки.

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

GlobalKey

Это наиболее часто используемый ключ во Flutter по сравнению с указанными выше ключами.

GlobalKey может быть использован для изменения родительских виджетов в любом месте вашего приложения без потери состояния.

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

Один из вариантов использования - GlobalKey это проверка Form или отображение Snackbar в приложении и т.д.

Теперь мы можем получить доступ к count значению CounterWidget на любой странице, передав GlobalKey.

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

Читайте также: