美文网首页跨平台
Flutter了解之小练习

Flutter了解之小练习

作者: 平安喜乐698 | 来源:发表于2020-10-31 08:12 被阅读0次

1. 实现一个可以收藏、无限滚动的随机单词列表,点击收藏按钮进入收藏页。

步骤

第一步:使用Android Studio创建项目。显示Hello World。
第二步:添加english_words依赖包,创建一个StatefulWidget。将Hello World改为随机字符串
第三步:创建一个ListView,点击收藏按钮跳转到收藏页
最终效果

第一步:使用Android Studio创建项目

选择 Start a new Flutter project 选择 Flutter Application 初始根目录 初始项目结构 模拟器运行

修改main.dart

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.yellow,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Home"),
      ),
      body: new Center(
        child: new Text('Hello World'),
      ),
    );
  }
}
运行

第二步:添加english_words依赖包,创建一个StatefulWidget(显示随机字符串)

1. pubspec.yaml文件将“english_words”(3.1.5版本)添加到依赖项列表,如下:
  dependencies:
    flutter:
      sdk: flutter
    cupertino_icons: ^0.1.0
    # 新添加的依赖
    english_words: ^3.1.5

2. 下载包。在Android Studio的编辑器视图中查看pubspec.yaml时,单击右上角的  Get dependencies 。这会将依赖包安装到项目。
命令行对应的命令:flutter packages get

3. main.dart文件中引入english_words包。
import 'package:english_words/english_words.dart';

4. 创建一个StatefulWidget,显示随机字符串
class RandomWordsWidget extends StatefulWidget {
  @override
  createState() => new RandomWordsState();
}
class RandomWordsState extends State<RandomWordsWidget> {
  @override
  Widget build(BuildContext context) {
    final wordPair = new WordPair.random();
    return new Text(wordPair.asPascalCase);
  }
}
修改MyHomePage
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final wordPair = new WordPair.random();
    return Scaffold(
      appBar: AppBar(
        title: Text("Home"),
      ),
      body: new Center(
        child: new RandomWordsWidget(),
      ),
    );
  }
}
Pub搜索english_words
pubspec.yaml添加依赖
下载依赖包
运行

第三步:创建一个ListView,点击收藏按钮跳转到收藏页

修改MyHomePage

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new RandomWordsWidget();
  }
}
修改RandomWordsState

添加属性
  // 存储单词
  final _suggestions = <WordPair>[];
  // 存储收藏的单词。Set比List更合适,因为Set中不允许重复的值。
  final _saved = new Set<WordPair>();
  // 字体大小
  final _biggerFont = const TextStyle(fontSize: 18.0);

添加方法(显示ListView)
  // 自定义方法:返回显示单词的ListView
  Widget _buildSuggestions() {
    return new ListView.builder(
        padding: const EdgeInsets.all(16.0),
        /*
        对于每个单词对都会调用一次itemBuilder,然后将单词对添加到ListTile行中

        在偶数行,该函数会为单词对添加一个ListTile row.
        在奇数行,该函数会添加一个分割线widget,来分隔相邻的词对。
        注意,在小屏幕上,分割线看起来可能比较吃力。

        i从0开始,每调用一次会自增1
         */
        itemBuilder: (context, i) {
          // 在每一列之前,添加一个1像素高的分隔线widget
          if (i.isOdd) return new Divider();

          /*
          语法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),比如i为:1, 2, 3, 4, 5时,结果为0, 1, 1, 2, 2。
          这可以计算出ListView中减去分隔线后的实际单词对数量
           */
          final index = i ~/ 2;
          // 如果是列表中最后一个单词,接着再生成10个单词,然后添加到收藏列表,无限循环。
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }
          return _buildRow(_suggestions[index]);
        }
    );
  }
  // 自定义方法(每一行的UI)
  Widget _buildRow(WordPair pair) {
    // 检查确保单词对有没有添加到收藏夹中
    final alreadySaved = _saved.contains(pair);
    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
      // 尾部设置一个收藏图标
      trailing: new Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      // 点击后调用(收藏/取消收藏)
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }

添加方法(跳转)
  // 自定义方法(跳转至收藏页)
  void _pushSaved() {
    Navigator.of(context).push(
      new MaterialPageRoute(
        builder: (context) {
          final tiles = _saved.map(
                (pair) {
              return new ListTile(
                title: new Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );
          final divided = ListTile
              .divideTiles(
            context: context,
            tiles: tiles,
          )
              .toList();
          return new Scaffold(
            appBar: new AppBar(
              title: new Text('CollectionPage'),
            ),
            body: new ListView(children: divided),
          );
        },
      ),
    );
  }

修改build方法
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Home'),
        // 收藏按钮
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions(),
    );
  }
列表页 收藏页

2. 布局练习

实现效果 取消收藏

分析布局

最外层使用ListView(默认:纵向滚动),允许滚动(保证在小屏幕手机上也可以查看超出屏幕的内容)。

分为4部分:
  1. 图片
  2. 标题、副标题、图标和收藏个数
  3. 3个按钮(上面图标,下面文字)
  4. 介绍

步骤

1. 项目根目录下创建imgs目录,存放timg.jpg

2. pubspec.yaml文件下配置timg.jpg图片
flutter:
  assets:
    - imgs/timg.jpg
3. main.dart文件内容如下,主要工作在children中

import 'package:flutter/material.dart';

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.orange,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //。。。

    return new Scaffold(
        // ListView:可滚动
        body: new ListView(
          children: [
            // 。。。
          ],
        ),
    );
  }}
4. 图片
在build下创建,然后添加imgSection到children中


Widget imgSection = new Image.asset(
  'imgs/timg.jpg',
  height: 240.0,
  fit: BoxFit.cover,
);
5. 标题、副标题、图标和收藏个数
在build下创建,然后添加titleSection到children中


Widget titleSection = new Container(
  padding: const EdgeInsets.all(32.0),
  child: new Row(
    children: [
      // Expanded:占满额外的空间(占满除了图标喝收藏个数之外的空间)
      new Expanded(
        child: new Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            new Container(
              padding: const EdgeInsets.only(bottom: 8.0),
              child: new Text(
                '东北虎',
                style: new TextStyle(
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            new Text(
              '又称西伯利亚虎',
              style: new TextStyle(
                color: Colors.grey[500],
              ),
            ),
          ],
        ),
      ),
      new Icon(
        Icons.star,
        color: Colors.yellow[500],
      ),
      new Text('110'),
    ],
  ),
);
6. 3个按钮(上面图标,下面文字)
在build下创建,然后添加buttonSection到children中


Column buildButtonColumn(IconData icon, String label) {
  Color color = Theme.of(context).primaryColor;

  return new Column(
    mainAxisSize: MainAxisSize.min,
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      new Icon(icon, color: color),
      new Container(
        margin: const EdgeInsets.only(top: 8.0),
        child: new Text(
          label,
          style: new TextStyle(
            fontSize: 12.0,
            fontWeight: FontWeight.w400,
            color: color,
          ),
        ),
      ),
    ],
  );
}
Widget buttonSection = new Container(
  child: new Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      buildButtonColumn(Icons.description, '详情'),
      buildButtonColumn(Icons.near_me, '路线'),
      buildButtonColumn(Icons.share, '分享'),
    ],
  ),
);
7. 介绍
在build下创建,然后添加buttonSection到children中


Widget textSection = new Container(
  padding: const EdgeInsets.all(32.0),
  child: new Text(
    '''
    虎(学名:Panthera tigris ;英文名:Tiger):是哺乳纲的大型猫科动物;毛色浅黄或棕黄色,满身黑色横纹;头圆、耳短,耳背面黑色,中央有一白斑甚显著;四肢健壮有力;尾粗长,具黑色环纹,尾端黑色。老虎是典型的山地林栖动物,由南方的热带雨林、常绿阔叶林,以至北方的落叶阔叶林和针阔叶混交林,都能很好的生活。在中国东北地区,也常出没于山脊、矮林灌丛和岩石较多或砾石塘等山地,以利于捕食。虎常单独活动,只有在繁殖季节雌雄才在一起生活。无固定巢穴,多在山林间游荡寻食。能游泳。由于林区开发、人口激增,过去偏远地区都已发展为村镇,虎亦常到林区居民点附近觅食。虎多黄昏活动,白天多潜伏休息,没有惊动则很少出来。虎的活动范围较大,在北方日寻食活动范围可达数十公里;在南方西双版纳因食物较多则活动距离较短。
    ''',
    softWrap: true,
  ),
);
8. 使收藏按钮可点击
创建一个有状态组件(包含收藏图标和个数),使用FavoriteWidget()替换上面代码中的相应部分。


class FavoriteWidget extends StatefulWidget {
  @override
  _FavoriteWidgetState createState() => new _FavoriteWidgetState();
}

// _开头代表私有
class _FavoriteWidgetState extends State<FavoriteWidget> {
  // 是否收藏
  bool _isFavorited = true;
  // 收藏个数
  int _favoriteCount = 110;

  // 点击收藏按钮后调用
  void _toggleFavorite() {
    // 改变状态值,更新UI
    setState(() {
      if (_isFavorited) {
        _favoriteCount -= 1;
        _isFavorited = false;
      } else {
        _favoriteCount += 1;
        _isFavorited = true;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        new Container(
          padding: new EdgeInsets.all(0.0),
          child: new IconButton(
            icon: (_isFavorited
                ? new Icon(Icons.star)
                : new Icon(Icons.star_border)),
            color: Colors.yellow[500],
            onPressed: _toggleFavorite,
          ),
        ),
        // 将文本放在SizedBox中并设置其宽度可防止出现明显的跳跃
        new SizedBox(
          width: 25.0,
          child: new Container(
            child: new Text('$_favoriteCount'),
          ),
        ),
      ],
    );
  }
}

相关文章

网友评论

    本文标题:Flutter了解之小练习

    本文链接:https://www.haomeiwen.com/subject/daydyktx.html