Live Note

Remain optimistic

In this post, I want to share how I built a custom slider component that comes packed with useful features. This slider not only supports basic functionalities like step increments and configurable maximum/minimum values, but it also offers advanced features such as displaying scale tick values, suffix rendering, and custom value formatting. Whether you’re building a finance dashboard, a settings panel, or a data visualization tool, this component can be tailored to your needs.

Features

Step Increments

The slider supports step increments, allowing you to specify how much the slider’s value should increase or decrease with each move. This is particularly useful for ensuring users select values within a desired precision.

Scale Tick Values

To improve usability, the slider renders tick values along its track. These ticks provide a visual reference for users, making it easier to gauge the range and current value.

Maximum and Minimum Values

You can easily define the slider’s range by setting the maximum and minimum values. This ensures that users can only select a value within a valid, predetermined range.

Suffix Rendering

Often, slider values need to be accompanied by a unit (e.g., %, $, kg). With suffix rendering, you can easily append a suffix to the displayed value, making it clear what the number represents.

Custom Value Formatting

In some cases, the raw slider value might not be in the ideal format for display. This slider component allows you to pass a formatter function that converts the numeric value into a user-friendly string format.

Implementation Overview

Below is a simplified example of how the slider component is implemented using React and TypeScript:

Read more »

事业略有起色

3 月份从工厂离职了,真正意义上的工厂.每天除了当客服,收发快递,还有搬货/送货/扫地/修电脑/修网线… 如果真的说学到了什么东西, 那就是: “穷死不耕丈人田,饿死不打亲戚工”. 用最少的钱去让你干最多的活, 美其名曰”教学”, 实际上资源也不给, 就等你一个人摸爬滚打. 算了, 各自安好.

在厂里做过的工作

  • 收发快递
  • 收货/送货
  • 赶生产
  • 客服
  • 店铺运营
  • TikTok 运营
  • 摄影/美工/后期
  • 司机
  • 跑腿
  • 修电脑/修网线

工资: 5k-6k/月, 工作时间: 9:00-19:30, 工作日为 6 天/周.

4 月离职了, 找了一家做数字货币相关的公司,负责 React Native. 在我这小地方还是不错的, 因为工作岗位没那么多, 就将就下吧. 公司里有个老大哥, 看起来 blog 里面摸索过非常多的东西, 但是实际的代码真是一言难尽, 也可能是老项目的原因吧, 太多遗留了, 初期规划不好+没有彻底的理解, 就会导致项目越来越混乱.
项目最开始应该是要走 MVC 模式的, 但是不知道为什么写着写着就变成了 MVVM 模式, 导致代码混乱, 后期维护起来也很麻烦. 很多地方还会存在 State 刷新滞后问题, 因为整体是没有一个状态管理的, 靠的是强制更新最底层的一个 state 去整体刷新 page. 非常不友好.

奶奶送回老家了,说起来也有意思,四十来岁就跟着二伯父了, 劳累到七十多, 有点脑萎缩(记忆力减退,智商减退),二伯父一脚踢给大伯父了,哈哈. 所以说, 心不黑,不能成商啊. 准备过年回去看一下, 毕竟这种事小辈也不好掺和. 大伯父都不说话, 我还说什么呢? 不能交真心.

没什么想说的了, 年终总结也就是记流水账, 希望自己能坚持下去, 2025 继续努力.

去年的目标

Opps… 才发现去年没有写总结呢, 那就用前年的目标吧.

  • 英语,需要到精通需要学习上万小时,努力吧 : 正在努力学习
  • 攒钱了,先把婚姻大事搞定 : 嗯… 开销有点大, 今年存… flag
  • 目前的几本书先看完 : 说来也算看完了吧, 纸质书+微信读书. 而且我觉得微信读书非常好
  • 陪女朋友出省旅游一次 : 已经去了 南昌/南京/杭州 今年继续努力.
  • 日语还是慢慢来吧 : 在用 Duolingo 学习,但是学到后面还是得上书本. Duolingo 只是非常基础非常基础的东西,让你开口, 仅此而已. 真要系统学习还是得上书本.
  • 电池健康管理 : 无了, 已从电池厂离职

今年的目标

嗯…又多了一些爱好

  1. 英语: 老生常谈了, 不赘述
  2. 日语: 努力学习, 以后可以看看日本的机会
  3. 工资: 努力提高到 3 开头吧, 大概率是实现不了
  4. 创业: 准备看看有没有什么项目了, 拿点钱来做点事情, 预计会上独立站/阿里国际站, 还在计划中.
  5. 结婚: 运气好的话, 应该可以搞定吧
  6. 旅游: 或许能上一次高原呢?

Node.js is built on Google’s V8 engine, and V8’s garbage collection mechanism is one of its core performance features. In this article, we’ll explore the three primary garbage collection algorithms used in V8: Mark-Sweep, Mark-Compact, and Scavenge, along with their working principles and application scenarios.

V8’s Memory Partition Model

Before diving into garbage collection algorithms, we need to understand V8’s memory partition model. V8 divides memory into two main regions:

Young Generation

  • Contains objects with short lifespans.
  • Typically small in size (e.g., a few MB).
  • Uses the Scavenge algorithm for garbage collection.

Old Generation

  • Contains objects with longer lifespans.
  • Typically larger in size (e.g., hundreds of MB).
  • Uses the Mark-Sweep and Mark-Compact algorithms for garbage collection.
Read more »

Boosting Flutter Performance with Frame-Based Rendering using keframe

Flutter is known for its smooth UI performance, but complex animations or frequent rebuilds can sometimes lead to jank. Frame-based rendering, also known as keyframe animation, offers a powerful technique to optimize these scenarios. This article explores how to leverage frame-based rendering in Flutter using the keframe package, focusing on FrameAnimation, FrameSeparateWidget, and SizeCacheWidget.

What is Frame-Based Rendering?

Traditional rendering in Flutter often involves rebuilding widgets every time their properties change. While efficient in many cases, this can become a bottleneck when dealing with intricate animations or rapidly changing data.

Frame-based rendering pre-calculates animation frames and stores them. During animation, the system displays these pre-rendered frames sequentially, minimizing constant rebuilds. This results in smoother animations and improved performance, especially on less powerful devices.

Read more »

Flutter web 在 iOS 18.2 版本上只能用两指滑动滚动

issue 地址: [iOS 18.2][Web] Scrolling is broken in browsers (Safari, Chrome)

flutter 版本为 3.25.x, 低于 iOS 18.2 的设备上, 可以单指滚动

原因

Safari 在 iOS 18.2 添加了 getCoalescedEvents()支持, 这个方法用于合并多个 touch 事件,有助于提高性能.
但是 api 是不完整的(与其他浏览器内核实现不符, 缺少了 pointerId 和 target 等返回值), 在 flutter 3.27.1 修改了 binding 部分的内容, 用于兼容: [web] Work around wrong pointerId in coalesced events in iOS Safari 18.2

解决方案

把 flutter 升级到 3.27.1 版本, 或者使用 flutter channel dev 切换到 dev 分支, 然后 flutter upgrade 升级到最新 beta 版本.
也可以将 pr 合并到本地 flutter engine, 直接构建 flutter web 项目.

Flutter anti-aliasing(抗锯齿) bug

问题描述

项目里有一段弧形曲线, 我选择用 Row + Expanded + Container 堆叠的方式实现,但是出现了一些很奇怪的hairline border现象.

Flutter anti-aliasing bug

原因

每个 Wrap 之间没有进行像素对齐, 重复渲染的地方导致了混色(颜色加深), 形成了hairline borderissue.

所以相同颜色,尽量避免分块去渲染,会导致抗锯齿效果不佳.

解决方案

  1. 根据更具体的像素比,去渲染对应的大小. 但是这种方法只适用于 width 和 height 都是明确的情况下, 我们通过像素比去控制实际渲染的大小尽量贴近于整数.
  2. 直接使用 custom paint 进行整体绘制. 这种方法可以避免 Wrap 之间像素对齐, 也能保证整体的抗锯齿效果.

我使用的是第二种方法, 效果如图:
Flutter anti-aliasing solution

Read more »

在 Flutter 中,AppBar 是一个重要的组件,通常用于显示应用程序的标题、导航按钮、操作菜单等。随着用户界面设计的发展,滚动效果在移动应用中变得越来越常见。scrolledUnderElevation 属性正是为了解决当页面滚动时,AppBar 的阴影效果的控制需求。

比如你使用了某个滚动组件,然后发现了为什么滚动的时候我的 AppBar 变色了呢?
这就是原因: scrolledUnderElevation 属性。

什么是 scrolledUnderElevation?

scrolledUnderElevation 是 Flutter 3.0 引入的 AppBar 属性之一。它用于设置当 AppBar 位于滚动内容顶部且内容向下滚动时的 阴影高度。简单来说,当页面向下滚动且 AppBar 覆盖部分内容时,该属性决定了 AppBar 的阴影深度。

使用场景

在用户滚动列表或长内容时,我们通常希望 AppBar 在不同的滚动状态下显示不同的视觉效果。例如:

  • 初始状态(未滚动): AppBar 通常是透明的或没有阴影。
  • 滚动状态: 当用户滚动页面并向下查看内容时,AppBar 应该带有一定的阴影,以显示它在内容之上的层次感。

这种设计可以改善用户体验,使界面更清晰且具有层次感。

Read more »

在使用 Android dev 开发 flutter 应用时,控制台会输出 GPU debug 日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[+1001 ms] D/EGL_emulation( 9434): app_time_stats: avg=1001.31ms min=1001.31ms max=1001.31ms count=1
[+1989 ms] D/EGL_emulation( 9434): app_time_stats: avg=994.95ms min=992.16ms max=997.75ms count=2
[+1996 ms] D/EGL_emulation( 9434): app_time_stats: avg=998.40ms min=994.74ms max=1002.06ms count=2
[+2005 ms] D/EGL_emulation( 9434): app_time_stats: avg=1002.85ms min=990.68ms max=1015.03ms count=2
[+1983 ms] D/EGL_emulation( 9434): app_time_stats: avg=991.95ms min=987.00ms max=996.89ms count=2
[+1016 ms] D/EGL_emulation( 9434): app_time_stats: avg=1015.37ms min=1015.37ms max=1015.37ms count=1
[+1002 ms] D/EGL_emulation( 9434): app_time_stats: avg=1002.23ms min=1002.23ms max=1002.23ms count=1
[+1002 ms] D/EGL_emulation( 9434): app_time_stats: avg=1003.33ms min=1003.33ms max=1003.33ms count=1
[+1008 ms] D/EGL_emulation( 9434): app_time_stats: avg=1005.76ms min=1005.76ms max=1005.76ms count=1
[+1997 ms] D/EGL_emulation( 9434): app_time_stats: avg=999.30ms min=994.23ms max=1004.37ms count=2
[+1998 ms] D/EGL_emulation( 9434): app_time_stats: avg=998.66ms min=998.60ms max=998.71ms count=2
[+2000 ms] D/EGL_emulation( 9434): app_time_stats: avg=1000.03ms min=998.15ms max=1001.91ms count=2
[+1998 ms] D/EGL_emulation( 9434): app_time_stats: avg=999.53ms min=999.27ms max=999.79ms count=2
[+1990 ms] D/EGL_emulation( 9434): app_time_stats: avg=995.32ms min=993.38ms max=997.25ms count=2
[+1001 ms] D/EGL_emulation( 9434): app_time_stats: avg=1001.47ms min=1001.47ms max=1001.47ms count=1
[+1001 ms] D/EGL_emulation( 9434): app_time_stats: avg=1001.27ms min=1001.27ms max=1001.27ms count=1
[+1004 ms] D/EGL_emulation( 9434): app_time_stats: avg=1004.90ms min=1004.90ms max=1004.90ms count=1
[+1005 ms] D/EGL_emulation( 9434): app_time_stats: avg=1005.88ms min=1005.88ms max=1005.88ms count=1
[+1979 ms] D/EGL_emulation( 9434): app_time_stats: avg=989.67ms min=979.52ms max=999.82ms count=2

这些日志并不影响应用的运行,但是会占用控制台的空间,可以通过以下方式忽略掉:

1
flutter run --dart-define=ENV=dev --verbose | grep -v "EGL_emulation"

效果如下:

  • 分为三部分,上部,中部,下部。
  • 上部为 header 部分,不吸顶。
  • 中部吸顶。
  • 下部为 SubPages 部分,可以左右滑动切换页面子页面。
Read more »