Разработайте свое первое приложение с помощью Flutter

внешний интерфейс IntelliJ IDEA Программа перевода самородков Flutter Material Design

Разработайте свое первое приложение с помощью Flutter

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

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

Разработаем дисплей пользователю изJSONPlaceholder APIПриложение, которое извлекает список сообщений в формате .

Что такое флаттер?

Flutter — это SDK, который позволяет разрабатывать нативные приложения на базе Android, iOS или следующей операционной системы Google, Fuschia. Он использует Dart в качестве основного языка программирования.

Установите необходимые инструменты

Git, Android Studio и XCode

Чтобы получить Flutter, вам нужно клонировать его официальный репозиторий. Если вы хотите разрабатывать приложения для Android, вам также понадобится Android Studio. Если вы разрабатываете приложения для iOS, вам также понадобится XCode.

IntelliJ IDEA

Вам также понадобится IntelliJ IDEA (это не обязательно, но может быть полезно). После установки IntelliJ IDEA добавьте подключаемые модули Dart и Flutter в IntelliJ IDEA.

Получить флаттер

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

git clone -b beta https://github.com/flutter/flutter.git

Затем вам нужно добавить путь к папке bin в переменную среды PATH. Вот и все, теперь вы можете приступить к разработке приложений с помощью Flutter.

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

разработать первый проект

Давайте теперь откроем IntelliJ IDEA и создадим наш первый проект. На левой панели выберите Flutter (если нет, установите плагины Flutter и Dart в свою IDE).

Назовем его следующим образом:

  • название проекта: feedme
  • описывать: A sample JSON API project
  • организация: net.gahfy
  • Язык Android: Kotlin
  • язык iOS: Swift

Запустите свой первый проект и изучите Flutter

Редактор IntelliJ открывает файл с именемmain.dartфайл, который является основным файлом приложения. Если вы еще не знакомы с Dart, не паникуйте, остальная часть этого руководства необходима время от времени.

Теперь подключите телефон Android или iOS к компьютеру или запустите эмулятор.

Теперь вы можете запустить приложение, нажав кнопку запуска (с зеленым треугольником) в правом верхнем углу:

Щелкните нижнюю плавающую кнопку действия, чтобы увеличить отображаемое число. Мы не будем сейчас углубляться в его код, но мы обнаружим некоторые интересные особенности Flutter.

Горячая перезагрузка флаттера

Как видите, основной цвет этого приложения — синий. Можем поменять на красный. существуетmain.dartфайле найдите следующий код:

return new MaterialApp(
  title: 'Flutter Demo',
  theme: new ThemeData(
    // This is the theme of your application.
    //
    // Try running your application with "flutter run". You'll see the
    // application has a blue toolbar. Then, without quitting the app, try
    // changing the primarySwatch below to Colors.green and then invoke
    // "hot reload" (press "r" in the console where you ran "flutter run",
    // or press Run > Flutter Hot Reload in IntelliJ). Notice that the
    // counter didn't reset back to zero; the application is not restarted.
    primarySwatch: Colors.blue,
  ),
  home: new MyHomePage(title: 'Flutter Demo Home Page'),
);

В этом разделе используйтеColors.redзаменитьColors.blue. Flutter позволяет вам загружать ваше приложение в горячем режиме, что означает, что текущее состояние приложения не будет изменено, но будет использоваться новый код.

В приложении нажмите кнопку +, плавающую внизу, чтобы увеличить счетчик.

Затем в правом верхнем углу IntelliJ нажмите кнопку Hot Reload (с желтой молнией). Ехать можно до тех пор, пока основной цвет не станет красным, но счетчик останется прежним.

Разработать окончательное приложение

давай удалим сейчасmain.dartВсе в файле, разве это не лучший способ узнать.

минимальное приложение

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

import 'package:flutter/material.dart';

Теперь давайте создадим наследствоStatelessWidgetкласс для создания экземпляра нашего приложения (подробнее об этом позжеStatelessWidget).

import 'package:flutter/material.dart';
 
class MyApp extends StatelessWidget {
 
}

IntelliJ IDEA показывает красную подчеркивание под MyApp. ФактическиStatelessWidgetнеобходимо реализоватьbuild()Абстрактный класс для методов. Для этого наведите курсор на MyApp и нажмите Alt+Enter.

import 'package:flutter/material.dart';
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
  }
}

Теперь давайте реализуемbuild()мы видим, что он должен возвращатьWidgetпример. Мы собираемся вернутьMaterialApp. С этой целью вbuild()Добавьте следующий код в:

return new MaterialApp();

MaterialAppДокументация говорит нам, по крайней мере, инициализироватьhome,routes,onGenerateRouteилиbuilder. Здесь мы определим толькоhomeАтрибуты. Это будет основной интерфейс приложения. Поскольку мы хотим, чтобы наше приложение было макетом на основе Material Design, мы поместилиhomeустановить на пустойScaffold:

import 'package:flutter/material.dart';
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new Scaffold()
    );
  }
}

Наконец, нам нужно установить, что при запуске main.dart мы хотим запускатьMyAppзаявление. Поэтому нам нужно добавить следующую строку после оператора импорта:

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

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

разработать пользовательский интерфейс

Несколько слов о статусе

Мы можем захотеть разработать два пользовательских интерфейса. Один — это пользовательский интерфейс, не связанный с текущим состоянием приложения, а другой — пользовательский интерфейс, связанный с текущим состоянием.

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

  • Событие запуска приложения: -Показать круговой индикатор выполнения
    • Запустить действие, которое извлекает сообщение
  • Конец запроса API:
    • В случае успеха отобразить результат получения сообщения
    • Если это не удается, отобразите Snackbar с сообщением об ошибке на пустом экране.

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

Инициализация StatefulWidget

Добавим наследствоStatefulWidgetКласс нашего приложения:

import 'package:flutter/material.dart';
 
void main() => runApp(new MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new PostPage()
    );
  }
}
 
class PostPage extends StatefulWidget {
  PostPage({Key key}) : super(key: key);
 
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
  }
}

Как мы видим, нам нужно реализовать возвратStateобъектcreateState()метод. Итак, давайте создадим наследствоStateтип:

class PostPage extends StatefulWidget {
  PostPage({Key key}) : super(key: key);
 
  @override
  _PostPageState createState() => new _PostPageState();
}
 
class _PostPageState extends State<PostPage>{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
  }
}

Как видите, нам нужно реализоватьbuild()метод, пусть он возвращает Widget . Для этого сначала создадим пустой виджет (Row):

class _PostPageState extends State<PostPage>{
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('FeedMe'),
        ),
        body: new Row()//TODO add the widget for current state
    );
  }
}

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

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

class _PostPageState extends State<PostPage>{
  Widget _getLoadingStateWidget(){
    return new Center(
      child: new CircularProgressIndicator(),
    );
  }
 
  Widget getCurrentStateWidget(){
    Widget currentStateWidget;
    currentStateWidget = _getLoadingStateWidget();
    return currentStateWidget;
  }
 
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('FeedMe'),
        ),
        body: getCurrentStateWidget()
    );
  }
}

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

показать список постов

Сначала мы определяемPostобъект, как он определен в JSONPlaceholder API. Для этого создайтеPost.dartдокумент:

class Post {
  final int userId;
 
  final int id;
 
  final String title;
 
  final String body;
 
  Post({
    this.userId,
    this.id,
    this.title,
    this.body
  });
}

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

class PostState{
  List<Post> posts;
  bool loading;
  bool error;
 
  PostState({
    this.posts = const [],
    this.loading = true,
    this.error = false,
  });
 
  void reset(){
    this.posts = [];
    this.loading = true;
    this.error = false;
  }
}

Все, что вам нужно сделать сейчас, этоPostStateОпределите метод в классе, чтобы получить его из APIPostсписок. Мы увидим, как это сделать позже, так как сейчас мы можем только асинхронно возвращать статическийPostСписок:

Future<void> getFromApi() async{
  this.posts = [
    new Post(userId: 1, id: 1, title: "Title 1", body: "Content 1"),
    new Post(userId: 1, id: 2, title: "Title 2", body: "Content 2"),
    new Post(userId: 2, id: 3, title: "Title 3", body: "Content 3"),
  ];
  this.loading = false;
  this.error = false;
}

Теперь, когда это сделано, давайте вернемся кmain.dartв файлеPostPageState类来看看如何使用我们刚定义的类。 мы вPostPageStateИнициализировать классpostStateАтрибуты:

class _PostPageState extends State<PostPage>{
  final PostState postState = new PostState();
 
  // ...
}

Если IntelliJ IDEA находится вPostStateподчеркнуто красным, что означаетPostStateКласс не определен в текущем файле. Так что вам нужно импортировать его. Наведите курсор на подчеркнутую красным часть и нажмите Alt+Enter, затем выберите «Импорт».

Теперь давайте определим метод, который, когда мы успешно получимPostВиджет возвращается, когда список:

Widget _getSuccessStateWidget(){
  return new Center(
    child: new Text(postState.posts.length.toString() + " posts retrieved")
  );
}

Если нам удастся получить список постов, а теперь нужно сделать, это редактироватьgetCurrentStateWidget()способ отображения этого виджета:

Widget getCurrentStateWidget(){
  Widget currentStateWidget;
  if(!postState.error && !postState.loading) {
    currentStateWidget = _getSuccessStateWidget();
  }
  else{
    currentStateWidget = _getLoadingStateWidget();
  }
  return currentStateWidget;
}

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

@override
void initState() {
  super.initState();
  _getPosts();
}
 
_getPosts() async {
  if (!mounted) return;
 
  await postState.getFromApi();
  setState((){});
}

Dangdang, вы можете запустить приложение, чтобы увидеть результаты. На самом деле, даже если отображается круглый индикатор выполнения, маловероятно, что его увидят. Это связано с тем, что извлечение списка сообщений выполняется настолько быстро, что почти сразу же исчезает.

Получить список сообщений из API

Чтобы убедиться, что круглый индикатор выполнения действительно отображается, давайте извлечем запись из JSONPlaceholder API. если мы посмотрим наПочтовый сервис API, мы видим, что он возвращает массив сообщений JSON.

Поэтому мы должны сначала добавить статический метод в класс Post, чтобы преобразовать массив JSON Post вPostСписок:

static List<Post> fromJsonArray(String jsonArrayString){
  List data = JSON.decode(jsonArrayString);
  List<Post> result = [];
  for(var i=0; i<data.length; i++){
    result.add(new Post(
        userId: data[i]["userId"],
        id: data[i]["id"],
        title: data[i]["title"],
        body: data[i]["body"]
    ));
  }
  return result;
}

Теперь нам просто нужно отредактировать поискPostStateв классеPostМетод списка, который фактически извлекает сообщения из API:

Future<void> getFromApi() async{
  try {
    var httpClient = new HttpClient();
    var request = await httpClient.getUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
    var response = await request.close();
    if (response.statusCode == HttpStatus.OK) {
      var json = await response.transform(UTF8.decoder).join();
      this.posts = Post.fromJsonArray(json);
      this.loading = false;
      this.error = false;
    }
    else{
      this.posts = [];
      this.loading = false;
      this.error = true;
    }
  } catch (exception) {
    this.posts = [];
    this.loading = false;
    this.error = true;
  }
}

Теперь вы можете запустить приложение и увидеть круговой индикатор выполнения в зависимости от скорости вашего интернета.

показать список постов

В настоящее время мы показываем только количество полученных сообщений, но не список сообщений, как мы ожидали. Чтобы иметь возможность отображать его, давайте отредактируемPostPageStateКатегория_getSuccessStateWidget()метод:

Widget _getSuccessStateWidget(){
  return new ListView.builder(
    itemCount: postState.posts.length,
    itemBuilder: (context, index) {
      return new Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          new Text(postState.posts[index].title,
            style: new TextStyle(fontWeight: FontWeight.bold)),
 
          new Text(postState.posts[index].body),
 
          new Divider()
        ]
      );
    }
  );
}

Если вы снова запустите приложение, вы увидите список сообщений.

обрабатывать ошибки

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

Widget _getErrorState(){
  return new Center(
    child: new Row(),
  );
}
 
Widget getCurrentStateWidget(){
  Widget currentStateWidget;
  if(!postState.error && !postState.loading) {
    currentStateWidget = _getSuccessStateWidget();
  }
  else if(!postState.error){
    currentStateWidget = _getLoadingStateWidget();
  }
  else{
    currentStateWidget = _getErrorState();
  }
  return currentStateWidget;
}

Теперь при возникновении ошибки отображается пустой интерфейс. Не стесняйтесь изменять содержимое для отображения интерфейса ошибки. Но мы сказали, что хотим показать Snackbar для повторной попытки в случае ошибки. Для этого давайтеPostPageStateразвитие в классеshowError()а такжеretry()метод:

class _PostPageState extends State<PostPage>{
  // ...
  BuildContext context;
 
  // ...
  _retry(){
    Scaffold.of(context).removeCurrentSnackBar();
    postState.reset()
    setState((){});
    _getPosts();
  }
 
  void _showError(){
    Scaffold.of(context).showSnackBar(new SnackBar(
      content: new Text("An unknown error occurred"),
      duration: new Duration(days: 1), // Make it permanent
      action: new SnackBarAction(
        label : "RETRY",
        onPressed : (){_retry();}
      )
    ));
  }
 
  //...
}

Как мы видим, нам нуженBuildContextполучитьScaffoldState, из-за чего Snackbar появляется и исчезает. Но мы должны использоватьScaffoldобъектBuildContextполучитьScaffoldState. Для этого нам нужно отредактироватьPostPageStateКатегорияbuild()метод:

Widget currentWidget = getCurrentStateWidget();
return new Scaffold(
    appBar: new AppBar(
      title: new Text('FeedMe'),
    ),
    body: new Builder(builder: (BuildContext context) {
      this.context = context;
      return currentWidget;
    })
);

Теперь запустите приложение в режиме полета, и теперь оно покажет Snackbar. Если вы выйдете из режима полета и нажмете «Повторить попытку», вы сможете увидеть публикацию.

Суммировать

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

Проект - все исходный код можно найти вFeed-Me Flutter project on GitHubполучать.


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


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