Android技术知识FlutterAndroid开发

移植一个抖音贴纸组件到Flutter

2019-06-18  本文已影响491人  何时夕

本文发于简书——何时夕,搬运转载请注明出处,否则将追究版权责任。交流qq群:859640274

大家好久不见,又有一个多月没有发文章了,所以今天发一篇来刷刷存在感。最近 Flutter 非常火,我这一个月也不断的找资料来学习 Flutter。经过一段时间的摸索,我发现现在很多资料都非常”水“。各种 Dart 入门、Flutter 入门、Flutter 资料收集,完全没有任何有趣的东西。我不想去写重复而无聊的文章,所以本篇文章会抛转引玉的探讨一些在学习和开发 Flutter 的过程中遇见的问题和解决方案。

阅读须知:

本文分为以下章节,读者可按需阅读:

一、Flutter之问

天下事有难易乎?为之,则难者亦易已!

Q:Flutter 怎么学?

A:这是老生常谈的问题了。随便打开一个 Flutter 系列文章,都会为你铺平接下来几周的路。但是几周之后呢?似乎很少文章会接着写下去,毕竟大脑最喜欢简单的东西(我也不例外),一件事情的难度与受欢迎程度成反比。所以 Flutter 怎么学?所谓:取乎其上,得乎其中。我只有一句话:以让 Flutter 成为你最拿手技能为目标去学。

Q:能给一些 Flutter 的学习资料吗?

A:我列举一下我学习 Flutter 过程中用到的资料:

Q:Flutter 会干掉 Native?

A:Flutter 是 Native 的子集。在手机被”革命“之前,但凡业务比较复杂的公司,只会要求 Native 工程师掌握 Flutter。而不会出现抛弃 Native 只做 Flutter 的工程师,因为 Flutter 说一千道一万只是一个 ui 框架。毕竟它自身的复杂度很难支撑起比它还复杂的业务。以上只是个人观点,有分歧可以在评论区探讨

Q:Flutter 哪些地方做的比 Native 好?

A:下面是我总结出来的 Flutter 比 Native 好的地方:

二、移植一个FluTter控件

经常读我的文章的读者应该看过我上一篇文章:抖音、ins、微信功能大比拼——Story的贴纸文字,这篇文章中详细比较了各家 Story 的贴纸文字的功能,然后在 Android 端实现了一个贴纸框架。而这一章我就打算将这个贴纸框架移植到 Flutter,相信最后的还原度会超过你的想象。接下来建议配合源码阅读文章。注意这一章的大部分内容和上一篇文章中讲解 Android 端实现控件的章节是差不多的。

github 地址

使用方式:sticker_framework: ^0.0.1

1.架构方式

我们第一节先讲讲文字贴纸控件的架构实现,我会基于下面的 图1 和 github 上的代码进行讲解。建议大家把代码 clone 下来,当然别忘了给个 star。

flutter文字贴纸架构.jpg

我们先来根据图1来讲讲整个控件的架构

2.技术点实现

我在开发整个控件的时候遇到过比较多的技术实现上的难点,所以这一节就选一些来讲讲,让读者在看源码的时候不会特别困惑。

(1).定义数据结构与绘制坐标系

-----代码块1----- ws_element.dart

int mZIndex = -1; // 图像的层级

  double mMoveX = 0.0; // 初始化后相对 ElementContainerWidget 中心的移动距离

  double mMoveY = 0.0; // 初始化后相对 ElementContainerWidget 中心的移动距离

  double mOriginWidth; // 初始化时内容的宽度

  double mOriginHeight; // 初始化时内容的高度

  Rect mEditRect; // 可绘制的区域

  double mRotate = 0.0; // 图像顺时针旋转的角度,以 π 为基准

  double mScale = 1.0; // 图像缩放的大小

  double mAlpha = 1.0; // 图像的透明度

  bool mIsSelected = false; // 是否处于选中状态

  bool mIsSingeFingerMove = false; // 是否处于单指移动的状态

  bool mIsDoubleFingerScaleAndRotate = false; // 是否处于双指旋转缩放的状态

  Widget mElementShowingWidget; // 展示内容的 widget

  Offset mOffset; // ElementContainerWidget 相对屏幕的位移

函数未动数据先行,数据结构是一个框架非常核心的东西,定义了一个好的数据结构可以省去很多不必要的代码。所以这一小节我们来根据代码块1定义一下数据结构和 Widget 绘制坐标系

(2).WE是如何刷新元素的

-----代码块2----- ws_element.dart
    
  add() {
    mElementShowingWidget = initWidget();
  }

  Widget initWidget();

  Widget buildTransform() {
    Matrix4 matrix4 = Matrix4.translationValues(mMoveX, mMoveY, 0);
    matrix4.rotateZ(mRotate);
    matrix4.scale(mScale, mScale, 1);
    return Transform(
      alignment: Alignment.center,
      transform: matrix4,
      child: Opacity(
        opacity: mAlpha,
        child: mElementShowingWidget,
      ),
    );
  }

(3).ECWS如何构建整个容器

-----代码块2----- element_container_widget.dart

@override
  Widget build(BuildContext context) {
    RawGestureDetector gestureDetectorTwo = GestureDetector(
      child: GestureDetector(
        child: Stack(
            alignment: AlignmentDirectional.center,
            key: globalKey,
            children: mElementList.map((e) {
              return e.buildTransform();
            })
                .toList()
                .reversed
                .toList()
        ),
        onPanUpdate: onMove,
        behavior: HitTestBehavior.opaque,
      ),
    ).build(context);
    gestureDetectorTwo.gestures[RotateScaleGestureRecognizer] =
        GestureRecognizerFactoryWithHandlers<RotateScaleGestureRecognizer>(
              () => RotateScaleGestureRecognizer(debugOwner: this),
              (RotateScaleGestureRecognizer instance) {
            instance
              ..onStart = onDoubleFingerScaleAndRotateStart
              ..onUpdate = onDoubleFingerScaleAndRotateProcess
              ..onEnd = onDoubleFingerScaleAndRotateEnd;
          },
        );
    return Listener(
      child: ConstrainedBox(
        constraints: BoxConstraints(
          minHeight: double.infinity,
          minWidth: double.infinity,
        ),
        child: gestureDetectorTwo,
      ),
      behavior: HitTestBehavior.opaque,
      onPointerDown: onDown,
      onPointerUp: onUp,
    );
  }

3.源码流程解析

这一节我主要会对项目中的测试 demo 进行源码流程分析,让读者对控件整体的运行方式有个简单的了解。这一节主要是讲解源码,所以读者一定要去 clone 源码,跟随文章的脚步前进。

(1).添加元素

(2).元素单指手势

元素手势不像添加元素那样需要外部调用,元素手势是通过事件分发触发的,我们这里不讲 Flutter 的事件分发机制,只讲我们基于其上的逻辑。

三、Flutter探究

这一章我会从一个 Android 工程师的角度来研究一下 Flutter,讲一讲我在移植控件时遇见的问题们。

1.Flutter与Android对比

先看看 Flutter 与 Android 写的 App 实际的比较吧

图2:对比 图3:flutter profile 图4:android profile

2.Flutter原理

以一个 Android 工程师的眼光来看 Flutter

(1).Flutter的事件简单总结

(2).Flutter的绘制逻辑

Flutter 核心原理

四、尾巴

啊!感觉这篇文章有点虎头蛇尾的感觉,文章从开始到结束跨了好几周。中间又是加班又是搬家,把我的热血都消磨了。本来多加一些 Flutter 的深入探究的,但是感觉会越写越久,所以先就这样。接下来我会写一系列文章来分析 Flutter 的原理和 Flutter Sdk。所以更多内容敬请期待!ps:一鼓作气,再而竭,三而衰。真是完美的表现了我写这篇文章的过程,希望读者们不要学我。

连载文章

不贩卖焦虑,也不标题党。分享一些这个世界上有意思的事情。题材包括且不限于:科幻、科学、科技、互联网、程序员、计算机编程。下面是我的微信公众号:世界上有意思的事,干货多多等你来看。

世界上有意思的事
上一篇 下一篇

猜你喜欢

热点阅读