Live Note

Remain optimistic

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 »

What is OpenID?

OpenID 是一种用于标识用户身份的协议,它允许用户在多个网站上使用同一个用户名和密码。它是由一组标准定义的,包括一个身份提供者(IdP)和一个身份验证服务(AS)。IdP 是网站或服务,它提供用户的身份信息,并将其发送给 AS。AS 是另一个网站或服务,它验证 IdP 发送的身份信息,并确认用户的身份。

OpenID 工作流程

  1. 用户选择 OpenID 提供商: 比如 Google/Tencent 或其他支持 OpenID 的服务来管理他们的身份。
  2. 用户访问应用网站,点击登录按钮。
  3. 重定向到 OpenID 提供商,验证用户身份。
  4. 用户认证成功后,OpenID 提供商将用户信息发送给应用网站。
  5. 应用网站验证用户信息,确认用户身份。
  6. 应用网站允许用户访问受保护的资源。
Read more »

什么是 Basic Authentication?

Basic Authentication 是一种 HTTP 协议的认证方式,它使用用户名和密码对客户端进行身份验证。
RFC 2617 定义了 Basic Authentication 协议,它规定了客户端如何向服务器发送请求,以及服务器如何验证用户名和密码。
当用户试图访问受保护的资源时,服务器会判断 HTTP Header 中的 Authorization 字段是否包含有效的 Basic Authentication 认证信息。如果没有,服务器会返回 401 Unauthorized 状态码,要求客户端提供认证信息,并在响应头中添加 WWW-Authenticate: Basic 字段。

Read more »

什么是 JWT?

JWT(JSON Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间安全地传输信息。该信息可以是声明(claim)、有效期、签名或密钥。JWT 可以使用 HMAC 算法或 RSA 算法进行签名。

JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。

可以看出,JWT 更符合设计 RESTful API 时的「Stateless(无状态)」原则 。

Read more »

Time Picker Pnl in React Native

Why i write this component?
First, I found a lib called @react-native community/picker and wrote my code based on it. When I was done, it worked fine in ios, but when I turned on my android. Oh, my God, it’s not working. This component is platform based. It behaves differently on different platforms.

Then I found another library called react-native-picker, but it was too ugly and not customizable. My UI designer wouldn’t let me use this kind of thing, so I wrote my own component.

Note: This component is not perfect, but it works fine in my work. If you have any suggestion or issue, please let me know. You can build your own component based on this code.
If this code help you, please follow me on Github. XD(am greedy)

Requirements:

  • react-native-modal: pop up modal for time picker

Time Picker Pnl

Read more »

Why is this error occurring?

The ERR_OSSL_EVP_UNSUPPORTED error in a React JS application typically arises due to an underlying issue with the version of Node.js and OpenSSL being used. This error is commonly encountered when certain cryptographic algorithms or keys are not supported by the OpenSSL version bundled with the Node.js installation.

How can I fix this error?

Node.js 17 has a new option called –openssl-legacy-provider. This option lets you go back to using the old way of doing things until you can update your code to work with the new rules.

package.json file

package.json
1
2
3
4
5
{
"scripts": {
"start": "node --openssl-legacy-provider index.js"
}
}

set environment variable

1
export NODE_OPTIONS=--openssl-legacy-provider

change it in the gradle file

build.gradle
1
2
3
project.ext.react = [
nodeExecutableAndArgs: ["node", "--openssl-legacy-provider"]
]

change it in the Xcode build settings

project.pbxproj
1
2
3
buildSettings = {
NODE_OPTIONS = "--openssl-legacy-provider";
}

After changes, try running the application again. Or you also need to reinstall the dependencies.