Magic-8-Ball был выбран в качестве первой истории серии Flutter, потому что предыдущие задания/проекты были немного недостаточны с точки зрения предоставления большого количества полезных деталей. Итак, давайте посмотрим на исходный код.

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

void main() => runApp(
      MaterialApp(
        home: BallPage(),
      ),
    );

class BallPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue[900],
        title: Text("Ask Me Anything"),
      ),
      body: Ball(),
      backgroundColor: Colors.blue,
    );
  }
}

class Ball extends StatefulWidget {
  @override
  _BallState createState() => _BallState();
}

class _BallState extends State<Ball> {
  int ballNumber = 1;
  @override
  Widget build(BuildContext context) {
    return Center(
      child: FlatButton(
        onPressed: () {
          setState(() {
            ballNumber = Random().nextInt(4) + 1;
          });
        },
        child: Image.asset("images/ball$ballNumber.png"),
      ),
    );
  }
}

Шаг 1 — Настройка

Сначала я скачал скелет проекта из репозитория git appbrewery. Скелетный код выглядит так:

import 'package:flutter/material.dart'; 
void main() => runApp(      
MaterialApp(        
home: null,      
),    
);

Там почти ничего нет, кроме MaterialApp, который является основой практически для всего. MaterialApps — важная основа, потому что именно их задумал разработчик Google, чтобы дать нам своего рода блокнот для разработки приложений.

Шаг 2 — Создайте виджет без сохранения состояния

Это легко. Все, что мне нужно было сделать, это ввести «stless» где-нибудь в файле main.dart и автозаполнить остальную часть кода виджета без сохранения состояния. Виджет без сохранения состояния назывался BallPage. Затем в MaterialApp вы можете увидеть, что свойство «home» имеет значение «null». Я изменил это нулевое значение на BallPage, чтобы этот виджет без сохранения состояния теперь стал домом для этого MaterialApp.

Следующая часть этого шага — некоторые раскраски. Давайте взглянем на готовую часть кода виджета без сохранения состояния.

class BallPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Вы можете видеть, что внутри метода сборки он возвращает только контейнер. Давайте исправим это и добавим AppBar (у которого есть backgroundColor и заголовок) и body (у которого пока есть Container) и свой собственный backgroundColor.

class BallPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue[900],
        title: Text("Ask Me Anything"),
      ),
      body: Container(),
      backgroundColor: Colors.blue,
    );
  }
}

Вот диаграмма.

Крутая вещь. Идем дальше.

Шаг 3 — Создайте виджет с отслеживанием состояния

Точно так же, как я создал файл без гражданства, я использовал для этого ярлык «stful». Взгляните на автозаполнение по умолчанию.

class Ball extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Помните Контейнер для тела виджета без сохранения состояния? Пришло время изменить это.

class BallPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue[900],
        title: Text("Ask Me Anything"),
      ),
      body: Ball(),
      backgroundColor: Colors.blue,
    );
  }
}

Теперь BallPage будет иметь виджет с состоянием Ball в качестве тела. Давайте перейдем к виджету Ball с состоянием, сделаем его центрированным и добавим FlatButton. Давайте также сделаем эту FlatButton изображением шара-восьмерки.

class Ball extends StatefulWidget {
  @override
  _BallState createState() => _BallState();
}

class _BallState extends State<Ball> {
  int ballNumber = 1;
  @override
  Widget build(BuildContext context) {
    return Center(
      child: FlatButton(
        child: Image.asset("images/ball1.png"),
      ),
    );
  }
}

Шаг 4 — Сделайте его интерактивным

Внутри FlatButton вам нужно «onPressed: () {}», внутри которого также должно быть что-то, что изменяет какое-то состояние… что-то вроде «setState (() {});»

class _BallState extends State<Ball> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: FlatButton(
        onPressed: () {
          setState(() {
            
          });
        },
        child: Image.asset("images/ball1.png"),
      ),
    );
  }
}

Шаг 5 — Рандомизируйте это

Пришло время импортировать математическую библиотеку.

import 'dart:math';

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

class Ball extends StatefulWidget {
  @override
  _BallState createState() => _BallState();
}

class _BallState extends State<Ball> {
  int ballNumber = 1;
  @override
  Widget build(BuildContext context) {
    return Center(
      child: FlatButton(
        onPressed: () {
          setState(() {
            ballNumber = Random().nextInt(4) + 1;
          });
        },
        child: Image.asset("images/ball$ballNumber.png"),
      ),
    );
  }
}

Это оно! Проект завершен.