本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
Android Flutter实现创意时钟的示例代码
zhuxiaoqiang · 320浏览 · 发布于2023-03-31 +关注

时钟这个东西很奇妙,总能当做创意实现的入口。这篇文章主要介绍了如何通过Android Flutter实现一个创意时钟,感兴趣的小伙伴可以了解一下


时钟这个东西很奇妙,总能当做创意实现的入口,比如这个大神用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。

  • widthFactor和heightFactor是用于确定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。如果我不显式指定宽高,而通过同时指定widthFactor和heightFactor 为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下vulkan与opengles纹理互通

talkchan · 1175浏览 · 2020-11-23 10:37:39
Android 使用RecyclerView实现轮播图

奔跑的男人 · 2175浏览 · 2019-05-09 17:11:13
微软发布新命令行工具 Windows Terminal

吴振华 · 869浏览 · 2019-05-09 17:15:04
Facebook 停止屏蔽部分区块链广告

· 754浏览 · 2019-05-09 17:20:08
加载中

0评论

评论
我爱编程,我爱工作,更爱生活
小鸟云服务器
扫码进入手机网页