Android Flutter如何实现创意时钟的示例代码

时钟这个东西很奇妙,总能当做创意实现的入口,比如这个大神用compose实现了一个小创意时钟 看下效果习惯把Compose这种组合声明的开发方式叫热插拔,节省了

时钟这个东西很奇妙,总能当做创意实现的入口,比如这个大神用compose实现了一个小创意时钟

看下效果

习惯把Compose这种组合声明的开发方式叫热插拔,节省了大量代码,简化了开发,尤其Modifier这个神奇的东西,熟悉了解决一切样式的问题。

看了下他的源码,很简单,百十行左右,不多说,用Flutter仿一份。或者你觉得简单直接看GitHub欢迎批评指正

本案例使用的环境是:

Flutter (Channel stable, 2.2.3, on macOS 11.0.1 20B29 darwin-arm, locale zh-Hans-CN)
    • Flutter version 2.2.3 at /Users/moon/Documents/sdk/flutter
    • Framework revision f4abaa0735 (2 months ago), 2021-07-01 12:46:11 -0700
    • Engine revision 241c87ad80
    • Dart version 2.13.4
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn

1.构建一个代表时间的小格子

一个最普通的Container 里包含一个text

_Number() {
  return Container(
    width: 40,
    height: 40,
    child: Text(
      "5",
      style: TextStyle(color: Colors.white, fontSize: 16),
    ),
  );
}

通过看上边的gif图就能设计出来,小格子是有状态的,是当前的时间点数字的话背景色改变,同时也可以让这个数字的字体变大一点,区别于其他数字,而且他会在所在的列里位于屏幕的中部。 所以先简单封装下这个小格子。

_Number(int number, bool isActive) {
  var backgroundColor;
  var numberSize;
  if (isActive) {
    backgroundColor = Colors.black;
    numberSize = 18.0;
  } else {
    backgroundColor = Colors.deepPurpleAccent;
    numberSize = 16.0;
  }

  return Container(
    alignment: Alignment.center,
    width: _normalSize,
    height: _normalSize,
    child: Text(
      "$number",
      style: TextStyle(color: Colors.white, fontSize: numberSize),
    ),
  );

2.构建一列小格子

既然是几列数字条构成的一个时钟,所以想下大概是绘制出一条就可以了,其他的几个传不同的数字和状态就可以, Compose里用column,Flutter里同样有这个东西,当然用listview 或其他的容器都可以。

child: Column(
  children: [
      _Number(1 , false,),
      _Number(2 , false,),
      _Number(3 , false,),
      _Number(4 , false,),
      _Number(5 , true,),
  ],
))

为了美观可以切个圆角,这点compose的modifier就体现出了优势, 可以直接clip column,但Flutter却没那么强大,只能根据位置对每个小格子单独处理了。

if (number == 0) {
  borderRadius = BorderRadius.only(
      topLeft: Radius.circular(15), topRight: Radius.circular(15));
} else if (number == (totalSize - 1)) {
  borderRadius = BorderRadius.only(
      bottomLeft: Radius.circular(15), bottomRight: Radius.circular(15));
} else {
  borderRadius = BorderRadius.all(Radius.zero);
}
decoration: BoxDecoration(
  color: backgroundColor,
  borderRadius: borderRadius,
),

或许还有其简单方式设置边角,请朋友提示。

3.构建多列小格子

同理搞出六列格子,代表双位的时分秒,可以用row 包裹六个 column ,设置外层container的子widget都居中,接受当前时间作为状态,突出显示就可以了。 比如现在是21:49:15

这样就画出了一个单独的静态时间刻度。

4.关于Align

这个图好像不太对,一种乱糟糟的感觉,需要能一眼看出当前时间才行,即把所有时间对齐在一条线上。

这方面Compose 发挥了优势, modifier的 offset 可以轻松实现位移。

val mid = (range.last - range.first) / 2f 
val offset = 40.dp * (mid - current)
Modifier .offset(y = offset)

flutter 里貌似没这么方便了,怎么实现呢,我使用了Align组件,简单说明下, 以下摘自官方。

Align 组件可以调整子组件的位置,并且可以根据子组件的宽高来确定自身的的宽高,定义如下:

Align({
  Key key,
  this.alignment = Alignment.center,
  this.widthFactor,
  this.heightFactor,
  Widget child,
})
  • alignment : 需要一个AlignmentGeometry类型的值,表示子组件在父组件中的起始位置。AlignmentGeometry 是一个抽象类,它有两个常用的子类:Alignment和 FractionalOffset
  • widthFactorheightFactor是用于确定Align 组件本身宽高的属性;它们是两个缩放因子,会分别乘以子元素的宽、高,最终的结果就是Align 组件的宽高。如果值为null,则组件的宽高将会占用尽可能多的空间。

举例如下

Container(
  height: 120.0,
  width: 120.0,
  color: Colors.blue[50],
  child: Align(
    alignment: Alignment.topRight,
    child: FlutterLogo(
      size: 60,
    ),
  ),
)

我显式指定了Container的宽、高都为120。如果我不显式指定宽高,而通过同时指定widthFactorheightFactor 为2也是可以达到同样的效果:

Align(
  widthFactor: 2,
  heightFactor: 2,
  alignment: Alignment.topRight,
  child: FlutterLogo(
    size: 60,
  ),
),

5.对齐时间线

分析,Align实际上就是把原高度扩大为之前的 heightFactor 倍数,而它的子widget仍然处于Align的顶部,而当前时间点位于column顶部的距离是已知的,所以要让当前时间点的数字定位于 Align的中间 ,需要补齐(或截掉)当前时间点的格子下边的空间。 为了示意明确,我给总体背景和 Align 背景都加了颜色。

第一列: 小时首位,只有三个格子, 当前是2, 2位于第三个,所以需要给下边补齐两个格子, 第二列:小时的末位,共有10个格子,当前数字也是2 ,也位于第三个,为了让上下相等,需要截掉4以下的数字,让2位于中间位置。

以此类推。

这下就可以发现规律了。 高度的系数因子为 :

(current * 2 + 1)/numbers.length

numbers.length 是列的长度。 因此, 每列的函数可以写为

_columnNumber(List<int> numbers, int current) {
  List<Widget> list = [];
  numbers.forEach((e) {
    list.add(_Number(e, e == current, numbers.length));
  });

  return Container(
    color: Colors.white,
    child: Align(
      alignment: Alignment.topCenter,
      widthFactor: 1,
      heightFactor: (current *2 + 1)/numbers.length,
      child: Container(
        height: numbers.length * _normalSize,
        margin: EdgeInsets.only(left: 5, right: 5),
        child: Column(
          children: list,
        )),
    ),
  );
}

至此一个静态时间钟就绘制完成。

6.动起来

获取当前时间,开启计时器,每秒刷新一次就可以实现动态效果了 这个比较简单,不再复述了。

完整代码

总结下: Compose 和 Flutter、SwiftUI都是声明式UI,良好的设计已经确定了是发展趋势, 同时上手简单,更能把精力专注在业务上。

以上就是Android Flutter实现创意时钟的示例代码的详细内容,更多关于Android Flutter时钟的资料请关注好代码网其它相关文章!

您可能有感兴趣的文章
Android Studio下Flutter环境搭建图文好代码教程

Android Studio 下 Flutter 开发环境搭建过程

Android Flutter如何实现"斑马纹"背景的示例代码

Android Studio生成 Flutter 模板代码技巧详解

Android开发中Dart语言7个很酷的特点