开篇寄语
这一篇文章主要是学习flutter中各种在App中可能出现的实用功能,比如白天模式与夜间模式自由切换,分享到社交媒体,照相摄像,打分五星好评之类的等等,一起来看看都有什么吧。
前情提要
- 《如何在Mac M1芯片电脑上安装Flutter并建立自己第一个全系统应用》
- 《如何在Windows电脑上安装Flutter并建立自己第一个全系统应用》
- 《Flutter制作自己的第一个全平台APP学习之Navigation篇》
- 《Flutter制作自己的第一个全平台APP学习之Popup篇》
- 《Flutter制作自己的第一个全平台APP学习之多媒体篇》
内容详情
以下内容大多是更改lib下的main.dart文件内容,删掉里面的内容,复制粘贴代码,开启调试就可以出现了。
白天与夜间模式切换
- 夜间模式现在在制作App中很流行,Flutter中也很容易实现,试举例如下:
// main.dart import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // Using "static" so that we can easily access it later static final ValueNotifier<ThemeMode> themeNotifier = ValueNotifier(ThemeMode.light); @override Widget build(BuildContext context) { return ValueListenableBuilder<ThemeMode>( valueListenable: themeNotifier, builder: (_, ThemeMode currentMode, __) { return MaterialApp( // Remove the debug banner debugShowCheckedModeBanner: false, title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.amber), darkTheme: ThemeData.dark(), themeMode: currentMode, home: HomeScreen(), ); }); } } // Home Screen class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Demo'), actions: [ IconButton( icon: Icon(MyApp.themeNotifier.value == ThemeMode.light ? Icons.dark_mode : Icons.light_mode), onPressed: () { MyApp.themeNotifier.value = MyApp.themeNotifier.value == ThemeMode.light ? ThemeMode.dark : ThemeMode.light; }) ], ), body: Center( child: ElevatedButton( child: Text('Go to Other Screen'), onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) => OtherScreen())); }, ), ), ); } } // Other Screen class OtherScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Other Screen'), ), body: Center( child: Text( 'Hello', style: TextStyle(fontSize: 50), ), ), ); } }
生成效果如下图所示:
文字添加超链接
- 就像是html中的<a></a>标签,点击后就会跳转到网页,试举例如下:
import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // Remove the debug banner debugShowCheckedModeBanner: false, title: 'Flutter Demo', home: HomePage(), ); } } class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Demo'), ), body: Padding( padding: const EdgeInsets.all(30), child: DefaultTextStyle( style: TextStyle(fontSize: 24, color: Colors.black87), child: Wrap( children: [ Text('Welcome to '), GestureDetector( child: Text( 'Flutter Dev', style: TextStyle( color: Colors.blue, decoration: TextDecoration.underline), ), onTap: () async => await canLaunch('https://www.flutter.dev') ? await launch('https://www.flutter.dev') : throw 'Something bad happend', ), ], ), ), ), ); } }
生成效果如下图所示:
复制粘贴到剪切板
- 这个功能也是十分常见的,所以也需要掌握的,试举例如下:
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Demo', home: HomePage(), ); } } class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { TextEditingController _textController = TextEditingController(); // This key will be used to show the snack bar final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey(); // This function is triggered when the copy icon is pressed Future<void> _copyToClipboard() async { await Clipboard.setData(ClipboardData(text: _textController.text)); _scaffoldKey.currentState!.showSnackBar(SnackBar( content: Text('Copied to clipboard'), )); } @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, appBar: AppBar( title: Text('Flutter Demo'), backgroundColor: Colors.deepOrange, ), body: Center( child: Padding( padding: const EdgeInsets.all(30), child: TextField( controller: _textController, decoration: InputDecoration( icon: IconButton( icon: Icon(Icons.copy), onPressed: _copyToClipboard, ), ), ), ))); } }
生成效果如下图所示:
分享按钮
- 各种消息分享到社交媒体的功能,岂能错过,除了有更多乐趣外,还能扩大App的知名度哦,试举一例:
- 需要添加一个名为share的支撑库,安装和使用方法请参看这个地址:share
import 'package:flutter/material.dart'; import 'package:share/share.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // Remove the debug banner debugShowCheckedModeBanner: false, title: 'Flutter Demo', home: HomePage(), ); } } class HomePage extends StatelessWidget { final String _content = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum diam ipsum, lobortis quis ultricies non, lacinia at justo.'; void _shareContent() { Share.share(_content); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Demo'), ), body: Padding( padding: const EdgeInsets.all(25), child: Center( child: Column(children: [ Text(_content), SizedBox(height: 15), ElevatedButton.icon( onPressed: _shareContent, icon: Icon(Icons.share), label: Text('Share This Sentence')) ]), ), ), ); } }
生成效果如下图所示:
五星好评
- 这个常见于打分环节,自然也要掌握啦,试举一例:
- 需要安装一个名为flutter rating bar的支撑库,地址是这里:flutter_rating_bar,安装完成后,可以参考下面这个代码案例:
import 'package:flutter/material.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { late final _ratingController; late double _rating; double _userRating = 3.0; int _ratingBarMode = 1; double _initialRating = 2.0; bool _isRTLMode = false; bool _isVertical = false; IconData? _selectedIcon; @override void initState() { super.initState(); _ratingController = TextEditingController(text: '3.0'); _rating = _initialRating; } @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.amber, appBarTheme: AppBarTheme( textTheme: TextTheme( headline6: Theme.of(context) .textTheme .headline6 ?.copyWith(color: Colors.white), ), ), ), home: Builder( builder: (context) => Scaffold( appBar: AppBar( title: Text('Flutter Rating Bar'), actions: [ IconButton( icon: Icon(Icons.settings), color: Colors.white, onPressed: () async { _selectedIcon = await showDialog<IconData>( context: context, builder: (context) => IconAlert(), ); _ratingBarMode = 1; setState(() {}); }, ), ], ), body: Directionality( textDirection: _isRTLMode ? TextDirection.rtl : TextDirection.ltr, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ SizedBox( height: 40.0, ), _heading('Rating Bar'), _ratingBar(_ratingBarMode), SizedBox(height: 20.0), Text( 'Rating: $_rating', style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox(height: 40.0), _heading('Rating Indicator'), RatingBarIndicator( rating: _userRating, itemBuilder: (context, index) => Icon( _selectedIcon ?? Icons.star, color: Colors.amber, ), itemCount: 5, itemSize: 50.0, unratedColor: Colors.amber.withAlpha(50), direction: _isVertical ? Axis.vertical : Axis.horizontal, ), SizedBox(height: 20.0), Padding( padding: EdgeInsets.symmetric(horizontal: 16.0), child: TextFormField( controller: _ratingController, keyboardType: TextInputType.number, decoration: InputDecoration( border: OutlineInputBorder(), hintText: 'Enter rating', labelText: 'Enter rating', suffixIcon: MaterialButton( onPressed: () { _userRating = double.parse(_ratingController.text ?? '0.0'); setState(() {}); }, child: Text('Rate'), ), ), ), ), SizedBox(height: 40.0), _heading('Scrollable Rating Indicator'), RatingBarIndicator( rating: 8.2, itemCount: 20, itemSize: 30.0, physics: BouncingScrollPhysics(), itemBuilder: (context, _) => Icon( Icons.star, color: Colors.amber, ), ), SizedBox(height: 20.0), Text( 'Rating Bar Modes', style: TextStyle(fontWeight: FontWeight.w300), ), Row( children: [ _radio(1), _radio(2), _radio(3), ], ), Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'Switch to Vertical Bar', style: TextStyle(fontWeight: FontWeight.w300), ), Switch( value: _isVertical, onChanged: (value) { setState(() { _isVertical = value; }); }, activeColor: Colors.amber, ), ], ), Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'Switch to RTL Mode', style: TextStyle(fontWeight: FontWeight.w300), ), Switch( value: _isRTLMode, onChanged: (value) { setState(() { _isRTLMode = value; }); }, activeColor: Colors.amber, ), ], ), ], ), ), ), ), ), ); } Widget _radio(int value) { return Expanded( child: RadioListTile<int>( value: value, groupValue: _ratingBarMode, dense: true, title: Text( 'Mode $value', style: TextStyle( fontWeight: FontWeight.w300, fontSize: 12.0, ), ), onChanged: (value) { setState(() { _ratingBarMode = value!; }); }, ), ); } Widget _ratingBar(int mode) { switch (mode) { case 1: return RatingBar.builder( initialRating: _initialRating, minRating: 1, direction: _isVertical ? Axis.vertical : Axis.horizontal, allowHalfRating: true, unratedColor: Colors.amber.withAlpha(50), itemCount: 5, itemSize: 50.0, itemPadding: EdgeInsets.symmetric(horizontal: 4.0), itemBuilder: (context, _) => Icon( _selectedIcon ?? Icons.star, color: Colors.amber, ), onRatingUpdate: (rating) { setState(() { _rating = rating; }); }, updateOnDrag: true, ); case 2: return RatingBar( initialRating: _initialRating, direction: _isVertical ? Axis.vertical : Axis.horizontal, allowHalfRating: true, itemCount: 5, ratingWidget: RatingWidget( full: _image('assets/heart.png'), half: _image('assets/heart_half.png'), empty: _image('assets/heart_border.png'), ), itemPadding: EdgeInsets.symmetric(horizontal: 4.0), onRatingUpdate: (rating) { setState(() { _rating = rating; }); }, updateOnDrag: true, ); case 3: return RatingBar.builder( initialRating: _initialRating, direction: _isVertical ? Axis.vertical : Axis.horizontal, itemCount: 5, itemPadding: EdgeInsets.symmetric(horizontal: 4.0), itemBuilder: (context, index) { switch (index) { case 0: return Icon( Icons.sentiment_very_dissatisfied, color: Colors.red, ); case 1: return Icon( Icons.sentiment_dissatisfied, color: Colors.redAccent, ); case 2: return Icon( Icons.sentiment_neutral, color: Colors.amber, ); case 3: return Icon( Icons.sentiment_satisfied, color: Colors.lightGreen, ); case 4: return Icon( Icons.sentiment_very_satisfied, color: Colors.green, ); default: return Container(); } }, onRatingUpdate: (rating) { setState(() { _rating = rating; }); }, updateOnDrag: true, ); default: return Container(); } } Widget _image(String asset) { return Image.asset( asset, height: 30.0, width: 30.0, color: Colors.amber, ); } Widget _heading(String text) => Column( children: [ Text( text, style: TextStyle( fontWeight: FontWeight.w300, fontSize: 24.0, ), ), SizedBox( height: 20.0, ), ], ); } class IconAlert extends StatelessWidget { @override Widget build(BuildContext context) { return AlertDialog( title: Text( 'Select Icon', style: TextStyle( fontWeight: FontWeight.w300, ), ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), titlePadding: EdgeInsets.all(12.0), contentPadding: EdgeInsets.all(0), content: Wrap( children: [ _iconButton(context, Icons.home), _iconButton(context, Icons.airplanemode_active), _iconButton(context, Icons.euro_symbol), _iconButton(context, Icons.beach_access), _iconButton(context, Icons.attach_money), _iconButton(context, Icons.music_note), _iconButton(context, Icons.android), _iconButton(context, Icons.toys), _iconButton(context, Icons.language), _iconButton(context, Icons.landscape), _iconButton(context, Icons.ac_unit), _iconButton(context, Icons.star), ], ), ); } Widget _iconButton(BuildContext context, IconData icon) => IconButton( icon: Icon(icon), onPressed: () => Navigator.pop(context, icon), splashColor: Colors.amberAccent, color: Colors.amber, ); }
生成效果如下图所示:
右下角弹出按钮
- 可以在该按钮中添加各种实用功能,列出很多选项按钮,需要安装支持库,这里涉及到一个名为flutter speed dial的库,这个需要安装,可前往这个网址参看指导:flutter speed dial
- 试举例如下:
import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // Remove the debug banner debugShowCheckedModeBanner: false, title: 'Flutter Demo', home: HomePage(), ); } } class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Demo'), ), body: Center( child: Text("Hello World"), ), floatingActionButton: SpeedDial( icon: Icons.share, backgroundColor: Colors.amber, children: [ SpeedDialChild( child: Icon(Icons.face), label: 'Social Network', backgroundColor: Colors.amberAccent, onTap: () {/* Do someting */}, ), SpeedDialChild( child: Icon(Icons.email), label: 'Email', backgroundColor: Colors.amberAccent, onTap: () {/* Do something */}, ), SpeedDialChild( child: Icon(Icons.chat), label: 'Message', backgroundColor: Colors.amberAccent, onTap: () {/* Do something */}, ), ]), ); } }
生成效果如下图所示:
- 我的微信
- 微信扫一扫加好友
- 我的微信公众号
- 扫描关注公众号