Flutter: переопределение кнопки «назад» в AppBar

Возникла ситуация: на одной из страниц (например авторизация) произошли изменения, касающиеся «стартового» экрана с изменением пунктов меню в drawer, ну и его шапке соотвественно. Но возник нюанс — при нажатии кнопки «назад» в AppBar, перерисовка меню не происходит.

Что будем делать? Одним из вариантов решения проблемы является перехват нажатия кнопки при помощи виджета WildPopScope и принудительная перерисовка при помощи вызова роутинга:

@override
  Widget build(BuildContext context) {
    // Переопределяем кнопку назад
    return WillPopScope(
      onWillPop: () {
        Navigator.pushNamed(context,'/');
        return Future.value(false);
      },
      child: Scaffold(
        appBar: AppBar(title: Text('Авторизация')),
        body: Center(
...

Flutter: работа с json

В предыдущей статье мы получили по URL json данные. Теперь задача их обработать.

{
"UserId":10,
"UserName":"Vasya Pukin"
}

Для работы с json, необходимо импортировать библиотеку:

import 'dart:convert';

Далее загрузим данные в тип Map:

 Map<String, dynamic> user = jsonDecode(response.body);
                        print (user["UserName"]);

А что если это массив?

[
  {"UserId":10,"UserName":"Vasya Pukin 1"},
  {"UserId":10,"UserName":"Vasya Pukin 2"}
  ]

В этом случае загрузим JSON в объет List:

                        List users = jsonDecode(response.body);
                        for(int i=0; i < users.length; i++){
                          print(users[i]["UserName"]);
                        }

Обратная конвертация:

                        String json = jsonEncode(user);
                        print (json);

Flutter: получение данных по http/https

Для обмена данными между клиентом (приложением) и сервером можно использовать пакеты http и http_parser. Для этого в зависимости добавляем пакеты:

dependencies:

 http: ^0.13.4
 http_parser: ^4.0.1

Для подключения в самом проекте нужно указать:

import 'package:http/http.dart' as http;

Ключевое слово as — указывает на то что подключаемые методы из пакета будут доступны через объект-имя http, к примеру:

В файл манифеста для Android, обязательно нужно добавить доступ в интернет:

<uses-permission android:name="android.permission.INTERNET" />
  • http.get(…)
  • http.post(…)
  • http.put(…)

Сетевые запросы к серверу медленные, потому результат запроса будет обрабатываться асинхронно после .then

 ElevatedButton(
                    onPressed: (){
                        http.post(Uri.parse('https://erferf.ru/1.json'),body: {'login':_controller1.text,'password':_controller2.text}).then((response) {
                        print("Response status: ${response.statusCode}");
                        print("Response body: ${response.body}");
                      }).catchError((error){
                        print("Error: $error");
                      });
                    },

Flutter: виды кнопок

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

В Flutter довольно таки большой выбор «стандартных» кнопок, код вызова которых в принципе идентичен

child:FlatButton(
              child:Text("Button"),
              onPressed: () {
              },
            )
FlatButton
RaisedButton
ElevatedButton
TextButton
OutlinedButton
FloatingActionButton

Flutter: ввод текста

За ввод текста во Flutter отвечает виджет TextField и соответствующий класс TextEditingController для управления вводом текста

Для примера отрисуем страницу авторизации. Сначала «Рыба»:

import 'package:flutter/material.dart';
import 'package:invent/globals.dart' as globals;

class Login extends StatefulWidget {
  _LoginState createState() => _LoginState(); // сюда передаем текущее состояние страницы
}
class _LoginState extends State<Login> {// _ впереди класса, означает чтоб скрыть доступ из другх файлов
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Авторизация')),
      body: Center(

      ),
    );
  }
}

Добавим надписи Логин и Пароль:

      body: Center(
        child: Padding(
          padding: EdgeInsetsDirectional.fromSTEB(10, 10, 10, 0),
          child: Column(
              children: [
                  Text('Логин:'),
                  Text('Пароль:',),
                ],
          ),
        ),
      ),

Далее необходимо рассказать о классе TextEditingController.

Данный класс имеет два конструктора:

TextEditingController({String text})
TextEditingController.fromValue(TextEditingValue value)

Первый конструктор в качестве параметра принимает начальное значение, которое затем будет отображаться в ассоциированном текстовом поле. Второй конструктор также принимает начальное значение, но в виде объекта TextEditingValue

TextEditingController позволяет контроллировать введенный и выделенный текст в поле ввода, для чего у него определены три свойства:

  • selection: выделенный текст в виде объекта TextSelection
  • text: текущий введенный текст в виде объекта String
  • value: текущее значение в виде объекта TextEditingValue

При изменении ввода в текстовом поле связанный объект TextEditingController уведомляет слушателей об изменении. Для добавления слушателей — функций обработного вызова в классе определен метод addListener(). Все добавленные слушатели могут считать введенный текст, а также выделенный текст и таким образом узнать о произошедших изменениях.

Когда объект TextEditingController больше не нужен, у него надо вызвать метод dispose(). Это позволит освободить все ресурсы, используемые объектом.

Таким образом модифицируем код, добавив поля ввода для логина и пароля:

class _LoginState extends State<Login> {// _ впереди класса, означает чтоб скрыть доступ из другх файлов
  final _controller1 = TextEditingController();
  final _controller2 = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Авторизация')),
      body: Center(
        child: Padding(
          padding: EdgeInsetsDirectional.fromSTEB(10, 10, 10, 0),
          child: Column(
              children: [
                  Text('Логин:'),
                  TextField(
                      style: TextStyle(fontSize: 22),
                      controller: _controller1
                  ),
                  Text('Пароль:',),
                  TextField(
                      style: TextStyle(fontSize: 22),
                      controller: _controller2
                  ),
                ],
          ),
        ),
      ),
    );
  }
}

Теперь создадим обработчики событий ввода и начальное заполнение контроллеров.

class _LoginState extends State<Login> {// _ впереди класса, означает чтоб скрыть доступ из другх файлов
  final _controller1 = TextEditingController();
  final _controller2 = TextEditingController();

  _changField(){
    print("-чтото повводили..");
  }

  @override
  void initState() {
    super.initState();
    _controller1.text = "Логин";
    _controller1.addListener(_changField);
    _controller2.text = "***";
    _controller2.addListener(_changField);
  }
  @override
  void dispose() {
    _controller1.dispose();
    _controller2.dispose();
    super.dispose();
  }

Результат:

Если поля ввода заполняются например из списка, то заполнение начальных значений и их сохранение можно организовать как-то так:

 TextField(
                                            style: TextStyle(fontSize: 22),
                                            controller: TextEditingController()..text = globals.ComfortList[index]["temp"].toString(),
                                            onChanged: (text) {
                                              globals.ComfortList[index]["temp"]=text;
                                              print("Введено: {$index},{$text}");
                                            }

Получится:

1 68 69 70 71 72 310