文章目录
-
- 如下选项创建,按步骤操作即可;
- 具体教程去看https://flutterchina.club/get-started/codelab/,我这里只贴出Main.dart文件!其他按需修改! import 'package:flutter/material.dart'; import 'package:english_words/english_words.dart'; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Startup Name Generator', // 使用主题更改UI theme: new ThemeData( primaryColor: Colors.white, ), home: RandomWords(), ); } } //添加一个 有状态的部件(Stateful widget) class RandomWords extends StatefulWidget { @override _RandomWordsState createState() => _RandomWordsState(); } class _RandomWordsState extends State<RandomWords> { final _suggestions = <WordPair>[]; final _biggerFont = TextStyle(fontSize: 18.0); final _saved = new Set<WordPair>();// 添加一个 _saved Set(集合) 到RandomWordsState。这个集合存储用户喜欢(收藏)的单词对。 在这里,Set比List更合适,因为Set中不允许重复的值。 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Startup Name Generator'), // 在RandomWordsState的build方法中为AppBar添加一个列表图标。当用户点击列表图标时,包含收藏夹的新路由页面入栈显示。 actions: [ // NEW lines from here... IconButton(icon: Icon(Icons.list), onPressed: _pushSaved), ], // ... to here. ), body: _buildSuggestions(), ); } Widget _buildSuggestions() { return ListView.builder( padding: EdgeInsets.all(16.0), itemBuilder: /*1*/ (context, i) { if (i.isOdd) return Divider(); /*2*/ final index = i ~/ 2; /*3*/ if (index >= _suggestions.length) { _suggestions.addAll(generateWordPairs().take(10)); /*4*/ } return _buildRow(_suggestions[index]); }); } Widget _buildRow(WordPair pair) { final alreadySaved = _saved.contains(pair);//在 _buildRow 方法中添加 alreadySaved来检查确保单词对还没有添加到收藏夹中。 return ListTile( title: Text( pair.asPascalCase, style: _biggerFont, ), // 同时在 _buildRow()中, 添加一个心形 ❤️ 图标到 ListTiles以启用收藏功能。接下来,你就可以给心形 ❤️ 图标添加交互能力了 trailing: new Icon( alreadySaved ? Icons.favorite : Icons.favorite_border, color: alreadySaved ? Colors.red : null, ), // 重新启动应用。你现在可以在每一行看到心形❤️图标️,但它们还没有交互。 // 在 _buildRow中让心形❤️图标变得可以点击。如果单词条目已经添加到收藏夹中, 再次点击它将其从收藏夹中删除。当心形❤️图标被点击时,函数调用setState()通知框架状态已经改变。 onTap: () { setState(() { if (alreadySaved) { _saved.remove(pair); } else { _saved.add(pair); } }); }, ); } // 向RandomWordsState类添加一个 _pushSaved() 方法. // 热重载应用,列表图标将会出现在导航栏中。现在点击它不会有任何反应,因为 _pushSaved 函数还是空的。 void _pushSaved() { Navigator.of(context).push( MaterialPageRoute<void>( // NEW lines from here... builder: (BuildContext context) { final tiles = _saved.map( (WordPair pair) { return ListTile( title: Text( pair.asPascalCase, style: _biggerFont, ), ); }, ); final divided = ListTile.divideTiles( context: context, tiles: tiles, ).toList(); return Scaffold( appBar: AppBar( title: Text('Saved Suggestions'), ), body: ListView(children: divided), ); }, // ...to here. ), ); } }
- android studio 在AVD manager(倒数第二个图标)按步骤创建模拟器,三角绿标是运行,闪电是Hot reload(即修改后按下可即时在模拟器中查看改动); 命令行运行 进入项目目录,输入如下命令即可运行(要先打开模拟器),推荐使用这一个启动方法; flutter run
- 详细请参考https://flutterchina.club/android-release/,我这里讲重要的点!
- 要想把 app 发布到 Play store,还需要给 app 一个数字签名。我们可以采用以下步骤来为 app 签名: 创建一个密钥库 如果我们已经有一个密钥库,可以跳到下一步。如果没有,在命令行中运行以下的命令来创建一个: 在 macOS 或者 Linux 系统上,执行下面的代码 keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key On Windows, use the following command: keytool -genkey -v -keystore c:/Users/USER_NAME/key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias key 备忘 保证这个文件的私有性,不要将它提交到公共的代码管理空间。 备忘 keytool 可能不在我们的系统路径中。它是 Java 的一部分,在安装 Android Studio 的时候会被一起安装。运行 flutter doctor -v,’Java binary at:’ 之后打印出来的就是它的路径,然后用 java 来替换以上命令中的 keytool,并加上 keytool 的完整路径即可。如果文件路径包含空格,类似 Program Files 这样的,你需要在路径上加入转义符:/"Program Files"/。 只有 Java 9 或更高版本才需要 -storetype JKS 标签。从 Java 9 版本开始,keystore 类型默认为 PKS12。 从 app 中引用密钥库 创建一个名为 /android/key.properties 的文件,它包含了密钥库位置的定义: storePassword=<上一步骤中的密码> keyPassword=<上一步骤中的密码> keyAlias=key storeFile=<密钥库的位置,e.g. /Users/<用户名>/key.jks> 备忘 (再次)请保证这个文件的私有性,不要将它提交到公共的代码管理空间。
- windows 是无法生成iOS的; android studio 命令行(推荐) 分处理器编译 flutter build apk --split-per-abi 不分处理器 flutter build apk --release
- https://flutterchina.club/android-release/ https://www.bookstack.cn/read/flutter-1.2-zh/65cbdef5d8028edd.md#%E4%B8%BA%20app%20%E7%AD%BE%E5%90%8D https://flutter.dev/docs/deployment/android
我之前讲过如何创建flutter的环境,环境搭建好了就尝试一下这个框架的好处,我之前以为这个东西就是一个前端的UI界面,弄了后发现这个居然有操作逻辑的东西,只用flutter就可以创建一个app了,而且还能生成IOS端的app;
说明一下,https://flutterchina.club/里面的教程有点过时的感觉。英语好的还是去看官方的最新教程,我生成apk文件时按中文教程弄了一下午没弄出来,各种Error报错。英文教程几十就搞出来了!
如下选项创建,按步骤操作即可;
如下选项创建,按步骤操作即可;
具体教程去看https://flutterchina.club/get-started/codelab/,我这里只贴出Main.dart文件!其他按需修改!
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
// 使用主题更改UI
theme: new ThemeData(
primaryColor: Colors.white,
),
home: RandomWords(),
);
}
}
//添加一个 有状态的部件(Stateful widget)
class RandomWords extends StatefulWidget {
@override
_RandomWordsState createState() => _RandomWordsState();
}
class _RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = TextStyle(fontSize: 18.0);
final _saved = new Set<WordPair>();// 添加一个 _saved Set(集合) 到RandomWordsState。这个集合存储用户喜欢(收藏)的单词对。 在这里,Set比List更合适,因为Set中不允许重复的值。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
// 在RandomWordsState的build方法中为AppBar添加一个列表图标。当用户点击列表图标时,包含收藏夹的新路由页面入栈显示。
actions: [ // NEW lines from here...
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
], // ... to here.
),
body: _buildSuggestions(),
);
}
Widget _buildSuggestions() {
return ListView.builder(
padding: EdgeInsets.all(16.0),
itemBuilder: /*1*/ (context, i) {
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
if (index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10)); /*4*/
}
return _buildRow(_suggestions[index]);
});
}
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);//在 _buildRow 方法中添加 alreadySaved来检查确保单词对还没有添加到收藏夹中。
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
// 同时在 _buildRow()中, 添加一个心形 ❤️ 图标到 ListTiles以启用收藏功能。接下来,你就可以给心形 ❤️ 图标添加交互能力了
trailing: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
// 重新启动应用。你现在可以在每一行看到心形❤️图标️,但它们还没有交互。
// 在 _buildRow中让心形❤️图标变得可以点击。如果单词条目已经添加到收藏夹中, 再次点击它将其从收藏夹中删除。当心形❤️图标被点击时,函数调用setState()通知框架状态已经改变。
onTap: () {
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
}
// 向RandomWordsState类添加一个 _pushSaved() 方法.
// 热重载应用,列表图标将会出现在导航栏中。现在点击它不会有任何反应,因为 _pushSaved 函数还是空的。
void _pushSaved() {
Navigator.of(context).push(
MaterialPageRoute<void>(
// NEW lines from here...
builder: (BuildContext context) {
final tiles = _saved.map(
(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final divided = ListTile.divideTiles(
context: context,
tiles: tiles,
).toList();
return Scaffold(
appBar: AppBar(
title: Text('Saved Suggestions'),
),
body: ListView(children: divided),
);
}, // ...to here.
),
);
}
}
具体教程去看https://flutterchina.club/get-started/codelab/,我这里只贴出Main.dart文件!其他按需修改!
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
// 使用主题更改UI
theme: new ThemeData(
primaryColor: Colors.white,
),
home: RandomWords(),
);
}
}
//添加一个 有状态的部件(Stateful widget)
class RandomWords extends StatefulWidget {
@override
_RandomWordsState createState() => _RandomWordsState();
}
class _RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = TextStyle(fontSize: 18.0);
final _saved = new Set<WordPair>();// 添加一个 _saved Set(集合) 到RandomWordsState。这个集合存储用户喜欢(收藏)的单词对。 在这里,Set比List更合适,因为Set中不允许重复的值。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
// 在RandomWordsState的build方法中为AppBar添加一个列表图标。当用户点击列表图标时,包含收藏夹的新路由页面入栈显示。
actions: [ // NEW lines from here...
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
], // ... to here.
),
body: _buildSuggestions(),
);
}
Widget _buildSuggestions() {
return ListView.builder(
padding: EdgeInsets.all(16.0),
itemBuilder: /*1*/ (context, i) {
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
if (index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10)); /*4*/
}
return _buildRow(_suggestions[index]);
});
}
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);//在 _buildRow 方法中添加 alreadySaved来检查确保单词对还没有添加到收藏夹中。
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
// 同时在 _buildRow()中, 添加一个心形 ❤️ 图标到 ListTiles以启用收藏功能。接下来,你就可以给心形 ❤️ 图标添加交互能力了
trailing: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
// 重新启动应用。你现在可以在每一行看到心形❤️图标️,但它们还没有交互。
// 在 _buildRow中让心形❤️图标变得可以点击。如果单词条目已经添加到收藏夹中, 再次点击它将其从收藏夹中删除。当心形❤️图标被点击时,函数调用setState()通知框架状态已经改变。
onTap: () {
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
}
// 向RandomWordsState类添加一个 _pushSaved() 方法.
// 热重载应用,列表图标将会出现在导航栏中。现在点击它不会有任何反应,因为 _pushSaved 函数还是空的。
void _pushSaved() {
Navigator.of(context).push(
MaterialPageRoute<void>(
// NEW lines from here...
builder: (BuildContext context) {
final tiles = _saved.map(
(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final divided = ListTile.divideTiles(
context: context,
tiles: tiles,
).toList();
return Scaffold(
appBar: AppBar(
title: Text('Saved Suggestions'),
),
body: ListView(children: divided),
);
}, // ...to here.
),
);
}
}
- android studio
在AVD manager(倒数第二个图标)按步骤创建模拟器,三角绿标是运行,闪电是Hot reload(即修改后按下可即时在模拟器中查看改动);
- 命令行运行
进入项目目录,输入如下命令即可运行(要先打开模拟器),推荐使用这一个启动方法;
flutter run
在AVD manager(倒数第二个图标)按步骤创建模拟器,三角绿标是运行,闪电是Hot reload(即修改后按下可即时在模拟器中查看改动);
进入项目目录,输入如下命令即可运行(要先打开模拟器),推荐使用这一个启动方法;
flutter run
详细请参考https://flutterchina.club/android-release/,我这里讲重要的点!
详细请参考https://flutterchina.club/android-release/,我这里讲重要的点!
要想把 app 发布到 Play store,还需要给 app 一个数字签名。我们可以采用以下步骤来为 app 签名:
- 创建一个密钥库
如果我们已经有一个密钥库,可以跳到下一步。如果没有,在命令行中运行以下的命令来创建一个:
在 macOS 或者 Linux 系统上,执行下面的代码
keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
要想把 app 发布到 Play store,还需要给 app 一个数字签名。我们可以采用以下步骤来为 app 签名:
如果我们已经有一个密钥库,可以跳到下一步。如果没有,在命令行中运行以下的命令来创建一个:
在 macOS 或者 Linux 系统上,执行下面的代码
keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
On Windows, use the following command:
keytool -genkey -v -keystore c:/Users/USER_NAME/key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias key
- 备忘
保证这个文件的私有性,不要将它提交到公共的代码管理空间。 - 备忘
keytool 可能不在我们的系统路径中。它是 Java 的一部分,在安装 Android Studio 的时候会被一起安装。运行 flutter doctor -v,’Java binary at:’ 之后打印出来的就是它的路径,然后用 java 来替换以上命令中的 keytool,并加上 keytool 的完整路径即可。如果文件路径包含空格,类似 Program Files 这样的,你需要在路径上加入转义符:/"Program Files"/。
只有 Java 9 或更高版本才需要 -storetype JKS 标签。从 Java 9 版本开始,keystore 类型默认为 PKS12。 -
从 app 中引用密钥库
创建一个名为/android/key.properties 的文件,它包含了密钥库位置的定义:
storePassword=<上一步骤中的密码>
keyPassword=<上一步骤中的密码>
keyAlias=key
storeFile=<密钥库的位置,e.g. /Users/<用户名>/key.jks>
- 备忘
(再次)请保证这个文件的私有性,不要将它提交到公共的代码管理空间。
windows 是无法生成iOS的;
分处理器编译
flutter build apk --split-per-abi
不分处理器
flutter build apk --release
windows 是无法生成iOS的;
分处理器编译
flutter build apk --split-per-abi
不分处理器
flutter build apk --release





