美文网首页
flutter开发中一些技巧和坑点

flutter开发中一些技巧和坑点

作者: AJI大侠 | 来源:发表于2019-03-29 10:45 被阅读0次

    获取设备宽高

    double width = MediaQuery.of(context).size.width;
    double height = MediaQuery.of(context).size.height;
    

    Android设置状态栏透明

    1. 原生修改
    public class MainActivity extends FlutterActivity {
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
             // api大于21设置状态栏透明
            getWindow().setStatusBarColor(0);
        }
        GeneratedPluginRegistrant.registerWith(this);
      }
    }
    
    1. flutter修改(么有测试过,自己测试下反正不难)
    // 输出渲染
    void main() {
      runApp(App());
      if (Platform.isAndroid) {
        // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。
        SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
        SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
      }
    }
    

    区别final与const

    在Dart中,当你不需要去改变一个变量的时候,应该使用final或者const,而不是使用var去声明一个变量。一个final变量只允许被赋值一次,必须在定义时或者构造函数参数表中将其初始化。
    const所修饰的是编译时常量,我们在编译时就已经知道了它的值,它的值是不可改变的。
    const比final更加严格,看以下例子:

    final List<String> list = [];
    list.add('1'); // 正确
    
    const List<String> list = [];
    list.add('1'); // 错误,运行时报错:Cannot add to an unmodifiable list
    
    
    final timestamp = new DateTime.now().millisecondsSinceEpoch; // 正确
    
    const timestamp = new DateTime.now().millisecondsSinceEpoch; // 错误,编译前报错:Const variables must be initialized with a constant value
    
    

    FocusScope转移焦点,隐藏输入法

    166723349530a968.gif
    Container(
            height: 500.0,
            child: new GestureDetector(
              onTap: () {
                // 通过GestureDetector捕获点击事件,再通过FocusScope将焦点转移至空焦点      new FocusNode()
                FocusScope.of(context).requestFocus(FocusNode());
              },
              child: Container(
                  margin: EdgeInsets.all(30.0),
                  child: ListView(children: <Widget>[
                    TextField(
                      decoration: InputDecoration(labelText: 'Username'),
                    ),
                    TextField(
                      decoration: InputDecoration(labelText: 'Password'),
                    )
                  ])),
            ),
          ),
    
    • 这里传递给FocusScope的context不能在MaterialApp下面,即你需要将这部分代码放到独立的一个Widget里面

    定时任务

    1. 在我们的开发之中难免要用到定时,比如我们常用的获取验证码的需求,下面请看利用定时器来实现这一功能需求
    • 定义3个变量
    int _seconds = 0;
    String _verifyStr  = "获取验证码";
    /// 定时器Timer
    Timer _timer;
    
    • 实现timer,代码很清晰,简单的说我设了10秒的倒计时,利用Timer.periodic方法来执行,间隔时间是1秒
    /// 倒计时
      _startTimer() {
        _seconds = 10;
    
        _timer = Timer.periodic(new Duration(seconds: 1), (timer){
          if(_seconds == 0){
            _cancleTimer();
            return;
          }
          _seconds--;
          _verifyStr = "${_seconds}s";
          if (_seconds == 0){
            _verifyStr = "重新发送";
          }
          setState(() {});
        });
      }
    
      _cancleTimer(){
        _timer?.cancel();
      }
    
    @override
      void dispose() {
        // TODO: implement dispose
        super.dispose();
       /// 页面销毁的时候,清除timer
        _cancleTimer();
      }
    
    • 执行,并不是每次按都执行_startTimer,加上判断条件只有_seconds == 0时才执行效果如下图
    new Container(
              padding: const EdgeInsets.only(top: 15.0, left: 15.0),
              child: new RaisedButton(
                /// 触发定时任务
                onPressed: (_seconds == 0)?(){
                  _startTimer();
                }:null,
                child: new Text(_verifyStr),
                shape: new RoundedRectangleBorder(
                  borderRadius: new BorderRadius.all(new Radius.circular(15.0)),
                ),
                textColor: Colors.blue,
                color: Colors.yellowAccent,
                disabledColor: Colors.yellowAccent,
                disabledTextColor: Colors.blue,
              ),
            ),
    
    GIF.gif

    利用 Container的BoxDecoration装饰实现渐变

    • 例子如下
     Container(
            decoration: BoxDecoration(gradient: LinearGradient(
              colors: [const Color(0xFFFFFFEE), const Color(0xFF999999),const Color(0xFF862547),],
              tileMode: TileMode.repeated, // repeats the gradient over the canvas
            ),),
    
    • 效果如下


      渐变.png
    • BoxDecoration的属性

    const BoxDecoration({
        this.color, // 盒子颜色
        this.image, // 图片
        this.border, 边框颜色和线宽度
        this.borderRadius, // 圆角度
        this.boxShadow, // 阴影
        this.gradient, // 渐变
        this.backgroundBlendMode, // 混合Mode
        this.shape = BoxShape.rectangle,  // 形状
      }) 
    
    • 边框圆角实现
    decoration: new BoxDecoration(
      border: new Border.all(color: Color(0xFFFF0000), width: 1.0), // 边色与边宽度
      color: Color(0xFF999999), //  盒子颜色
      //        borderRadius: new BorderRadius.circular((15.0)), // 圆角度
      borderRadius: new BorderRadius.vertical(top: Radius.elliptical(20, 50)), // 也可控件一边圆角大小
    ),
    
    • Dart知识点(?. / ??)
    1. ?. 运算符在左边为null的情况下会阻断右边的调用。
    2. ?? 运算符表示在左侧表达式为null时为其设置默认值。

    对于表达式:

    tar[a]?.tars(b)
    

    如果tar为null或tar[a]为null或tars(b)的值为null,都会导致表达式为null。

    1. operator重载操作符
      operator 是 Dart 的一个关键字,它和运算符(如=,+,-)一起使用,表示一个 运算符重载函数,在理解时可将operator和运算符(如operator=)视为一个函数名

    关于混编中退出flutter页面的时候黑屏的情况

    if(Navigator.canPop(context)){
      Navigator.pop(context, true);
    }else {
      SystemNavigator.pop();
    }
    

    关于ListView中嵌套使用ListView,请在子组件中设置以下属性

    shrinkWrap: true,
    

    底部弹窗默认点击消失,如何保持面板点击不消失

    • 可以子组件外面包一层GestureDetector并设置onTap为false,拦截点击事件可以使点击底部面板区域时不消失。
     showModalBottomSheet(
            context: context,
            builder: (context) {
              return GestureDetector(
                onTap: () => false,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    titleWidget,
                    twoWidget,
                    Expanded(
                      child: BottomUserRankingPage(
                        context,
                        lists: lists,
                      ),
                    ),
                  ],
                ),
              );
            });
    

    实现跳转到广告按back返回是主界面

     Navigator.of(context).pushReplacementNamed('/Main');
     Navigator.of(context).push(WebPage);
    

    如何强制竖屏

    void main() {
      SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
        .then((_) {
          runApp(new MyApp());
        });
    }
    

    在线上的app,如果flutter报错,那一片红可是非常的辣眼睛,给用户的体验也很不好,其实我们可以自定义错误页面

    ErrorWidget.builder = (FlutterErrorDetails details) {
        print(details.toString());
        return Center(
          child: Text("Sorry 我下班了"),
        );
      };
    

    在Flutter中,加载本地图片会存在一个加载过程。比如点击图标做图标的切换时,那么首次会发生闪动的情况。尤其是做类似引导页这类需求是,通过左右滑动切换图片时会发生比较明显的白屏一闪而过。

    解决方法很简单,就是使用 precacheImage,它将图像预存到图像缓存中。如果图像稍后被使用,它会被加载得更快。

    precacheImage(AssetImage("assets/mylogo"), context);
    

    在iOS 13中遇到了http网页打不开的问题,添加以下文字到Info.plist
    yourdomain.com 是你请求的链接的域名

    <key>NSAppTransportSecurity</key>
        <dict>
            <key>NSExceptionDomains</key>
            <dict>
                <key>yourdomain.com</key>
                <dict>
                    <key>NSExceptionAllowInsecureHTTPLoads</key>
                    <true/>
                </dict>
            </dict>
            <key>NSAllowsArbitraryLoadsInWebContent</key>
            <true/>
            <key>NSAllowsArbitraryLoads</key>
            <true/>
        </dict>
    

    相关文章

      网友评论

          本文标题:flutter开发中一些技巧和坑点

          本文链接:https://www.haomeiwen.com/subject/flxqzftx.html