美文网首页
Flutter 技术分享

Flutter 技术分享

作者: Mr_step | 来源:发表于2022-04-09 09:57 被阅读0次

    技术演进

    伴随着 Android、iOS 等智能手机的不断普及,移动端已逐步取代 PC 端,成为兵家必争之地。正所谓“得移动端者得天下”,移动端已成为互联网领域最大的流量分发入口,一大批互联网公司正是在这大趋势下崛起。

    为什么需要跨平台技术呢

    伴随着移动互联网的高速发展,公司间竞争越来越激烈,如何将好想法快速落地、快速试错,成为备受关注的问题。提升研发效率、缩短研发周期,降低成本,让新产品新功能以最快的速度同时抵达 Android、iOS 等多端用户,成为了许多公司移动端技术的选型基础。
    为了解决这一痛点。跨平台技术便应运而生,各大互联网公司为此都投入大量人力,于是出现了各种跨平台技术框架,面对移动领域的跨平台技术方案的层出不穷,又该如何做技术选型呢。

    跨平台的技术划分

    跨平台技术大致可分为三大类 :
    1.依赖于Webview,性能体验差 如Cordova,小程序
    2.使用JavaScript作为编程语言,通过中间层转化为原生控件来渲染UI界面,比如React Native、Weex。
    3.自行实现一套渲染框架,可通过调用skia等方式完成自渲染,而不依赖于原生控件,如Flutter、Unity

    技术选型

    我认为的移动端的跨端技术方案,关注的分为4个方面:
    1.研发效率:
    代码复用,减少多端差异的适配工作量,降低开发成本,专注业务开发 。这也是跨平台技术会出现的重要原因之一
    2.多端一致性,
    很多产品在多端UI设计上,往往是整体风格统一,所以业务方采用原生各自独立开发完成后,还需额外花不少时间来修改UI以保证多端一致性。
    3.性能体验
    一般跨端技术方案拥有以上两种优势,但在性能方面比原生流畅更差些。如果哪天跨平台技术能和Native一样流畅,那么Native 可能就要退出历史舞台了。

    Flutter技术优势

    Flutter是彻底的跨平台方案,既没有采用webView,也没有采用JS桥接原生控件,而是自行实现一套UI框架,在引擎底层通过Skia渲染到屏幕。对于UI之外所需要使用的移动设备自身提供的服务,比如相机、定位、屏幕触摸等,则采用Platform Channels跟原生系统通信的方式来实现

    1.高效率
    采用dart语言编写代码,一套代码适用多个平台(Android、iOS、Web),以及高效的Hot Reload能快速辅助调试。

    2.高一致性:实现UI像素级的控制,Flutter渲染引擎依靠跨平台Skia图形库来实现,仅依赖系统图形绘制相关的接口

    3.高性能 image.png

    通过一张渲染原理来看Flutter的性能优势,作为谷歌亲儿子,Flutter框架调用Dart Framework层,再直接调用到skia来渲染界面,并没有经过原生Framework过程,可见其渲染性能并不会弱于Native技术,这是一个性能上限很高的跨平台技术。

    当然,不得不说目前的Flutter确实不够尽善尽美,会存在一些不够尽善尽美之处,比如生态不够健全,包体积问题,还有大天朝的网络问题,但其该方案的上限比较高,想象空间比较大,相信更多开发者参与进来,经过更多打磨,未来会做得更好

    Flutter未来趋势

    目前Flutter主要在Android/iOS/Web/Windows跨端,后续可能会嵌入式设备。Fuchsia是Google内部正在开发的一款新的操作系统,采用Flutter作为系统默认的UI框架,也就是说Flutter天然支持Fuchsia,这无疑让Flutter在众多的跨平台方案更有优势.

    小🌰:
    滑动列表的实现

    import 'dart:math' as math;
    
    import 'package:flutter/material.dart';
    import 'package:flutter/material.dart' as W;
    import 'package:flutter/rendering.dart';
    
    class SliverListDemoPage extends StatefulWidget {
    
      @override
      _SliverListDemoPageState createState() => _SliverListDemoPageState();
    }
    
    class _SliverListDemoPageState extends State<SliverListDemoPage>
        with SingleTickerProviderStateMixin {
      int listCount = 30;
    
      List<Widget> _sliverBuilder(BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[
          ///头部信息
          SliverPersistentHeader(
            delegate: SliverHeaderDelegate(
              maxHeight: 180,
              minHeight: 180,
              vSync: this,
              snapConfig: FloatingHeaderSnapConfiguration(
                curve: Curves.bounceInOut,
                duration: const Duration(milliseconds: 10),
              ),
              child: Container(
                color: Colors.redAccent,
              ),
            ),
          ),
          SliverOverlapAbsorber(
            handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
            sliver: SliverPersistentHeader(
              pinned: true,
    
              /// SliverPersistentHeaderDelegate 的实现
              delegate: SliverHeaderDelegate(
                  maxHeight: 60,
                  minHeight: 60,
                  changeSize: true,
                  vSync: this,
                  snapConfig: FloatingHeaderSnapConfiguration(
                    curve: Curves.bounceInOut,
                    duration: const Duration(milliseconds: 10),
                  ),
                  builder: (BuildContext context, double shrinkOffset,
                      bool overlapsContent) {
                    ///根据数值计算偏差
                    var lr = 10 - shrinkOffset / 60 * 10;
                    return SizedBox.expand(
                      child: Padding(
                        padding: EdgeInsets.only(
                            bottom: 10, left: lr, right: lr, top: lr),
                        child: Row(
                          mainAxisSize: MainAxisSize.max,
                          children: <Widget>[
                            Expanded(
                              child: Container(
                                alignment: Alignment.center,
                                color: Colors.orangeAccent,
                                child: TextButton(
                                  onPressed: () {
                                    setState(() {
                                      listCount = 30;
                                    });
                                  },
                                  child: const Text("按键1"),
                                ),
                              ),
                            ),
                            Expanded(
                              child: Container(
                                alignment: Alignment.center,
                                color: Colors.orangeAccent,
                                child: TextButton(
                                  onPressed: () {
                                    setState(() {
                                      listCount = 4;
                                    });
                                  },
                                  child: const Text("按键2"),
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    );
                  }),
            ),
          ),
        ];
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("SliverListSticky"),
          ),
          body: Container(
            child: NestedScrollView(
              physics: const AlwaysScrollableScrollPhysics(),
              headerSliverBuilder: _sliverBuilder,
              body: CustomScrollView(
                slivers: [
                  W.Builder(
                    builder: (context) {
                      return SliverOverlapInjector(
                          handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                              context));
                    },
                  ),
                  SliverList(
                    delegate: SliverChildBuilderDelegate(
                          (context, index) {
                        return Card(
                          child: Container(
                            height: 60,
                            padding: const EdgeInsets.only(left: 10),
                            alignment: Alignment.centerLeft,
                            child: Text("Item $index"),
                          ),
                        );
                      },
                      childCount: 100,
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      }
    }
    
    ///动态头部处理
    class SliverHeaderDelegate extends SliverPersistentHeaderDelegate {
      SliverHeaderDelegate(
          {required this.minHeight,
            required this.maxHeight,
            required this.snapConfig,
            required this.vSync,
            this.child,
            this.builder,
            this.changeSize = false});
    
      final double minHeight;
      final double maxHeight;
      final Widget? child;
      final Builder? builder;
      final bool changeSize;
      final TickerProvider vSync;
      final FloatingHeaderSnapConfiguration snapConfig;
      AnimationController? animationController;
    
      @override
      double get minExtent => minHeight;
    
      @override
      double get maxExtent => math.max(maxHeight, minHeight);
    
      @override
      TickerProvider get vsync => vSync;
    
      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        if (builder != null) {
          return builder!(context, shrinkOffset, overlapsContent);
        }
        return child!;
      }
    
      @override
      bool shouldRebuild(SliverHeaderDelegate oldDelegate) {
        return true;
      }
    
      @override
      FloatingHeaderSnapConfiguration get snapConfiguration => snapConfig;
    }
    
    typedef Widget Builder(
        BuildContext context, double shrinkOffset, bool overlapsContent);
    

    在 Flutter 里我们常见的滑动列表场景,大致是由三部分组成:
    Viewport : 它提供的是一个“视窗”的作用,也就是列表所在的可视区域大小;
    Scrollable :它主要通过对手势的处理来实现滑动效果 ,比如VerticalDragGestureRecognizer 和 HorizontalDragGestureRecognizerRenderSliver, : 它主要是用于在 Viewport 里面布局和渲染内容

    一般情况下 Viewport 和 Scrollable 的实现都是很通用的,所以一般在 Flutter 里要实现不同的滑动列表,就是通过自定义和组合不同的 Sliver 来完成布局
    ListView 使用的是 SliverFixedExtentList 或者SliverList
    GridView 使用的是 SliverGrid
    PageView 使用的是 SliverFillViewport
    ListView 是由 Viewport+ Scrollable 和一个RenderSliver 组成,所以在ListView 里只会有一个 RenderSliver而不是多个,想使用多个 RenderSliver 需要使用 CustomScrollView

    相关文章

      网友评论

          本文标题:Flutter 技术分享

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