Фактический бой флаттера создает «остров» приложение с нуля (NO.1, инициализация проекта, адаптация экрана)

Flutter
Фактический бой флаттера создает «остров» приложение с нуля (NO.1, инициализация проекта, адаптация экрана)

рекомендации по чтению

Цели главы

Мы закончим эту часть дальше

0102.gif

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

написать впереди

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

  • Научный Интернет: не спрашивайте почему, потому что этот шаг особенно важен как развитие
  • Ду Вэнь, автор книги «Флаттер в действии» (псевдоним)wendux): Эта книга очень подходит для начинающих, чтобы познакомиться с различными частями Flutter. Это будет отличаться от нашего HTML
  • Китайское сообщество флаттера:китайское сообщество: Будут некоторые видео-ресурсы и рекомендации по плагинам.
  • Технический блог Flutter Salted Fish TeamКоманда соленой рыбы Alibaba: Как мы все знаем, такие приложения, как Xianyu, разрабатываются с использованием технологии Flutter в Китае, и их вклад в большое семейство Flutter также особенно важен.

Эта статья - первый абзац этого путешествия, потому что автор не знает, какой прогресс будет развиваться, но постарайтесь обновлять каждую неделю, давайте учиться вместе, lets_do_it

Инициализация проекта

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

0101.png

каталог проекта

0102.png

После того, как проект создан, по-прежнему старый способ удалить бесполезный код.Основной кодmain.dart

TIM截图20191116190242.png

Здесь мы можем задать уровень виртуальной машины, который нам удобен для отладки

TIM截图20191116190432.png

держи это всегда на высоте

Структура каталогов

Начните создавать знакомые папки

TIM截图20191116190802.png

  • models — это в основном класс Model, в котором размещен проект, поэтому нам не очень хорошо напрямую манипулировать JSON, возвращаемым фоном в проекте.
  • страницы в основном для размещения некоторых файлов страниц, включая домашнюю страницу, список книг, лайки
  • провайдер в основном размещает глобальное управление состоянием
  • Общие классы методов в проекте utils
  • виджеты общие виджеты

Установка зависимостей

Мы можем попробовать добавить эти два URL-адреса в закладки.

  • pubВ нашем проекте также используются некоторые сторонние плагины и пакеты.
  • hubВключая отличные проекты, такие как Flutter-go, я слышал, что пользователи appid могут подать заявку на использование APP через официальные каналы.
имя плагина адрес
flutter_screenutil flutter_screenutil экранизация
curved_navigation_bar curved_navigation_bar Нижняя панель навигации
provider provider государственное управление
shared_preferences shared_preferences локальная настойчивость
dio dio сетевой запрос
fluro fluro структура маршрутизации
. . .

Парсинг основного файла

Мы инициализировали проект выше, очевидно, что черный цвет немного уродлив, не соответствует нашей эстетике, взглянитеMaterialApp

Внешний API

  const MaterialApp({
    Key key,
    this.navigatorKey,
    this.home, 
    this.routes = const <String, WidgetBuilder>{},
    this.initialRoute,
    this.onGenerateRoute,
    this.onUnknownRoute,
    this.navigatorObservers = const <NavigatorObserver>[],
    this.builder,
    this.title = '',
    this.onGenerateTitle,
    this.color,
    this.theme,
    this.darkTheme,
    this.themeMode = ThemeMode.system,
    this.locale,
    this.localizationsDelegates,
    this.localeListResolutionCallback,
    this.localeResolutionCallback,
    this.supportedLocales = const <Locale>[Locale('en', 'US')],
    this.debugShowMaterialGrid = false,
    this.showPerformanceOverlay = false,
    this.checkerboardRasterCacheImages = false,
    this.checkerboardOffscreenLayers = false,
    this.showSemanticsDebugger = false,
    this.debugShowCheckedModeBanner = true,

  • главная Это должна быть домашняя страница
  • Является ли initialRoute исходным маршрутом? Может быть, мы сможем использовать его позже, когда будем писать маршрут.
  • название Это должно быть название
  • цвет цвет
  • тема есть тема

APP, по нашему мнению, делится на верхнюю, среднюю и нижнюю части, точно так же, как наша голова, тело и ноги.

Тогда давайте начнем писать мою домашнюю страницу

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

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

// 这里我们用StatelessWidget,我是一个没有状态的"孩子"
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '孤岛',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHome(),
    );
  }
}

class MyHome extends StatefulWidget {
  MyHome({Key key}) : super(key: key);

  @override
  _MyHomeState createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('孤岛APP'),
      ),
    );
  }
}

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

Затем напишите его в папке pages

lib
├── pages
├────book_list_page.dart
├────home_page.dart
├────love_page.dart

TIM截图20191116195314.png

Исходный код для каждой страницы выглядит так

  • book_list_page.dart
import 'package:flutter/material.dart';

class BookListPage extends StatefulWidget {
  BookListPage({Key key}) : super(key: key);

  @override
  _BookListPageState createState() => _BookListPageState();
}

class _BookListPageState extends State<BookListPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('我是书单'),
      ),
    );
  }
}

  • home_page.dart
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('我是首页'),
      ),
    );
  }
}

  • love_page.dart
import 'package:flutter/material.dart';

class LovePage extends StatefulWidget {
  LovePage({Key key}) : super(key: key);

  @override
  _LovePageState createState() => _LovePageState();
}

class _LovePageState extends State<LovePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('我是喜欢'),
      ),
    );
  }
}

Нижняя панель навигации

Здесь мы используем **curved_navigation_bar** это колесо

Сначала добавьте зависимости

dependencies:
  curved_navigation_bar: ^0.3.1 #latest version

TIM截图20191116200144.png

В начале мы сказали, что некоторые общие детали, которые мы вставляемwidgetsфайл, то мы планируем поместить его в папку общедоступных частей и назвать егоwidget_bottom_navigation_bar.dart

импортировать в голову файла

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

import '../pages/home_page.dart';
import '../pages/book_list_page.dart';
import '../pages/love_page.dart';

Весь код в нем


/// 在这里我们生命一个有状态的部件,因为其中会牵扯到index的改变
class BottomNavBarWidget extends StatefulWidget {
  BottomNavBarWidget({Key key}) : super(key: key);

  @override
  _BottomNavBarWidgetState createState() => _BottomNavBarWidgetState();
}

class _BottomNavBarWidgetState extends State<BottomNavBarWidget>
    with SingleTickerProviderStateMixin {
  /// 这里声明一个控制器,在flutter中好多用到控制器的地方,包括像最常见的表单
  TabController tabController;

  /// 这里把我们引入的三个页面放进List集合里,等候发落
  List _pages = [HomePage(), BookListPage(), LovePage()];

  /// 这个就是比较核心的索引了,默认值就是我们的首页
  int currentIndex = 0;

  @override
  void initState() {
    super.initState();
    tabController = TabController(vsync: this, length: 3)
      ..addListener(() {
        /// setState 这里有点像咱们 的React,更改数据的时候是要在setState()里
        setState(() {
          currentIndex = tabController.index;
        });
      });
  }

  // 这里是一个部件,返回的值类型是个Widget是用Scaffold包着的,里边也是界面的核心
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        bottomNavigationBar: CurvedNavigationBar(
          // backgroundColor: _pages[currentIndex],
          index: currentIndex,
          // 底部按钮
          items: <Widget>[
            Image.asset(
              'images/bottom_nav/home@light.png',
              width: 50,
              height: 50,
            ),
            Image.asset(
              'images/bottom_nav/book_list@light.png',
              width: 50,
              height: 50,
            ),
            Image.asset(
              'images/bottom_nav/love@light.png',
              width: 50,
              height: 50,
            ),
          ],

          /// 点击不同的底部导航
          onTap: (index) {
            //Handle button tap
            setState(() {
              currentIndex = index;
            });
            tabController.animateTo(index,
                duration: Duration(milliseconds: 300), curve: Curves.ease);
          },
        ),
        // 主体部分,就是文中我们所说的人的身体一样
        body: TabBarView(
          controller: tabController,
          children: <Widget>[
            Container(
              child: _pages[0],
            ),
            Container(
              child: _pages[1],
            ),
            Container(
              child: _pages[2],
            )
          ],
        ));
  }
}

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

TIM截图20191116201616.png

  • Проект: Список виджетов
  • index: индекс NavigationBar, который можно использовать для изменения текущего индекса или установки начального индекса.
  • Цвет: цвет панели навигации, по умолчанию — Colors.white.
  • buttonBackgroundColor: цвет фона плавающей кнопки, по умолчанию используется свойство color.
  • backgroundColor: фон NavigationBar, по умолчанию Colors.blueAccent.
  • onTap: функция обрабатывает щелчок по элементу
  • animationCurve: кнопка интерполяции кривой изменяет анимацию, по умолчанию Curves.easeOutCubic
  • animationDuration: продолжительность анимации изменения кнопки, по умолчанию Duration (миллисекунды: 600)
  • высота: высота панели навигации, минимальное значение – 0,0, максимальное – 75,0.

Импорт локальных изображений

Необходимо узнать о картинках, которые мы представили выше

 Image.asset(
              'images/bottom_nav/book_list@light.png',
              width: 50,
              height: 50,
            ),

то естьimages/bottom_nav/book_list@light.png,

  • Создайте проект в корневом каталоге проектаimages目录, и скопируйте нужные изображения в этот каталог

  • существуетpubspec.yamlсерединаflutterЧастично добавить следующее:

      assets:
        - images/bottom_nav/home@light.png
        - images/bottom_nav/book_list@light.png
        - images/bottom_nav/love@light.png
    
  • загрузить это изображение

    • Image(
        image: AssetImage("images/avatar.png"),
        width: 100.0
      );
      
    • Image.asset("images/avatar.png",
        width: 100.0,
      )
      

Пока что мы разработали ее часть, и никаких камней преткновения мы не встретили Вот так она выглядит сейчас в "Lone Island APP"

0101.gif

экранизация

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

Здесь мы используем flutter_ScreenUtil

Решение для адаптации экрана флаттера позволяет вашему пользовательскому интерфейсу отображать разумную компоновку на экранах разных размеров!

Поговорим о том, как использовать

  • ширина ширина ScreenUtil.getInstance().setWidth(540)
  • высота высота ScreenUtil.getInstance().setHeight(200)
  • размер шрифта
//长方形:
Container(
           width: ScreenUtil.getInstance().setWidth(375),
           height: ScreenUtil.getInstance().setHeight(200),
            ),
            
//如果你想显示一个正方形:
Container(
           width: ScreenUtil.getInstance().setWidth(300),
           height: ScreenUtil.getInstance().setWidth(300),
            ),
//传入字体大小,默认不根据系统的“字体大小”辅助选项来进行缩放(可在初始化ScreenUtil时设置allowFontScaling)
ScreenUtil.getInstance().setSp(28)         
 
//传入字体大小,根据系统的“字体大小”辅助选项来进行缩放(如果某个地方不遵循全局的allowFontScaling设置)     
ScreenUtil(allowFontScaling: true).setSp(28)   

Внесите в файл, который необходимо адаптировать

import 'package:flutter_screenutil/flutter_screenutil.dart';

Здесь следует отметить, что инициализацию размера адаптации мы прописали в нижней навигации

TIM截图20191116222116.png

Затем мы адаптируем три экрана изображения внизу

    items: <Widget>[
            Image.asset(
              'images/bottom_nav/home@light.png',
              width: ScreenUtil.getInstance().setWidth(100),
              height: ScreenUtil.getInstance().setHeight(100),
            ),
            Image.asset('images/bottom_nav/book_list@light.png',
                width: ScreenUtil.getInstance().setWidth(100),
                height: ScreenUtil.getInstance().setHeight(100)),
            Image.asset('images/bottom_nav/love@light.png',
                width: ScreenUtil.getInstance().setWidth(100),
                height: ScreenUtil.getInstance().setHeight(100)),
          ],

Итак, теперь нам нужно разобраться со шрифтом головы, верно?

  • Ввести import 'package:flutter_screenutil/flutter_screenutil.dart';
  • Специфическая адаптация
 title: Text(
        '我是首页',
        style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36)),
      ),

TIM截图20191116223249.png

Там что-то внутри, верно?

DEBUG в правом верхнем углу

В MaterialApp установите для параметра debugShowCheckdModeBanner значение false.

Вот ссылка для ознакомленияКак удалить метку отладки в приложении флаттера

В конце этого путешествия давайте усовершенствуем этот «Остров».

    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text(
          '首页',
          style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(36)),
        ),
      ),
      body: Container(
        height: ScreenUtil.getInstance().setHeight(1334),
        width: ScreenUtil.getInstance().setWidth(750),
        child: Image.network(
          'https://i.demo-1s.com/2019/11/16/yjhPSQWjuqPmosIL.jpg',
          fit: BoxFit.cover,
        ),
      ),
    );

напиши в конце

Этот участок дороги, мы придем сюда вместе, автор будет продолжать обновлять, пожалуйста, обратите больше внимания, соответствующий код также будет обновлен доавторский склад,GitHub.com/AsianStudent/грипп ТТ…

Если тебе это нравится, ты можешь меня подбодрить, так что давай помолодеем~~

END

Советы: для некоторых идей есть несколько отличных постов в блогах. Если они неуместны, вы также можете сослаться на автора.siteОставьте сообщение, чтобы поблагодарить открытый исходный код, спасибо всем