前言
今天是痛苦与快乐并存的一天,痛苦是因为今天在想一些东西的时候,头都想炸了,快乐的是因为学了非常多的东西,解决了很多的问题,今天我就把自己在工作中用到的一些东西分享出来,供大家学习
- pageView的页面状态保持
- TabBar顶部隐藏,下滑渐现
- 点击按钮,复制文字
- 将本地照片或者是将网络照片保存到手机相册中
- TabBar的切换加滑动切换效果
一、PageView的页面状态保持?
PageView( scrollDirection: Axis.horizontal, pageSnapping: true, onPageChanged: (index) { print(index); }, children: [ Container(color:Colors.red), PhoneWindowLayout( child:Container(color:Color(0xff5BD8FF)), ) ] ); //继承with AutomaticKeepAliveClientMixin轻松搞定 class PhoneWindowLayout extends StatefulWidget { Widget widget; @override _PhoneWindowLayoutState createState() => _PhoneWindowLayoutState(); } class _PhoneWindowLayoutState extends State<PhoneWindowLayout> with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { return widget } //状态保持 @override bool get wantKeepAlive => true; }
二、appBar顶部隐藏,下滑渐现
import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:home_insurance/my_ui/my_color.dart'; //隐藏在顶端并且时透明的导航栏,上滑的时候才会出现 class StackNavBar extends StatefulWidget { final IconData icon; final String title; final Widget child; Color iconColor = MyColor.inputBcColor; StackNavBar({this.iconColor,this.icon = Icons.keyboard_arrow_left,this.title = '',this.child}); @override _StackStackNavBarState createState() => _StackStackNavBarState(); } class _StackStackNavBarState extends State<StackNavBar> with TickerProviderStateMixin { AnimationController _colorAnimationController; AnimationController _textAnimationController; Animation _colorTween, _iconColorTween,_textColorTween; @override void initState() { _colorAnimationController = AnimationController(vsync: this, duration: Duration(seconds: 0)); //一开始的颜色和往上滑动的颜色 _colorTween = ColorTween(begin: Colors.transparent, end: MyColor.inputBcColor).animate(_colorAnimationController); _textColorTween = ColorTween(begin:Colors.transparent, end: Colors.black).animate(_colorAnimationController); _iconColorTween = ColorTween(begin:widget.iconColor, end: Colors.black).animate(_colorAnimationController); _textAnimationController =AnimationController(vsync: this, duration: Duration(seconds: 0)); super.initState(); } bool _scrollListener(ScrollNotification scrollInfo) { if (scrollInfo.metrics.axis == Axis.vertical) { //灵敏度 _colorAnimationController.animateTo(scrollInfo.metrics.pixels / 10); _textAnimationController .animateTo((scrollInfo.metrics.pixels - 350) / 50); return true; } return false; } @override Widget build(BuildContext context) { return Scaffold( body: NotificationListener<ScrollNotification>( onNotification: _scrollListener, child: Container( child: Stack( children: <Widget>[ Container( child: widget.child, ), Container( height:ScreenUtil().setHeight(100), child: AnimatedBuilder( animation: _colorAnimationController, builder: (context, child) => AppBar( backgroundColor: _colorTween.value, elevation: 0, centerTitle: true, title: Text( widget.title, style: TextStyle( fontSize: 17, fontWeight: FontWeight.w600, color: _textColorTween.value ), ), iconTheme: IconThemeData( color: _iconColorTween.value, ), ), ), ), ], ), ), ), ); } }
三.点击按钮,复制文字
导入库
clipboard: any
InkWell( child: Container( decoration: BoxDecoration( border: Border.all(width: 1, color: Color(0xff2DDD99)), borderRadius: BorderRadius.circular(5)), padding: EdgeInsets.symmetric(vertical: 2, horizontal: 3), child: Text( "复制", style: TextStyle(color: Color(0xff2DDD99), fontSize: 13), ), ), onTap: () { FlutterClipboard.copy(order.number).then((value) { Fluttertoast.showToast( msg: "成功复制到剪切板", gravity: ToastGravity.BOTTOM); }); }, ),
四.照片保存到相册
导入库
#保存照片到手机相册中 image_gallery_saver: any cached_network_image: any permission_handler: any
IOS配置文件
<key>NSPhotoLibraryUsageDescription</key> <string></string> <key>NSPhotoLibraryAddUsageDescription</key> <string>请允许APP保存图片到相册</string>
Android配置(含多项配置)
<!-- 开启网络访问权限 --> <uses-permission android:name="android.permission.INTERNET"/> <!--开启振动提示--> <uses-permission android:name="android.permission.VIBRATE"/> <!-- 开机启动权限 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <!-- 摄像头权限 --> <uses-permission android:name="android.permission.CAMERA"/> <!-- 允许程序录制声音通过手机或耳机的麦克--> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <!-- 在SDCard中创建与删除文件的权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!-- 往SDCard写入数据的权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 在SDCard读取数据的权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
五.TabBar的切换加滑动切换效果
class _CompleteOrderPageState extends State<CompleteOrderPage> with SingleTickerProviderStateMixin { final List<Tab> _myTabs = <Tab>[ Tab(text: '待付款'), Tab(text: '已付款'), Tab(text: '已取消') ]; @override Widget build(BuildContext context) { return DefaultTabController( initialIndex: 0, length: _myTabs.length, child: Scaffold( appBar: AppBar( backgroundColor: Color(0xffFFFFFF), elevation: 0, centerTitle: true, title: Text( "全部保单", style: TextStyle(fontSize: 17, fontWeight: FontWeight.w600), ), bottom: PreferredSize( preferredSize: Size(50, 50), child: Theme( child: TabBar( unselectedLabelColor: Color(0xffBBBEC2), labelPadding: EdgeInsets.symmetric(horizontal: 10), indicator: MyUnderlineTabIndicator( borderSide: BorderSide(width: 4.0, color: Color(0xff2DDD99))), indicatorWeight: ScreenUtil().setWidth(3), indicatorSize: TabBarIndicatorSize.label, labelColor: Color(0xff242629), tabs: _myTabs), data: ThemeData( splashColor: Colors.transparent, highlightColor: Colors.transparent, ), )), ), body: new TabBarView(children: [ Scaffold( ), Scaffold( ), Scaffold( ) ]), ), ); }
切换指示图标变得圆滑
import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; /// Used with [TabBar.indicator] to draw a horizontal line below the /// selected tab. /// /// The selected tab underline is inset from the tab's boundary by [insets]. /// The [borderSide] defines the line's color and weight. /// /// The [TabBar.indicatorSize] property can be used to define the indicator's /// bounds in terms of its (centered) widget with [TabIndicatorSize.label], /// or the entire tab with [TabIndicatorSize.tab]. class MyUnderlineTabIndicator extends Decoration { /// Create an underline style selected tab indicator. /// /// The [borderSide] and [insets] arguments must not be null. const MyUnderlineTabIndicator({ this.borderSide = const BorderSide(width: 2.0, color: Colors.white), this.insets = EdgeInsets.zero, }) : assert(borderSide != null), assert(insets != null); /// The color and weight of the horizontal line drawn below the selected tab. final BorderSide borderSide; /// Locates the selected tab's underline relative to the tab's boundary. /// /// The [TabBar.indicatorSize] property can be used to define the /// tab indicator's bounds in terms of its (centered) tab widget with /// [TabIndicatorSize.label], or the entire tab with [TabIndicatorSize.tab]. final EdgeInsetsGeometry insets; @override Decoration lerpFrom(Decoration a, double t) { if (a is UnderlineTabIndicator) { return UnderlineTabIndicator( borderSide: BorderSide.lerp(a.borderSide, borderSide, t), insets: EdgeInsetsGeometry.lerp(a.insets, insets, t), ); } return super.lerpFrom(a, t); } @override Decoration lerpTo(Decoration b, double t) { if (b is MyUnderlineTabIndicator) { return MyUnderlineTabIndicator( borderSide: BorderSide.lerp(borderSide, b.borderSide, t), insets: EdgeInsetsGeometry.lerp(insets, b.insets, t), ); } return super.lerpTo(b, t); } @override _MyUnderlinePainter createBoxPainter([VoidCallback onChanged]) { return _MyUnderlinePainter(this, onChanged); } } class _MyUnderlinePainter extends BoxPainter { _MyUnderlinePainter(this.decoration, VoidCallback onChanged) : assert(decoration != null), super(onChanged); final MyUnderlineTabIndicator decoration; BorderSide get borderSide => decoration.borderSide; EdgeInsetsGeometry get insets => decoration.insets; Rect _indicatorRectFor(Rect rect, TextDirection textDirection) { assert(rect != null); assert(textDirection != null); final Rect indicator = insets.resolve(textDirection).deflateRect(rect); //希望的宽度 double wantWidth = 42; //取中间坐标 double cw = (indicator.left + indicator.right) / 2; return Rect.fromLTWH(cw - wantWidth / 2, indicator.bottom - borderSide.width, wantWidth, borderSide.width); } @override void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { assert(configuration != null); assert(configuration.size != null); final Rect rect = offset & configuration.size; final TextDirection textDirection = configuration.textDirection; final Rect indicator = _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0); // 改为圆角 final Paint paint = borderSide.toPaint()..strokeCap = StrokeCap.round; canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint); } }