Flutter笔记:发布一个模块 scale_design - (移动端)设计师尺寸适配工具

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. 概述

这次做的 scale_design 模块旨在解决移动端适配方面的问题。需要指出的是,Flutter是一个跨平台的框架,它不仅仅把目光放在移动端,因此如果你考虑的是桌面端和 Web 开发,那么这个模块目前不适合你。

移动端上,由于屏幕小、屏幕尺寸固定的,他有一个特点是,整个页面的应用窗口即屏幕,一经初始化则大小为定值——不会像PC应用那样,

2. UI设计规范(以Android为例)

2.1 逻辑分辨率与单位

在Android中,与屏幕相关的两个重要概念是逻辑分辨率和单位。逻辑分辨率是您在应用程序中使用的虚拟分辨率,以确保应用在不同设备上具有一致的外观。为了实现这一目标,Android引入了两个主要单位:dpsp。接下来,分别介绍。

在这里插入图片描述

2.1.1 dp(密度独立像素)

dp 是用于非文字元素的长度单位。它的关键特点是,它是一个与屏幕密度相关的单位。在屏幕像素密度为160dpi的情况下,1dp等于1px。然而,在更高或更低的屏幕密度下,1dp的实际像素数会有所不同。这使得在不同设备上相同的dp大小的元素看起来差不多。因此,使用dp可以确保元素的大小在不同屏幕上具有一致性。

2.1.2 sp(尺寸独立像素)

sp 是用于文字大小的单位。它类似于dp,但具有一个特殊的特性,即允许用户在设备上调整字体大小,而不会影响其他元素的大小。这对于用户可访问性和个性化设置非常重要。

2.2 屏幕密度与单位之间的关系

屏幕密度通常以 dpi (每英寸点数)为单位表示。它描述了在每英寸长度内的像素数,即像素密度。这与dp和px之间的关系密切相关。以下是一些常见的屏幕密度版本以及它们的dp和px之间的转换关系:

屏幕密度版本DPIdp与px的比例
ldpi(低屏幕密度)1201dp = 0.75px
mdpi(中等屏幕密度)1601dp = 1px
hdpi(高屏幕密度)2401dp = 1.5px
xhdpi(超高屏幕密度)3201dp = 2px
xxhdpi(超超高屏幕密度)4801dp = 3px
xxxhdpi(超超超高屏幕密度)6401dp = 4px

了解不同屏幕密度版本的转换关系可以帮助开发者在应用程序中创建适应不同设备的元素。这对于确保用户体验的一致性至关重要,无论用户使用的是低密度还是高密度屏幕。这也有助于开发者更好地理解Android系统中的长度单位和分辨率的概念,以便更好地开发和设计应用。

3. UI适配的需求背景

为了解决不同屏幕尺寸和密度带来的UI适配问题,需要一种适配方案。提出方案面临的背景是:

移动应用在不同设备上运行,这些设备具有各种不同的屏幕尺寸和像素密度。如果开发者不考虑这些因素,应用可能会在某些设备上看起来不协调或缺乏一致性。

解决这个问题的关键点是使用 逻辑像素单位(dp) 来测量和布局UI元素。

原因很简单:

  • 由于逻辑像素是与屏幕密度无关的单位,因此它们可以确保在不同设备上,相同的dp大小的元素看起来差不多。

为了实现这一思想,需要完成了步骤:

  1. 定义一个基准的设计尺寸,通常由设计师确定,作为UI元素的标准大小。

  2. 使用比例计算,将设计中的尺寸值除以基准设计尺寸,然后乘以当前设备的屏幕尺寸,以获得在当前设备上的适当尺寸。

  3. 提供辅助函数,如 scaleHeightscaleWidthscaleFont等函数,以简化比例计算的过程,使开发者能够轻松地创建响应式布局。

其中, 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

perWidthperHeight 是两个函数,用于处理屏幕尺寸适配,具体功能如下:

  1. perWidth 函数:

    • perWidth 用于获取屏幕宽度的 1/n 部分,其中 n 是传入的参数。
    • 它接受一个 n 参数,表示要获取屏幕宽度的多少分之一,例如 n 为 2 时,表示获取屏幕宽度的一半。
    • 如果 n 大于 0,函数将返回屏幕宽度除以 n 的结果;否则,会抛出异常。
    • 这个函数通常用于根据屏幕宽度的比例来设置 UI 元素的宽度,以实现屏幕尺寸适配。
  2. perHeight 函数:

    • perHeight 用于获取屏幕高度的 1/n 部分,其中 n 是传入的参数。
    • 它接受一个 n 参数,表示要获取屏幕高度的多少分之一,例如 n 为 3 时,表示获取屏幕高度的三分之一。
    • 如果 n 大于 0,函数将返回屏幕高度除以 n 的结果;否则,会抛出异常。
    • 类似于 perWidthperHeight 主要用于根据屏幕高度的比例来设置 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值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/181601.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

容器核心技术-Namespace

一、容器 基于Linux 内核的 Cgroup&#xff0c; Namespace&#xff0c;以及Union FS等技术&#xff0c;对进程进行封装隔离&#xff0c;属于操作系统层面的虚拟化技术&#xff0c;由于隔离的进程独立于宿主和其它的隔离的进程&#xff0c;因此也称其为容器。 1.1 容器主要特性…

中国电子学会主办 第四届ATEC科技精英赛报名启动

11月1日由中国电子学会主办的第四届ATEC科技精英赛&#xff08;ATEC2023&#xff09;正式启动报名。 ATEC科技精英赛是主要面向中国籍计算机等专业在校学生、人工智能及网络安全行业研究者和从业者的一场高水平的智能科技挑战赛&#xff0c;意在贯彻落实党中央、国务院关于推动…

性能优化之懒加载 - 基于观察者模式和单例模式的实现

一、引入 在前端性能优化中&#xff0c;关于图片/视频等内容的懒加载一直都是优化利器。当用户看到对应的视图模块时&#xff0c;才去请求加载对应的图像。 原理也很简单&#xff0c;通过浏览器提供的 IntersectionObserver - Web API 接口参考 | MDN (mozilla.org)&#xff0c…

SpringSecurity全家桶 (二) ——实现原理

1. SpringSecurity的强大之处 当我们并未设置登录页面时&#xff0c;我们只需要导入SpringSecurity的依赖就可以令我们的界面进入保护状态&#xff0c;由下面例子可以凸显出&#xff1a; 随便写个接口 RequestMapping("/hello")public String hello(){return "H…

旧手机搭建linuxcentos

centos服务器搭建termux搭建centos旧手机搭建linux服务器ubuntu旧手机搭建网站旧手机搭建linux debian ubuntu centos 旧手机搭建宝塔搭建 32位Linux搭建宝塔 Linuxdeploy搭建宝塔 旧手机搭建服务器有需要的来 包答疑包售后 Linuxdeploy需要root mobile搭建服务器 脚本/工具

03 矩阵与线性变换

矩阵与线性变换 线性变换如何用数值描述线性变换特殊的线性变换反过来看总结 这是关于3Blue1Brown "线性代数的本质"的学习笔记。 线性变换 如果一个变换具有以下两个性质&#xff0c;我们就称它是线性的&#xff1a; 一是直线在变换后仍然保持为直线二是原点必须…

网安新旅程

网安新旅程 将近四个月没发博客了&#xff0c;今天交代一下最近发生的事情和规划。 TryHackMyOffsecBox QQ交流 君羊&#xff1a;751273347 近期的事情 6月开始我进入htb学院学习CPTS&#xff0c;7月左右我完成了95%左右的内容。7-8月份我基本都在做C#相关的开发&#xff0c…

【KVM】KVM介绍及功能概述

前言 大家好&#xff0c;我是秋意零。 今天介绍的内容是KVM的概述&#xff0c;以及它所支持的基本功能。 &#x1f47f; 简介 &#x1f3e0; 个人主页&#xff1a; 秋意零&#x1f525; 账号&#xff1a;全平台同名&#xff0c; 秋意零 账号创作者、 云社区 创建者&#x1f…

NTFS文件系统解析(三)

1、引言 对于NTFS文件系统而言&#xff0c;无论文件内容本身&#xff0c;抑或真实的文件属性&#xff0c;都被称之为属性。 而正如前文说到的&#xff0c;NTFS预定义了16种属性用于文件系统的管理。 而通常情况下&#xff0c;往往只需要关注其中的某些属性即可。 2、属性头 …

【AI】Stable-Diffusion-WebUI使用指南

注&#xff1a;csdn对图片有审核&#xff0c;审核还很奇葩&#xff0c;线稿都能违规&#xff0c;为保证完整的阅读体验建议移步至个人博客阅读 最近AI绘画实现了真人照片级绘画水准&#xff0c;导致AI绘画大火&#xff0c;公司也让我研究研究&#xff0c;借此机会正好了解一下…

一个JS版寻路的实现

js版的寻路的测试 20231104_161146 path get_v8: function (x_inc, y_inc) {if (x_inc 0) {if (y_inc < 0) {return [[0, -1], [-1, -1], [1, -1], [-1, 0], [1, 0], [-1, 1], [1, 1], [0, 1]];} else if (y_inc > 0) {return [[0, 1], [-1, 1], [1, 1], [-1, 0], [1, 0…

090基于web+springboot的中小企业设备管理系统

欢迎大家关注&#xff0c;一起好好学习&#xff0c;天天向上 文章目录 一项目简介技术介绍 二、功能组成三、效果图四、 文章目录 一项目简介 本中小企业设备管理系统管理员有个人中心&#xff0c;用户管理&#xff0c;员工管理&#xff0c;设备信息管理&#xff0c;配件信息管…

c++类和对象(八) static成员 友元

1.1 概念 声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff1b;用static修饰的成员函数&#xff0c;称之为静态成员函数。静态成员变量一定要在类外进行初始化。 面试题&#xff1a;实现一个类&#xff0c;计算…

【深度学习】pytorch——快速入门

笔记为自我总结整理的学习笔记&#xff0c;若有错误欢迎指出哟~ pytorch快速入门 简介张量&#xff08;Tensor&#xff09;操作创建张量向量拷贝张量维度张量加法函数名后面带下划线 _ 的函数索引和切片Tensor和Numpy的数组之间的转换张量&#xff08;tensor&#xff09;与标量…

2.10 CSS BFC

1.简介 BFC是Block Formatting Context(块级格式上下文)&#xff0c;可以理解成元素的一个“特异功能”。该“特异功能”&#xff0c;在默认的情况下处于关闭状态;当元素满足了某些条件后&#xff0c;该"特异功能被激活。所谓激活"特异功能”&#xff0c;专业点说就…

【KVM】软件虚拟化和硬件虚拟化类型

前言 大家好&#xff0c;我是秋意零。 今天介绍的内容是虚拟化技术以及软件虚拟化和硬件虚拟化。 &#x1f47f; 简介 &#x1f3e0; 个人主页&#xff1a; 秋意零&#x1f525; 账号&#xff1a;全平台同名&#xff0c; 秋意零 账号创作者、 云社区 创建者&#x1f9d1; 个…

Leetcode—187.重复的DNA序列【中等】

2023每日刷题&#xff08;二十&#xff09; Leetcode—187.重复的DNA序列 实现代码 class Solution { public:const int L 10;vector<string> findRepeatedDnaSequences(string s) {unordered_map<string, int> str;vector<string> ans;int len s.size()…

【市场分析】Temu数据采集销售额商品量占比分析数据分析接口Api

引言 temu电商平台是一个充满活力的电商平台&#xff0c;拥有多种商品类别和数万家店铺。在这个项目中我的任务是采集平台上的大量公开数据信息。通过数据采集&#xff0c;我旨在深入了解temu电商平台的产品分布、销售趋势和文本描述&#xff0c;以揭示有趣的见解。 数据采集…

PyQuery库写一个有趣的爬虫程序

PyQuery库是一个基于jQuery语法的Python库&#xff0c;它可以方便地对HTML/XML文档进行解析和操作。使用PyQuery库可以快速地获取网页中的数据&#xff0c;进行数据清洗和分析。PyQuery库的基本用法包括字符串初始化、打开网页、css属性、标签内容等获取、DOM基本操作等相关技巧…