FLutter 踩坑笔记

FLutter 踩坑笔记

Android 集成部分

Flutter 编写部分

  • MaterialButton RaisedButton 控件内部与child之间存在padding ,没有属性可以去掉。
    • 使用最新版sdk(1.22.0 以及以上)中的TextButton
    • 在Button 外面使用SizeBox等可以设置size的控件,设置size可以缩减 padding
  • 在 State中声明的Color 类型的属性,要么直接赋值,要么使用 final 进行修饰,不然会报错。
  • 在 main.dart 中 使用 runZonedGuarded 可以 捕获异常和输出,代码如下
bool get isInDebugMode {
  bool inDebugMode = false;
  return inDebugMode;
}

Future<Null> main() async {
  FlutterError.onError = (FlutterErrorDetails details) async {
    if (isInDebugMode) {
      // In development mode simply print to console.
      FlutterError.dumpErrorToConsole(details);
    } else {
      // In production mode report to the application zone to report to
      // Sentry.
      Zone.current.handleUncaughtError(details.exception, details.stack);
    }
  };

  //自定义错误提示页面
  ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails) {
    return Scaffold(
        appBar: AppBar(
          title: Text("错误页面"),
        ),
        body: Center(
          child: Text("Custom Error Widget"),
        ));
  };

  runZonedGuarded(
    () => runApp(MyApp()),
     zoneSpecification: ZoneSpecification(
       print: (Zone self, ZoneDelegate parent, Zone zone, String line) {collectLog(line); // 捕获所有的print
      },
     ),
    (error, stack) {
       var details = makeDetails(obj, stack);
       reportErrorAndLog(details);
    },
  );
}

  • flutter app 的正常模式和暗黑模式风格的定义是在MaterialApp中 theme 和 darkTheme 指定的。ThemeData中的brightness 属性 指定是正常模式还是暗黑模式
  • 使用 dart语言中extension on 语法 可以扩展系统中的类的属性,比如我们可以扩展 ThemeData 来添加项目中使用到的颜色,demo如下:
extension CustomThemeData on ThemeData {
  Color get primaryBlue => brightness == Brightness.dark ? Color(0xFF228AEE) : Color(0xFF1880EE);
  // ignore: non_constant_identifier_names
  Color get primaryBlue_outline => brightness == Brightness.dark ? Color(0xFF228AEE) : Color(0xFF1880EE);
}
  • ThemeData中涉及到很多系统中使用到的颜色,和样式,这些内容的修改可以影响到所有使用的页面和控件(自定义过颜色样式的除外)。修改时需要谨慎。
  • Platform 类中涉及到了app运行平台的信息,如:运行app的系统是android还是ios,运行环境(Map<String, String> environment)等内容
  • dart:ui 包下面的Window对象 包含了app的默认route,设备的PixelRatio等信息,可以之间在 state或 Widget 的方法中之间使用window这个对象
  • 可以使用 TextPainter 来提前获取Text中写入字符串时的size,Text 中的style,必须和TextSpan中的style一致,代码如下:
 TextPainter painter = TextPainter(text: TextSpan(text: v, style: fieldTextStyle), textDirection: TextDirection.ltr);
                   painter.layout();
   print(painter.width);
  • 使用 GlobalKey 的方式获取控件的size,需要在绘制完界面后才有效代码如下:
  final GlobalKey _textFieldKey = GlobalKey();
  Text("aaa",  key: _textFieldKey,);
  double  inputWidth = _textFieldKey.currentContext.size.width;

  • 获取屏幕Size,使用 MediaQuery.of(context).size

  • flutter 中图片的使用需要在pubspec.yaml中 声明,代码如下:

    图片放在和pubspec.yaml同级的iamges文件夹中

  flutter:
   uses-material-design: true
  assets:
    - images/
    
  //图片使用时的代码,使用在pubspec.yaml声明时的图片路径+图片的名字
  //Contanier 的 decoration中可以设置image decoration ,使用 DecorationImage对象,可以直接加载 asserts 中 的image 资源
Container(
        ……
   decoration: BoxDecoration(
          image: DecorationImage(
              image: AssetImage("images/warnIcon.png")),
        ) )
        )
  • 在 自定义的StatefulWidget中若有需要动态刷新的数据或子widget ,请在build()方法中使用widet.xx 来获取最新的值
  • notification 用于 子widget 给父widget 传递数据,使用方式如下:
    • 继承 Notification 类,创建 notification 数据类,demo 如下:
class BannerNotification extends Notification {
   
    BannerNotification(this.isShow,
      {
   this.type,
      this.tip,
    ……
    });

  String tip;
  int type;
……
}```

 - 在父widget的build中 return  NotificationListener 对象,代码如下:
 
 ```dart 
  @override
  Widget build(BuildContext context) {
   
    return NotificationListener<BannerNotification>(
      onNotification: (notification) {
   
      //处理逻辑 的代码
      ……
      return ture;
            },
      child:  Text("aaa")
       );
  }
}
  • 子widget中使用 notification ,代码如下:
notification.dispatch(context);
  • dispatch(context)中的context必须是在子widget的context,若在如点击事件等callback 方法中使用时,可以在子widget的外层加上Builder,确保context层级小于父widget,代码如下:
  Builder(
         builder: (context) {
         return MaterialButton(onPressed: (){
              return MaterialButton(onPressed: (){
             ……
           },);
           },);
         },
       )
  • 在 base body 这种 全局式的 父widget ,可以在需要使用notification的子widget的外层加上 Builder(),然后将context赋值给static 修饰的全局 context对象,在定义的static 方法中集中调用 ,使用 notification.dispatch(context);,代码如下:
class BaseBody extends StatelessWidget {
final Widget child;
static BuildContext _buildContext;

static void switchBanner(BannerNotification notification) {
 notification.dispatch(_buildContext);
}

@override
Widget build(BuildContext context) {
 return NotificationListener<BannerdNotification>(
   onNotification: (notification) {
   ……
   //逻辑代码
        return true;
   },
   child: Stack(
     children: <Widget>[
       Builder(
         builder: (context) {
           BaseBody._buildContext = context;
           return widget.child;
         },
       ),
     ],
   ),
 );
 }
}          
  • 自定义 widget中 使用了AnimationController ,Timer 等需要dispose的widget时,若在 state 的dispose()方法中调用 dispose方法时,要在super.dispose();之前调用,因为有时会出现controller 在页面退出后没有dispose的问题,代码如下:
 @override
  void dispose() {
     _controller?.dispose();
    super.dispose();
  }
  //若还是出现controller 没有dispose ,可以在deactivate 中执行 controller?.dispose();
 
  @override
  void deactivate() {
  _controller?.dispose();
    super.deactivate();
  }
  • 完全自定义 TextField中的contentPadding,代码如下:

    TextField(
             scrollPadding: EdgeInsets.zero,//默认是20,现在改成0
                       decoration: InputDecoration(
                 contentPadding: EdgeInsets.only(left: 12.px, right: 2.px, top: 12.px, bottom: 12.px),//自定义 contentPadding
                   isDense: true,//为true时 ,TextField的vertical方向没有space,默认是false。
              ),
                      )
    
  • TextField 中 keyboardType 属性中 TextInputType.visiblePassword 为设置键盘模式为输入密码模式,但是 输入的字符是可见的,若想不可见,可以设置 TextField的obscureText 属性为 ture,则输入字符不可见。代码如下:

    TextField(
          keyboardType: TextInputType.visiblePassword,
           autofocus: true,
                     ……
          ),
  • flutter中的动画,一般动画使用代码如下,
//动画的控制类,如动画的播放,暂停,反转,重复。
 _controller = AnimationController(
        duration: Duration(milliseconds: 250), vsync: provider)
      ..addStatusListener((status) {
      //动画状态的监听,completed,dissmiss,forward,reverse
               }
      })..addListener(() {
      
      //在此获取动画的当前值。
    var a =  _controller.value; //a的值为0到1之间
      var b =  _animation.value;/ /b的值在Tween定义的begin与end之间。

      });
      //CurvedAnimation 定义运动变化的速率,curve: 决定动画的差值器
    var curved =  CurvedAnimation(parent: _bannerController, curve: Curves.easeOut)
      // Tween 中定义动画的取值区间,数值可以是任意类型,如 Color,Offset,double等。

    _animation = Tween(begin: Offset(0, -1), end: Offset(0, 0)).animate(curved);
  }
  • 使用TweenSequence和 TweenSequenceItem 可以定义分阶段的连续动画,代码如下:

	//weight:执行时长占总时长的权重
	//TweenSequenceItem : 定义不同的动画
    Animation animation=TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 0,end: 100),weight: 20),
      TweenSequenceItem(tween: CurveTween(curve:Curves.easeIn ),weight: 80)
    ]).animate(  _controller);
  • ShaderMask 设置 widget的颜色渐变图层
    • Gradient颜色渐变的方式:LinearGradient(线形变换);RadialGradient(放射状变化);SweepGradient(扇形变化)

    • blendMode:颜色混合模式

    • tileMode:指定在begin,end之外的区域颜色如何渲染,repeated:重复使用区域之内的渲染颜色;clamp:按照接近的区域内的颜色;mirror:以镜像模式重复区域内的渲染颜色

    • demo如下:


    ShaderMask(
        shaderCallback: (Rect bounds) {
          
          return RadialGradient(
            center: Alignment.bottomCenter,
            radius: _gradientValue,
            colors: <Color>[_iconColor, _loadingColor],
            stops: [_gradientValue, 1],
              tileMode: TileMode.repeated,
          ).createShader(bounds);
        },
      
        blendMode: BlendMode.srcATop,
        child: Icon(
          _icon,
          size: _iconSize,
        ),
      )

      ShaderMask(
        shaderCallback: (Rect bounds) {
          return SweepGradient(
            center: Alignment.bottomCenter,
            startAngle: 0,
            endAngle: pi,
            tileMode: TileMode.clamp,
            colors: <Color>[_iconColor, _loadingColor],
            stops: [_gradientValue, 1],
          ).createShader(bounds);
        },
        blendMode: BlendMode.dstOver,
        child: Icon(
          _icon,
          size: _iconSize,
        ),
      )
      LinearGradient(
            begin: Alignment.bottomCenter,
            end:  Alignment.topCenter,
            tileMode: TileMode.mirror,
            colors: <Color>[_iconColor, _loadingColor],
            stops: [_gradientValue, 1],
          ).createShader(bounds);
        },
        blendMode: BlendMode.dstATop,
        child: Icon(
          _icon,
          size: _iconSize,
        ),
      );
  • Container 中设置阴影效果

    • 的style 有 outer,inner,normal,solid

    • demo

      
         Container(
             ……
            decoration: BoxDecoration(
                   shape: BoxShape.circle,
                   boxShadow: [
                     BoxShadow(
                       color: Color(0xFF000000),//阴影的颜色
                       blurRadius: 10.px,//阴影的半径
                       offset: Offset(2.px, 2.px),//shadow 对于 box的偏移量
                       spreadRadius: 10.px,//box扩展的大小
                     ),
                   ],
                 ),
           )
      
  • box shadow的原理

//ui.shadow 
  	 static double convertRadiusToSigma(double radius) {
   
       return radius * 0.57735 + 0.5;//阴影的逻辑像素计算公式
  }
  //根据传入的半径,计算阴影的逻辑像素
  double get blurSigma => convertRadiusToSigma(blurRadius);
  Paint toPaint() {
   
    return Paint()
      ..color = color
      //使用 MaskFilter.blur 实现paint的阴影效果
      ..
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值