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值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Xilinx DDR3 MIG系列——内存基本概念及原理

本节目录 一、内存简介 (1)内存基本存储原理 (2)内存频率 (3)DDR数据预取技术(Prefetch) (4)DDR3工作流程 (5)DDR3控制器的特点 二、内存基本参数 (1)物理Bank (2)逻辑Bank (3)内存芯片容量 (4)行激活命令—tRCD (5)列选通—CL (6)写入延迟—tDQSS (7)行预充电有效周期—tRP (8…

第十三章 Python操作数据库

系列文章目录 第一章 Python 基础知识 第二章 python 字符串处理 第三章 python 数据类型 第四章 python 运算符与流程控制 第五章 python 文件操作 第六章 python 函数 第七章 python 常用内建函数 第八章 python 类(面向对象编程) 第九章 python 异常处理 第十章 python 自定…

『亚马逊云科技产品测评』活动征文|如何搭建低成本亚马逊aws云服务器

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 0. 环境 win10 火狐浏览器 1. 登录 https://aws.amazon.com/cn/ ->…

渗透测试学习day2

文章目录 连接靶机靶机&#xff1a;Fawn 解题过程Task 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9Task 10Task 11Task 12 总结 连接靶机 详细过程可参考day1 靶机&#xff1a;Fawn 难度&#xff1a;very easy &#xff08;ftp服务的靶机&#xff09; 解题过程 T…

2023/11/7 JAVA学习

ctrl alt t自动重写

linux C++实现线程绑定CPU

前言 嵌入式里面我们会使用到多核的cpu&#xff0c;随着产品芯片性能提升&#xff0c;我们也会有很多功能&#xff0c;以及很多进程产生运行&#xff0c;这个时候我们在任务调度调优的时候&#xff0c;把一些进程绑定到固定cpu运行&#xff0c;下面就来分享一下cpu绑定运行的过…

我在Vscode学OpenCV 图像运算(权重、逻辑运算、掩码、位分解、数字水印)

文章目录 权重 _ 要求两幅图像是相同大小的。[ 1 ] 以数据说话&#xff08; 1&#xff09; 最终&#xff1a;&#xff08; 2 &#xff09;gamma _输出图像的标量值 [ 2 ] 图像的展现力gamma并不等同于增加曝光度&#xff08; 1 &#xff09;gamma100&#xff08; 2 &#xff09…

怎么学编程效率高,编程练习网站编程软件下载,中文编程开发语言工具下载

怎么学编程效率高&#xff0c;编程练习网站编程软件下载&#xff0c;中文编程开发语言工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的…

viple入门(五)

&#xff08;1&#xff09;自定义活动 自定义活动&#xff0c;用来创建新的组件、服务、函数或者其他代码模块&#xff0c;使用最多的是创建函数。 函数是对一个功能的封装&#xff0c;在调用的时候执行&#xff0c;没有调用的时候则不执行。函数可能有参数&#xff0c;可能没…

字符函数和字符串函数详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 1. 字符分类函数 2. 字符转换函数 3. strlen的使用和模拟实现 3.1strlen的使用&#xff1a; 3.2strlen的模拟实现&#xff1a; 4. strcpy的使用和模拟实现 4.1strc…

Ionic 模块组件的理解

1 Ionic4.x 文件分析 1.1 app.module.ts 分析 Ionic 是一个基于 Angular 的移动应用开发框架&#xff0c;能帮助开发者使用 Web 技术&#xff08;HTML5、CSS3、JavaScript&#xff09;创建跨平台的应用程序。在 Ionic 应用程序中&#xff0c;app.module.ts 文件是整个应用程序的…

【GitHub】Watch、Star、Fork、Follow 有什么区别?

目录 一、前言二、区别1. Watch2. Star3. Fork4. Follow 一、前言 GitHub 是最受欢迎的代码托管平台之一&#xff0c;拥有大量的开源代码可供学习。 Github 中也有类似 “点赞”、“收藏”、“加关注” 的功能。 下面介绍下&#xff0c;GitHub 中 Watch、Star、Fork、Follow 有…

Seata分布式事务实现原理

Seata可以解决分布式事务问题&#xff0c;利用GlobalTransacational(name "fsp-create-order",rollbackFor Exception.class)注解就可以实现全局的事务管理&#xff0c;但是我们需要明白原理的实现。 我们举例创建订单——>调减库存——>调扣余额——>改订…

配置阿里云镜像加速器 -docker

1.百度aliyun 2.找到镜像服务ACR 3.搞一个个人版&#xff0c;身份验证一下就行了很简单 4.找到镜像加速器Centos 5.执行下面4条命令&#xff1a;4条命令直接从上面操作文档中粘贴&#xff0c;不容易出错 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<…

折叠旗舰新战局:华为先行,OPPO接棒

乌云中的曙光&#xff0c;总能带给人希望。 全球智能手机出货量已经连续八个季度下滑&#xff0c;行业里的乌云挥之不散。不过&#xff0c;也能看到高端市场逆势上涨&#xff0c;散发光亮。个中逻辑在于&#xff0c;当前换机周期已经达到了34个月&#xff0c;只有创新产品才能…

xray:漏洞扫描利器

简介 长亭科技旗下的一款网络安全漏洞扫描工具&#xff0c;用于检测和评估web应用程序的安全性。具有一下特点&#xff1a;检测速读快、检查范围广、代码质量高、高级可定制以及安全无危害。属于不开源的项目&#xff0c;用户直接下载xray的可执行文件&#xff0c;即可运行该工…

【Linux系统】文件 / 文件夹权限:chmod

文件 / 文件夹权限&#xff1a;chmod 1.介绍 chmod 命令用于改变文件或目录的访问权限。 改变文件权限 chmod 777 xxx.txt改变文件夹下所有文件的权限 chmod -R 777 *-R 是递归遍历子目录&#xff0c;* 通配符代表要操作的文件。 777 777 777 有 3 3 3 位&#xff0c;最高…

设计模式之保护性暂停

文章目录 1. 定义2. 实现保护性暂停模式3. Join原理4. 保护性暂停模式的扩展 1. 定义 即Guarded Suspension&#xff0c;用在一个线程等待另一个线程的执行结果。 有一个结果需要从一个线程传递给另一个线程&#xff0c;让他们关联到同一个GuarderObject&#xff08;这就是保…

Chromebook文件夹应用新功能

种种迹象表明 Google 旗下的 Chromebooks 近期要有大动作了。根据 Google 团队成员透露&#xff0c;公司计划在 Chrome OS 的资源管理器中新增“Recents”&#xff08;最近使用&#xff09;文件&#xff0c;以便于用户更快找到所需要的文件。 种种迹象表明 Google 旗下的 Chro…

Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较

Flutter vs 前端 杂谈 SliverAppBar的弹性背景的显隐效果使用HtmlJS怎么实现 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550…