Flutter笔记:发布一个模块 scale_design - (移动端)设计师尺寸适配工具
设计师尺寸适配工具与常用组件库
作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/134210226
模块地址:https://pub.dev/packages/scale_design
仓库地址:https://github.com/jacklee1995/flutter_scale_design
目 录
- 1. 概述
- 2. UI设计规范(以Android为例)
- 3. UI适配的需求背景
- 4. scale_design 的安装和初始化
- 5. 字体尺寸适配方案
- 6. 在项目中调用工具函数
- scaleWidth 和 scaleHeight
- perWidth 和 perHeight
- scaleFont
- 7. 对原生Flutter组件的包装
1. 概述
这次做的 scale_design 模块旨在解决移动端适配方面的问题。需要指出的是,Flutter是一个跨平台的框架,它不仅仅把目光放在移动端,因此如果你考虑的是桌面端和 Web 开发,那么这个模块目前不适合你。
移动端上,由于屏幕小、屏幕尺寸固定的,他有一个特点是,整个页面的应用窗口即屏幕,一经初始化则大小为定值——不会像PC应用那样,
2. UI设计规范(以Android为例)
2.1 逻辑分辨率与单位
在Android中,与屏幕相关的两个重要概念是逻辑分辨率和单位。逻辑分辨率是您在应用程序中使用的虚拟分辨率,以确保应用在不同设备上具有一致的外观。为了实现这一目标,Android引入了两个主要单位:dp 和 sp。接下来,分别介绍。
2.1.1 dp(密度独立像素)
dp 是用于非文字元素的长度单位。它的关键特点是,它是一个与屏幕密度相关的单位。在屏幕像素密度为160dpi的情况下,1dp等于1px。然而,在更高或更低的屏幕密度下,1dp的实际像素数会有所不同。这使得在不同设备上相同的dp大小的元素看起来差不多。因此,使用dp可以确保元素的大小在不同屏幕上具有一致性。
2.1.2 sp(尺寸独立像素)
sp 是用于文字大小的单位。它类似于dp,但具有一个特殊的特性,即允许用户在设备上调整字体大小,而不会影响其他元素的大小。这对于用户可访问性和个性化设置非常重要。
2.2 屏幕密度与单位之间的关系
屏幕密度通常以 dpi (每英寸点数)为单位表示。它描述了在每英寸长度内的像素数,即像素密度。这与dp和px之间的关系密切相关。以下是一些常见的屏幕密度版本以及它们的dp和px之间的转换关系:
屏幕密度版本 | DPI | dp与px的比例 |
---|---|---|
ldpi(低屏幕密度) | 120 | 1dp = 0.75px |
mdpi(中等屏幕密度) | 160 | 1dp = 1px |
hdpi(高屏幕密度) | 240 | 1dp = 1.5px |
xhdpi(超高屏幕密度) | 320 | 1dp = 2px |
xxhdpi(超超高屏幕密度) | 480 | 1dp = 3px |
xxxhdpi(超超超高屏幕密度) | 640 | 1dp = 4px |
了解不同屏幕密度版本的转换关系可以帮助开发者在应用程序中创建适应不同设备的元素。这对于确保用户体验的一致性至关重要,无论用户使用的是低密度还是高密度屏幕。这也有助于开发者更好地理解Android系统中的长度单位和分辨率的概念,以便更好地开发和设计应用。
3. UI适配的需求背景
为了解决不同屏幕尺寸和密度带来的UI适配问题,需要一种适配方案。提出方案面临的背景是:
移动应用在不同设备上运行,这些设备具有各种不同的屏幕尺寸和像素密度。如果开发者不考虑这些因素,应用可能会在某些设备上看起来不协调或缺乏一致性。
解决这个问题的关键点是使用 逻辑像素单位(dp) 来测量和布局UI元素。
原因很简单:
- 由于逻辑像素是与屏幕密度无关的单位,因此它们可以确保在不同设备上,相同的dp大小的元素看起来差不多。
为了实现这一思想,需要完成了步骤:
-
定义一个基准的设计尺寸,通常由设计师确定,作为UI元素的标准大小。
-
使用比例计算,将设计中的尺寸值除以基准设计尺寸,然后乘以当前设备的屏幕尺寸,以获得在当前设备上的适当尺寸。
-
提供辅助函数,如
scaleHeight
、scaleWidth
、scaleFont
等函数,以简化比例计算的过程,使开发者能够轻松地创建响应式布局。
其中,
scaleHeight
等函数包含在 scale_design 库中。(scaleHeight、scaleWidth和scaleFont 等函数是基于逻辑像素单位(dp)进行计算的)
这里思想的核心目标是实现UI元素的一致性,无论用户使用的是小屏幕还是大屏幕,低分辨率还是高分辨率的设备。它旨在解决跨设备UI适配的挑战,以提供更好的用户体验。
4. scale_design 的安装和初始化
4.1 scale_design 的安装
运行以下命令:
flutter pub add scale_design
这将向你的包的 pubspec.yaml 配置文件依赖字段中添加一行scale_design的记录,并运行一个隐式的flutter pub get,版本默认为当前最新版本。
4.2 scale_design 的初始化
要在项目中正确使用 scale_design
,需要在项目启动之初获取屏幕的基本信息,即初始化。
可以在应用返回跟组件前调用静态初始化方法,比如最简单的情况:
import 'package:flutter/material.dart';
import 'package:flutter_scale/flutter_scale.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {// 用首选的标准屏幕尺寸初始化Scale类// 这个标准屏幕尺寸一般由设计师(美工)给Scale().init(context, standardWidth, standardHeight);return MaterialApp(// ...);}
}
很多实际项目,你希望将项目的一些配置全部写在同一个配置文件中,在 mian.dart 写一个初始化函数进行各种初始化操作。就比如在配置文件中:
class LayoutConfigs {static double standardWidth = 812.0;static double standardHeight = 375.0;
}
import 'package:flutter/material.dart';
import 'package:scale_design/scale_design.dart';
import 'app/config.dart'; // 导入你的配置文件void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});// 初始化方法Future<void> initialization(BuildContext context) async {// 初始化屏幕尺寸比例缩放Scale().init(context,LayoutConfigs.standardWidth,LayoutConfigs.standardHeight,);}Widget build(BuildContext context) {return MaterialApp(theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),useMaterial3: true,),home: FutureBuilder(future: initialization(context),builder: (context, snapshot) {return const MyHomePage(title: 'Scale Design Demo',);},),);}
}class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;State<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(),body: ...),);}
}
5. 字体尺寸适配方案
字体尺寸适配的关键目标是在不同的设备和屏幕尺寸下提供
“一致的用户体验”,即:
确保文本内容既不会过大导致溢出,也不会太小导致难以阅读。
我们这里的具体方案仍然是通过根据屏幕尺寸自动调整字体大小,可以有效应对多样化的移动设备,从小屏幕手机到大屏幕平板电脑。这种字体尺寸适配方案有助于提高用户体验,使应用程序更加灵活和适应不同的使用环境。
但是这个方案如何落实呢?
scale_design 模块的 scaleFont 方法是上述字体尺寸适配方案的具体实现之一。它是一个用于动态计算字体大小的工具,基于屏幕尺寸和设计标准的宽度之间的比例。这个方法的核心思想是将字体大小调整为适应不同屏幕宽度的需求,以保持文本内容的可读性。
具体而言,scaleFont 方法的应用如下:
- 基准字体大小: 开发者首先定义了一个基准字体大小,通常是在设计阶段确定的。这个基准字体大小是文本在设计标准的屏幕上的理想大小。
- 屏幕宽度比例: scaleFont 方法获取当前设备的屏幕宽度和设计标准的宽度之间的比例。这个比例反映了当前屏幕与设计标准的相对大小。
- 动态调整: 使用上述比例,scaleFont 方法将基准字体大小动态调整为适合当前屏幕的字体大小。这确保了文本内容在不同屏幕尺寸下都能够以一致的比例呈现。
事实上,如果屏幕宽度比例为1,意味着当前屏幕的宽度与设计标准的宽度相等,无需进行字体大小的缩放。在这种情况下是以一个特例:
double scaleFont(double fontSize) {return fontSize;
}
scaleFont 方法返回的字体大小将与设计时的大小保持一致,不会进行任何缩放。
然而 scale_design 中考虑到对于一般的情况,是按照上面几个步骤的完整实现:
double scaleFont(double fontSize) {// 获取当前设备的屏幕宽度double screenWidth = Scale.screenWidth;// 获取设计标准的宽度double standardWidth = Scale.standardWidth;// 计算字体大小的比例double scale = screenWidth / standardWidth;// 根据比例调整字体大小return fontSize * scale;
}
即:
double scaleFont(double fontSize) {return Scale.screenWidth Scale.standardWidth/ ;
}
6. 在项目中调用工具函数
scaleWidth 和 scaleHeight
依据设计师的来稿,在项目中有需要用到一般元素的宽高的时候,使用scaleWidth、scaleHeight来实现宽高的dp表示,如:
import 'package:scale_design/scale_design.dart';// ...
scaleWidth(320.0);
scaleHeight(60.0);
perWidth 和 perHeight
perWidth
和 perHeight
是两个函数,用于处理屏幕尺寸适配,具体功能如下:
-
perWidth
函数:perWidth
用于获取屏幕宽度的 1/n 部分,其中n
是传入的参数。- 它接受一个
n
参数,表示要获取屏幕宽度的多少分之一,例如n
为 2 时,表示获取屏幕宽度的一半。 - 如果
n
大于 0,函数将返回屏幕宽度除以n
的结果;否则,会抛出异常。 - 这个函数通常用于根据屏幕宽度的比例来设置 UI 元素的宽度,以实现屏幕尺寸适配。
-
perHeight
函数:perHeight
用于获取屏幕高度的 1/n 部分,其中n
是传入的参数。- 它接受一个
n
参数,表示要获取屏幕高度的多少分之一,例如n
为 3 时,表示获取屏幕高度的三分之一。 - 如果
n
大于 0,函数将返回屏幕高度除以n
的结果;否则,会抛出异常。 - 类似于
perWidth
,perHeight
主要用于根据屏幕高度的比例来设置 UI 元素的高度,以实现屏幕尺寸适配。
这两个函数对于创建响应式布局和动态适应不同屏幕尺寸的应用程序非常有用。开发者可以使用它们来设置 UI 元素的尺寸,以适应不同的设备屏幕,从而提供更好的用户体验。
import 'package:scale_design/scale_design.dart';// ...
perWidth(2); // 屏幕宽度的1/2
perHeight(2); // 屏幕宽度的1/2
scaleFont
scaleFont 函数是用于根据屏幕大小进行字体大小适配的工具。例如:
Text('Hello, World!',style: TextStyle(fontSize: scaleFont(18)),
);
不过,这可以使用使用对应于 Text 组件的 T 组件表示,那将更加简洁(T组件也需要导入该scale design库)。
7. 对原生Flutter组件的包装
包装的目的在于更加简单地使用一些常见地组件,比如 Flutter 中的 ElevatedButton ,在 Scale Design 库中的对应品是 ElevatedBtn,不再需要使用 scaleXXX 这些函数来指定宽高,传入的 double 数值已经在内部做了转换。并且默认情况下,不需要使用 Text来在按钮上实现文字,直接传入字符串默认就是文字,除非你硬性指定 child 属性,这时传入的text不再有效。
一个例子是,我们在项目中可以直接基于 ElevatedBtn 二次封装直接用于特定功能的组件:
import 'package:flutter/material.dart';
import 'package:scale_design/scale_design.dart';class SubmitButton extends StatelessWidget {final String text;final Function()? onPressed;final double width;final double height;final double size;final Color color;const SubmitButton(this.text, {super.key,this.onPressed,this.width = 320.0,this.height = 49.0,this.size = 18.0,this.color = const Color.fromARGB(255, 255, 98, 7),});Widget build(BuildContext context) {return ElevatedBtn(text,onPressed: onPressed,width: width,height: height,fontSize: size,backgroundColor: color,);}
}class IconBtn extends StatelessWidget {final IconData icon;final Function()? onPressed;const IconBtn({super.key, required this.icon, required this.onPressed});Widget build(BuildContext context) {return IconButton(icon: Icon(icon),onPressed: onPressed,iconSize: scaleFont(24), // 调整图标大小);}
}
当然这个 SubmitButton 的 width、height 也是基于 dp 的。然后我们可以将这个按钮用于它适应的具体化场景,比如下面是我一个项目中登陆页面的表单提交:
SubmitButton("继续", onPressed: () async {if (_formKey.currentState!.validate()) {_formKey.currentState!.save();await authService.login().then((String? token) {if (token != '' && LoginViewController.to.remember) {LoginViewController.to.saveLoginInfo(authService.email.value,authService.password.value,);goToMallViewPage(index: 0, type: 'offAll');} else {LoginViewController.to.clearSavedPassword(authService.email.value,);}});}
}
类似的,scale_design 中还有 T 组件,是Text组件的替代,TSpan组件相当于对应的TextSpan组件,等等。不过也不全是这类对于原生的包装,也有一些组件是常见于项目的,但本身并不是基于 dp 封装的,需要使用 scaleXXX 这些函数传入对应的dp值。
相关文章:

Flutter笔记:发布一个模块 scale_design - (移动端)设计师尺寸适配工具
Flutter笔记 发布一个模块scale_design设计师尺寸适配工具与常用组件库 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/a…...
torch增加维度操作
使用none作为占位符 在Python中,None 表示空值或占位符。 在masked_pos[:, :, None]这个切片操作中,None 被用作一个占位符,以改变张量的维度。这通常用于将一维张量变为二维张量,或者改变张量的形状。 具体来说,ma…...

软件测试面试题及答案2024
1、你们的缺陷等级如何划分的?☆☆☆☆☆ 我们的缺陷一般分为四个等级,致命级,严重级,一般级和轻微级。致命级指能够导致软件程序无法使用的缺陷,比如宕机,崩溃,手机APP的闪退,数据…...
C现代方法(第18章)笔记——声明
文章目录 第18章 声明18.1 声明的语法18.2 存储类型18.2.1 变量的性质18.2.2 auto存储类型18.2.3 static存储类型18.2.4 extern存储类型18.2.5 register存储类型18.2.6 函数的存储类型18.2.7 小结 18.3 类型限定符18.4 声明符18.4.1 解释复杂声明18.4.2 使用类型定义来简化声明…...

Spring Data Redis + RabbitMQ - 基于 string + hash 实现缓存,计数(高内聚)
目录 一、Spring Data Redis 1.1、缓存功能(分析) 1.2、案例实现 一、Spring Data Redis 1.1、缓存功能(分析) hash 类型存储缓存相比于 string 类型就有更多的更合适的使用场景. 例如,我有以下这样一个 UserInfo 信息 假设这样一个场景就是:万一只想获取其中某一个…...

【四、http】go的http的文件下载
一、日常下载图片到本地 //下载文件func downloadfile(url, filename string) {r, err : http.Get(url)if err ! nil {fmt.Println("err", err.Error())}defer r.Body.Close()f, err : os.Create(filename)if err ! nil {fmt.Println("err", err.Error())…...

Java web(六):FilterListenerAJAX
文章目录 一、Filter1.1 基本介绍1.2 过滤器的执行流程1.3 拦截路径配置1.4 过滤器链1.5 案例 二、Listener三、AJAX3.1 快速入门3.2 Axios异步框架 四、 JSON4.1 JSON基础语法4.2 Fastjson 五、 案例JSONAxiosServlet Java web的三大组件:Servlet、Filter、Listene…...

初识jQuery
文章目录 一、jQuery介绍二、Jquery优势三、jQuery版本四、jQuery对象jQuery的引用js代码与jQuery代码对比标签对象与jQuery对象 五、jQuery查找标签1.基本选择器2.组合选择器3.层次选择器4.属性选择器5.基本筛选器6.表单筛选器 六、筛选器方法七、操作标签1.class操作2.文本操…...
MATLAB算法实战应用案例精讲-【图像处理】计算机视觉(最终篇)
目录 知识储备 线阵相机调试 1.相机型号参数 2.相机软件安装 3.编码器连接方式 4.采集卡说明...
repo执行出现/usr/bin/env: ‘python’: No such file or directory问题
下载 Repo 工具,并确保它可执行: curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repochmod ax ~/bin/repo 执行 repo version报错: $ repo version /usr/bin/env: ‘python’: No such file or directory查看c…...

算法模板之单调栈解密 | 图文详解
🌈个人主页:聆风吟 🔥系列专栏:算法模板、数据结构 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋前言一. ⛳️单调栈讲解1.1 🔔单调栈的定义1.2 🔔如何维护一个单…...
187.重复的 DNA 序列
题目来源: leetcode题目,网址:187. 重复的DNA序列 - 力扣(LeetCode) 解题思路: 使用两个哈希表,一个存放已遍历过的长度为 10 的字符串,另一个存放重复的长度为 10 的字符串。顺…...

Sentinel黑白名单授权规则解读
目录 基本介绍 代码实战 架构说明 RequestOriginParser的实现类 网关添加请求头 配置授权规则 基本介绍 授权规则可以对请求方来源做判断和控制。 很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源…...
Spring底层原理学习笔记--第二讲--(BeanFactory实现与ApplicaitonContext实现)
BeanFactory实现 package com.lucifer.itheima.a02;import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.fac…...
云原生|kubernetes |kubelet服务加入系统守护进程supervisor(centos7系统下演示通过)
前言: kubelet 是 Kubernetes 集群中的一个重要组件,运行在每个节点上,负责管理该节点上的容器和Pod。它与控制平面(如 API Server 和 kube-controller-manager)通信,确保节点上的容器与期望的状态保持一致…...

onnx 模型加载部署运行方式
1.通过文件路径的onnx模型加载方式: 在onnxruntime下面的主要函数:session Ort::Session(env, w_modelPath.c_str(), sessionOptions); 这里的文件路径是宽字节的,通过onnx文件路径直接加载模型。 在opencv下使用dnn加载onnx模型的主要函数: std::string model…...

第68讲:MySQL触发器的核心概念以及常见的触发类型应用案例
文章目录 1.触发器的概念2.触发器操作的语法结构3.各类触发器的典型应用案例3.1.需求描述以及实现思路3.2.创建日志表3.3.INSERT类型的触发器3.4.UPDATE类型的触发器3.5.DELETE类型的触发器 1.触发器的概念 触发器是与表中数据相关的数据库对象,当表中的数据产生in…...

VS Code 开发 Spring Boot 类型的项目
在VS Code中开发Spring Boot的项目, 可以导入如下的扩展: Spring Boot ToolsSpring InitializrSpring Boot Dashboard 比较建议的方式是安装Spring Boot Extension Pack, 这里面就包含了上面的扩展。 安装方式就是在扩展查找 “Spring Boot…...

数据中心加密:保障数据安全的重要一环
随着信息化的快速发展,数据已经成为企业的重要资产,数据安全也成为了企业面临的重大挑战。数据中心作为企业数据存储和管理的重要场所,其安全性对于整个企业的数据安全具有至关重要的作用。而数据中心加密则是保障数据安全的重要一环。本文将…...

分享90个节日庆典PPT,总有一款适合您
分享90个节日庆典PPT,总有一款适合您 PPT下载链接:百度网盘 请输入提取码 提取码:8888 Python采集代码下载链接:采集代码.zip - 蓝奏云 学习知识费力气,收集整理更不易。知识付费甚欢喜,为咱码农谋福利…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...