本文将带您了解关于Flutter第二期-第一个flutter三平台APP的新内容,同时我们还将为您解释flutter全平台的相关知识,另外,我们还将为您提供关于dart–FlutterError:当前
本文将带您了解关于Flutter第二期 - 第一个flutter三平台APP的新内容,同时我们还将为您解释flutter 全平台的相关知识,另外,我们还将为您提供关于dart – Flutter Error:当前的Flutter SDK版本是2.1.0-dev.0.0.flutter-be6309690f、Flutter - flutter desktop embedding / flutter 桌面支持、Flutter APP开发 学习记录: flutter_swiper轮播图、Flutter 学习之路 --------- 第一个 Flutter 项目的实用信息。
本文目录一览:- Flutter第二期 - 第一个flutter三平台APP(flutter 全平台)
- dart – Flutter Error:当前的Flutter SDK版本是2.1.0-dev.0.0.flutter-be6309690f
- Flutter - flutter desktop embedding / flutter 桌面支持
- Flutter APP开发 学习记录: flutter_swiper轮播图
- Flutter 学习之路 --------- 第一个 Flutter 项目
Flutter第二期 - 第一个flutter三平台APP(flutter 全平台)
继续Flutter学习之旅。
1.先按照官方的例子敲一遍这个简单的点击事件,刷新数据,路由跳转的代码,体会一下,个人感觉还是很不错的:
这是例子的关键在于要理解一个概念widget:一种是可变状态的StatefulWidget,一种是不可变状态的StatelessWidget。而且启动app的写法是不可变的,就是创建的过程是runApp到StatelessWidget的初始化布局代码,理解这点,这些代码你写一会儿就明白了,个人理解就是你的项目经理把计划定下来了,每个人任务很明确,但是计划是不变的,你做成什么样是陈妍希,还是刘亦菲,还是李若彤,看你,最后出来的小龙女统称,所以才会有后面要讲到的tree的log,保证你的每一步操作都可寻,出现问题就会索引到,这点要比以前好很多,而是单纯的哪行错了,你要打断去找,这里所有的widget的操作会级联的往下走直到你的操作结束。
main6.dart:
import 'package:Flutter/material.dart'; void main() => runApp(new MyApp()); // 项目经理bufen class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // Todo: implement build return new MaterialApp( title: 'Flutter Demo1', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new MyHomePage(title: 'Flutter Demo Home Page'), ); } } // 苦逼的你 class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override State<StatefulWidget> createState() { // Todo: implement createState return new _MyHomePageState(); } } // 苦逼的你要做的活 class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _add_counter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { // Todo: implement build return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text( 'You have pushed the button this many times:', ), new Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: new FloatingActionButton( onpressed: _add_counter, tooltip: '增加', child: new Icon(Icons.add), ), ); } }
2.路由管理:这个是我最喜欢的,因为之前google的跳转太多方法了,我要学好多,现在终于变成一种了,很舒服,个人理解是跟javascript很像,就是超链接的方式,唯一要注意的就是如果你显式跳转就要好好看看MaterialPageRoute的方法,android和ios是不一样的,关系到你的页面跳转动画,这里我就不多说了,API会告诉你很细。但是你要是隐式去蹦,那就很爽了,跟之前的Intent一样,自己写名字,要注意的需要注册,而且是不能直接传值的,需要你手动传。
main7.dart:
import 'package:Flutter/material.dart'; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // Todo: implement build return new MaterialApp( title: 'Flutter Demo1', theme: new ThemeData( primarySwatch: Colors.blue, ), routes: { "act.yun.page2": (context) => NewRoute(), }, home: new MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override State<StatefulWidget> createState() { // Todo: implement createState return new _MyHomePageState(); } } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _add_counter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { // Todo: implement build return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text( 'You have pushed the button this many times:', ), new Text( '$_counter', style: Theme.of(context).textTheme.display1, ), FlatButton( child: Text("跳转到第二个页面"), textColor: Colors.lightBlueAccent, onpressed: () { Navigator.pushNamed(context, "act.yun.page2"); // Navigator.push(context, // new MaterialPageRoute(builder: (context) { // return new NewRoute(); // })); }, ) ], ), ), floatingActionButton: new FloatingActionButton( onpressed: _add_counter, tooltip: '增加', child: new Icon(Icons.add), ), ); } } class NewRoute extends StatelessWidget { @override Widget build(BuildContext context) { // Todo: implement build return new Scaffold( appBar: AppBar( title: new Text("新路由"), ), body: Center( child: Text("这是Flutter新路由写法"), ), ); } }
3.包管理:这地方巨坑,个人在用的时候把sdk路径都搞没了,原因是dart不能出现两个同时在用,不然就出问题,你跑不起来,终极解决方案,如果你遇到巨坑:重启ide就可以了,估计是google进程占用的问题,以后应该会解决的。第三方库地址终于可以秒开了:https://pub.dartlang.org/
import 'package:english_words/english_words.dart'; import 'package:Flutter/material.dart'; import 'package:Flutter/rendering.dart'; //void main() => runApp(new MyApp()); void main() { runApp(new MaterialApp( home: new MyApp(), )); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // Todo: implement build return new MaterialApp( title: 'Flutter Demo1', theme: new ThemeData( primarySwatch: Colors.blue, ), routes: { "act.yun.page2": (context) => EchoRoute("内容固定"), }, home: new MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override State<StatefulWidget> createState() { // Todo: implement createState return new _MyHomePageState(); } } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _add_counter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { // Todo: implement build return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text( 'You have pushed the button this many times:', ), new Text( '$_counter', style: Theme.of(context).textTheme.display1, ), FlatButton( child: Text("跳转到第二个页面"), textColor: Colors.lightBlueAccent, onpressed: () { Navigator.pushNamed(context, "act.yun.page2"); debugDumpApp();//Widget 层 debugDumpRenderTree();//渲染层 debugDumpLayerTree();//层 // Navigator.push(context, // new MaterialPageRoute(builder: (context) { // return new NewRoute(); // })); }, ) ], ), ), floatingActionButton: new FloatingActionButton( onpressed: _add_counter, tooltip: '增加', child: new Icon(Icons.add), ), ); } } class EchoRoute extends StatelessWidget { EchoRoute(this.tip); final String tip; @override Widget build(BuildContext context) { // Todo: implement build return Scaffold( appBar: AppBar( title: Text("Echo route"), ), body: Center( // child: Text(tip), child: new RandomWordWidget(), ), ); } } class RandomWordWidget extends StatelessWidget { @override Widget build(BuildContext context) { // Todo: implement build final wordPair = new WordPair.random(); return Padding( padding: const EdgeInsets.all(8.0), child: new Text(wordPair.toString()), ); } }
4.调试Flutter应用:终于到了激动的环节,这个log真的美哭了,你们自己看吧,调用的话就三句:
debugDumpApp();//Widget 层 debugDumpRenderTree();//渲染层 debugDumpLayerTree();//层
5.Flutter异常捕获:终于让google帮大家解决了,以后错了google告诉你错哪了,方案也弹出来,大部分都不用去百度了,是不是很好。
@overridevoid performRebuild() { ... try { //执行build方法 built = build(); } catch (e, stack) { // 有异常时则弹出错误提示 built = ErrorWidget.builder(_debugReportException('building $this', e, stack)); } ...}
总结:今天讲的不多,慢慢来,反正闲着也是闲着,过了打游戏的年纪就学点啥不丢人,哈哈~先把创建过程,然后属性设置,还有传值刷新,还有跳转基本操作写熟练后,你发现开启了新的世界,然后去google的dart官网去找几个lib玩玩,你兴趣就来了,下期我就准备玩玩,哈哈~不玩后面再这么多线程,网络封装,感觉不好玩,有大神封装好的库,你就觉得有意思了,哈哈~下期见~
dart – Flutter Error:当前的Flutter SDK版本是2.1.0-dev.0.0.flutter-be6309690f
The current Dart SDK version is 2.1.0-dev.0.0.Flutter-be6309690f. Because buddy depends on Flutter_built_redux 0.4.5 which requires SDK version >=1.19.0 <2.0.0,version solving Failed. pub get Failed (1)
如何降级Dart或如何解决此问题,我在mac上运行android studio.
我试过通过改变颤动的通道开发和主人,但它并没有什么区别.
扑医生-v结果:
[✓] Flutter (Channel dev,v0.6.0,on Mac OS X 10.13.4 17E202,locale en-IN) • Flutter version 0.6.0 at /Users/pro/Downloads/Flutter • Framework revision 9299c02cf7 (5 days ago),2018-08-16 00:35:12 +0200 • Engine revision e3687f70c7 • Dart version 2.1.0-dev.0.0.Flutter-be6309690f [✓] Android toolchain - develop for Android devices (Android SDK 27.0.3) • Android SDK at /Users/pro/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-27,build-tools 27.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release- 1024-b01) • All Android licenses accepted. [✓] iOS toolchain - develop for iOS devices (Xcode 9.4.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 9.4.1,Build version 9F2000 • ios-deploy 1.9.2 • CocoaPods version 1.5.0 [✓] Android Studio (version 3.1) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 27.1.1 • Dart plugin version 173.4700 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01) [!] Connected devices ! No devices available
解决方法
错误是由包而不是Flutter sdk引起的.
看这里
https://github.com/davidmarne/flutter_built_redux/blob/master/pubspec.yaml#L22
和
您可以使用此链接在Flutter_built_redux包上发布问题
https://github.com/davidmarne/flutter_built_redux/issues/new?title=support%20for%20flutter%20sdk%202.1.0.dev&body=please%20upgrade%20the%20package%20for%20new%20flutter%20releases
Flutter - flutter desktop embedding / flutter 桌面支持
2019年5月9日,随着谷歌在IO19宣布Flutter支持Web平台,就标志着Flutter已经全面支持所有平台(移动、网页、桌面、嵌入式)。
现编一个跨平台小段子:
微软Xarmarin:喵喵喵???不是我最先做的吗,咋没人关注???
Facebook React Native:我是做的最好的跨平台。
谷歌Flutter:去你的吧,支持桌面端不,嵌入式?哈哈哈
苹果SwiftUI:老司机们,等等我。
但是这次要说的是,Flutter for desktop,Flutter支持桌面版已经有很长一段时间了,但是一直都没大研究。主要原因就是现在除了Flutter for mobile可以用在production以外,其他的三个平台知识现在已经验证技术上可行,但仍处于technical preview。像现在的官方大部分plugins,仍然没有适配desktop版本,更不要说第三方的plugins。这些plugins在桌面上调用时,轻者会点击毫无反应,重者会导致程序崩溃。而且现在桌面版普遍的一个问题就是,当app最小化的时候,app崩溃。
所以大家激动归激动,千万别冲动。
不过既然有了flutter for desktop,我们就尝鲜一下,看看在桌面上是什么效果。
1 工具准备
我用的是Windows平台,需要Visual Studio 2017 or 2019,并且包含“C++桌面开发负载”。其他平台可以去Github主页查看。
2 下载官方示例
打开 Desktop Embedding for Flutter,下载整个项目并解压。把整个example文件夹拖进VS Code或者在VS Code 里面打开文件夹,
然后VS Code提示 Some packages are missing or out of date, would you like to get them now?
毫不犹豫的点击Get Packages按钮,或者在终端输入flutter packages get也行
如果网络没问题的话或者镜像配置正确(下载不下来或者配置镜像自行搜索,本文不做介绍)的话,VS Code就会输出
[example] flutter packages get
Running "flutter pub get" in example... 6.7s
exit code 0
3 桌面版运行配置
由于我们下载的是官方示例,所里都配置好了。但是我们还是要看一下,因为以后要移植自己的项目鸭~~~
3a 打开pubspec.yaml文件
# See https://github.com/flutter/flutter/wiki/Desktop-shells#fonts
fonts:
- family: Roboto
fonts:
- asset: fonts/Roboto/Roboto-Thin.ttf
weight: 100
- asset: fonts/Roboto/Roboto-Light.ttf
weight: 300
- asset: fonts/Roboto/Roboto-Regular.ttf
weight: 400
- asset: fonts/Roboto/Roboto-Medium.ttf
weight: 500
- asset: fonts/Roboto/Roboto-Bold.ttf
weight: 700
- asset: fonts/Roboto/Roboto-Black.ttf
weight: 900
官方指定了Roboto字体,大部分应用也都需要指定一个字体。但是现在的话,不指定,也可以运行。不过有的Widgets可能在字体显示上有异常。
官方的解释:
Fonts
Flutter applications may default to fonts that are standard for the target platform, but unavailable on desktop. For instance, if the target platform is TargetPlatform.iOS the Material library will default to San Francisco, which is available on macOS but not Linux or Windows.
Most applications will need to set the font (e.g., via ThemeData) based on the host platform, or set a specific font that is bundled with the application. Other widgets that doesn''t use ThemeData may not display without extra font specification (e.g., the DEBUG banner''s text).
Symptoms of missing fonts include text failing to display and/or console logging about failure to load fonts.
3b 打开main.dart
设置运行平台
import ''package:flutter/foundation.dart''
show debugDefaultTargetPlatformOverride;
void main() {
// See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override
debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
runApp(new MyApp());
}
3c 切换flutter到master channel
在终端中输入
flutter channel master
3d 升级master channel到最新版,然后会自动运行运行flutter doctor
flutter upgrade
3e 设置运行平台为桌面模式
如果VS Code终端是PowerShell,那么输入
$env:ENABLE_FLUTTER_DESKTOP="true"
CMD输入
set ENABLE_FLUTTER_DESKTOP=true
4 Flutter Run
如果按照上面操作没有问题的话,那么最激动人心的时刻就要到到来了
在终端输入
flutter run
回车
噔噔灯灯...(* ̄0 ̄)ノ
原文出处:https://www.cnblogs.com/hupo376787/p/10990899.html
Flutter APP开发 学习记录: flutter_swiper轮播图
说点儿闲话
大部分app都有轮播图,一般是展示一些新闻公告通知等图片,在flutter最强大的siwiper, 多种布局方式,无限轮播,Android和IOS双端适配,github:flutter_swiper
使用:
加载图片
一般是从本地代码中或者使用网络图片,那么,首先将资源添加到项目的 pubspec.yaml 文件中(更多细节请参阅Assets and images):
flutter:
assets:
- images/news_1.png
- images/news_1.png
- images/news_1.png
如果项目中所需要使用的图片资源太多,也可以直接直接这样写:
(1)、包含一个目录下的所有 assets,需要在目录名称的结尾加上/
:
flutter:
assets:
- assets/
注意只包含目录下根节点的所有文件。
(2)、如果要添加子目录下的文件,需要给每个目录创建节点:
flutter:
assets: [images/,images/index-icons/] # 配置代码中使用的图片所放置的文件夹及其子文件夹
显示base64图片
这里插个题外话,使用图片显示的辑中方法:Image class: A widget that displays an image.
其中,Image.memory
可以用来显示base64图片,具体使用如下:
import ''dart:convert'';
//"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAuCAYAAACvdRK..."
// 直接获取`base64,`之后的数据
pictureData = "iVBORw0KGgoAAAANSUhEUgAAAKAAAAAuCAYAAACvdRK..."
Image.memory(
Base64Decoder().convert(pictureData), // 转成Uint8List
fit: BoxFit.contain,
height: 160,
)
参考:flutter 显示base64 图片
flutter_swiper
在pubspec.yaml文件里添加
flutter\_swiper : ^lastest\_version
到项目根目录下的 pubspec.yaml ,并且根目录运行命令行
flutter packages get
flutter_swiper的最新版本号查看:pub.dev:flutter_swiper
实现轮播图 代码
import ''package:flutter/material.dart'';
import ''package:flutter_swiper/flutter_swiper.dart'';
import ''message.dart'';
class IndexScreen extends StatefulWidget {
@override
_SwiperViewState createState() => _SwiperViewState();
}
class _SwiperViewState extends State<IndexScreen> {
// 声明一个list,存放image Widget
List<Widget> imageList = List();
@override
void initState() {
imageList
..add(Image.asset(
''images/news_1.png'',
height: 200,
fit: BoxFit.fitWidth, // 显示可能拉伸,可能裁剪,宽度充满
))
..add(Image.asset(
''images/news_2.png'',
height: 200,
fit: BoxFit.fitWidth,
))
..add(Image.asset(
''images/news_3.png'',
height: 200,
fit: BoxFit.fitWidth,
));
super.initState();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
leading: Builder(
builder: (BuildContext context) {
// APP的logo图
return Image.asset(''images/logo-header.png'');
},
),
title: new Text(
''APP
style: TextStyle(fontSize: 18.0, height: 1.2, fontFamily: "Courier"),
),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.message),
onPressed: () {
// 右上角的通知消息图标,点击进入消息列表
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new MessageScreen()),
);
}),
],
),
body: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: 200,
child: new Swiper(
itemBuilder: _swiperBuilder,
itemCount: 3,
itemWidth: MediaQuery.of(context).size.width,
itemHeight: 200.0,
loop: true,
autoplay: true,
pagination: null,
control: null,
viewportFraction: 1,
scale: 1,
),
),
Container(
// padding: const EdgeInsets.fromLTRB(0, 10, 0, 5),
width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height,
// 将上方的header、底部菜单和轮播图的高度减掉
height: MediaQuery.of(context).size.height - 400,
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //对齐方式:平均间隔
children: [
// 下方的其他页面布局
],
),
),
],
),
);
}
Widget _swiperBuilder(BuildContext context, int index) {
return (imageList[index]);
}
}
以上是使用静态资源加载图片来实现轮播图,实际项目中,基本都是后端接口返回的数据,这就涉及到另外的知识点, GitHub - dio: 发起网络请求, 参见我整理的dio的相关学习记录: Flutter 使用dio来发起网络请求以及Cookie管理。
通过接口请求后端返回的数据后,对数据进行处理并通过setState来更新视图,代码:
setState(() {
// 处理返回数据
var rtn = response.data[''content''];
rtn.forEach((f) {
// print("image title:" + f["title"] + " imageUrl:" + f["imageUrl"]);
imageList
..add(Image.network(
f["imageUrl"],
height: 200,
fit: BoxFit.fitWidth, // 显示可能拉伸,可能裁剪,宽度充满
));
});
// print(imageList);
});
遇到的问题
在首页上,通过底部导航菜单点击跳转到另一个页面后,再回到首页,轮播图会出现疯狂的切换图片轮播一段时间后停下来继续以正常速度轮播,具体问题参我的提问:Flutter flutter_swiper轮播图的问题
这个问题我已经解决了,解决办法描述在我的提问下我自己的回答里记录了,这里就不再赘述了,直接附上解决是修改的代码:
IndexScreen 的 class中增加以下代码:
bool isLoading = true;
setState(() {
// 处理返回数据 上文中有,省略了
isLoading = false;
// print(imageList);
});
Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isLoading ? 1.0 : 00,
child: new CircularProgressIndicator(),
),
),
);
}
build方法中增加判断:
Container(
width: MediaQuery.of(context).size.width,
height: 125,
child: imageList.length == 0
? _buildProgressIndicator()
: new Swiper(
itemBuilder: _swiperBuilder,
itemCount: imageList.length,
itemWidth: MediaQuery.of(context).size.width,
itemHeight: 125.0,
loop: true,
autoplay: true,
autoplayDelay: 3000, //自动播放延迟
autoplayDisableOnInteraction: true, //触发时是否停止播放
pagination: null, //设置 new SwiperPagination() 展示默认分页指示器
control: null, //设置 new SwiperControl() 展示默认分页按钮
controller: swiperController,
viewportFraction: 1,
scale: 1,
),
),
参考资料:
github:flutter_swiper
Assets and images
pub.dev:flutter_swiper
笔记-Flutter之轮播图(多样式)
Flutter 三种方式实现页面切换后保持原页面状态
相关文章
Flutter APP开发 学习记录: bottomNavigationBar底部导航菜单 本篇文章是底部导航菜单这篇文章中对应的IndexScreen()
的布局
dio的相关学习记录: Flutter 使用dio来发起网络请求以及Cookie管理
Flutter 学习之路 --------- 第一个 Flutter 项目
Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。
Flutter 可以与现有的代码一起工作。在全世界,Flutter 正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。
Flutter 中文网 (有安装和搭建 Flutter 的教程)
https://flutterchina.club
安装 Flutter 和 Dart 插件
启动 Android Studio,搜索 Flutter 插件并单击 install,系统提示您安装 Dart 插件,点击 Yes 安装即可。
第一个项目
Android Studio - File - New - New Flutter Project,等待创建成功后,运行效果如下:
在这个示例中,你将主要编辑 Dart 代码所在的 lib/main.dart 文件,
替换 lib/main.dart.
删除 lib /main.dart 中的所有代码,然后替换为下面的代码,它将在屏幕的中心显示 “Hello World”.
import ''package:flutter/material.dart'';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: ''Welcome to Flutter'',
home: new Scaffold(
appBar: new AppBar(
title: new Text(''Welcome to Flutter''),
),
body: new Center(
child: new Text(''Hello World''),
),
),
);
}
}
运行效果图:
关于Flutter第二期 - 第一个flutter三平台APP和flutter 全平台的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于dart – Flutter Error:当前的Flutter SDK版本是2.1.0-dev.0.0.flutter-be6309690f、Flutter - flutter desktop embedding / flutter 桌面支持、Flutter APP开发 学习记录: flutter_swiper轮播图、Flutter 学习之路 --------- 第一个 Flutter 项目的相关知识,请在本站寻找。
本文标签: