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

news2024/11/28 23:54:42
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.coloradmin.cn/o/1168507.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

词向量模型Word2Vec

Word2Vec CBOW连续词袋模型例子CBOW模型的embeddings层CBOW模型的线性层 总结 skip-gram跳字模型例子Skip-Gram模型的结构 CBOW和skip-gram的目标都是迭代出词向量字典&#xff08;嵌入矩阵&#xff09;——embeddings CBOW连续词袋模型 根据上下文词汇预测目标词汇 例子 使…

【FastCAE源码阅读3】几何模型显示:从OCC对象到VTK对象

从几何到显示还是比较麻烦的&#xff0c;需要将几何对象转换成渲染对象&#xff0c;涉及几何建模、面的三角化、图形渲染等学科&#xff0c;阅读本文需了解一些基本的OCC、VTK编程 一、几何体显示基本流程 FastCAE几何内核使用的是OCC&#xff0c;显示渲染用的VTK&#xff0c;…

Leetcode—111.二叉树的最小深度【简单】

2023每日刷题&#xff08;十八&#xff09; Leetcode—111.二叉树的最小深度 DFS实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ int minDepth(struct TreeNode* root…

NCL颜色索引表---全平台可用

NCL颜色索引表—全平台可用

三维向量旋转

三维向量旋转 问题描述问题分析 v ⃗ ∣ ∣ \vec{v}_{||} v ∣∣​的旋转 v ⃗ ⊥ \vec{v}_{\bot} v ⊥​的旋转 v ⃗ \vec{v} v 的旋转结论致谢 问题描述 如图1所示&#xff0c;设一个向量 v ⃗ \vec{v} v 绕另一个向量 u ⃗ [ x , y , z ] T \vec{u}[x,y,z]^{T} u [x,y,z]T…

【电路笔记】-相位差和相移

相位差和相移 文章目录 相位差和相移1、概述2、相位差2.1 同频信号2.2 电流与电压信号2.3 相似频率的信号 3、干扰4、总结 当我们听歌曲时&#xff0c;我们将正弦声音波形感知为音乐。 它们的振幅告诉我们信号有多大&#xff0c;频率告诉我们声音是低音还是高音。 然而&#xf…

vue学习part01

02_Vue简介_哔哩哔哩_bilibili Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org) 1.简介 2.常用用法 新项目一般vue3&#xff0c;老项目vue2 3.vue两种风格&#xff1a;选项式api&#xff08;vue2&#xff09;和组合式api&#xff08;vue3&#xff09; 两种方式实现累…

JS异常处理——throw和try、catch以及debugger

让我为大家介绍一下异常处理吧&#xff01; 异常处理是指预估代码执行过程中可能发生的错误&#xff0c;然后最大程度的避免错误的发生导致整个程序无法继续运行 throw 抛异常 第一种写法 function fun(x, y) {// undefined是false 但取反就是trueif (!x || !y) {// 第一种写…

实习记录--(海量数据如何判重?)--每天都要保持学习状态和专注的状态啊!!!---你的未来值得你去奋斗

海量数据如何判重&#xff1f; 判断一个值是否存在&#xff1f;解决方法&#xff1a; 1.使用哈希表&#xff1a; 可以将数据进行哈希操作&#xff0c;将数据存储在相应的桶中。 查询时&#xff0c;根据哈希值定位到对应的桶&#xff0c;然后在桶内进行查找。这种方法的时间复…

在线词典项目-项目介绍及框架搭建

项目介绍 通过代码实现词典的注册、登录、单词注释查询、历史查询、查询记录。 有道词典分析图 客户端流程图 注释&#xff1a;首先开始-->创建流式套接字-->连接服务器-->输入需要执行的命令代码-->创建循环&#xff0c;判断需要执行的函数&#xff08;如果登录…

基于深度学习的行人重识别(person reid) 计算机竞赛

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的行人重识别 该项目较为新颖&#xff0c;适合…

AIGC | 如何用“Flow”,轻松解决复杂业务问题

随着LLM&#xff08;大语言模型&#xff09;的爆火&#xff0c;不少企业都在寻找通过LLM解决企业业务问题的方法&#xff0c;以达到降本增效的效果。但是&#xff0c;当面对较为复杂的业务问题&#xff08;如&#xff1a;背景资料多、问题分类多、条件判断复杂、涉及模块多等&a…

Java高级互联网架构师之路:垃圾回收器的介绍

本文重点 从本文开始我们将开启垃圾回收器的介绍了,我们知道垃圾回收算法是逻辑改变,而垃圾回收器是具体的实现。我们前面介绍的垃圾回收器有7个,本文将在添加三个,但是这三个目前来看不是很常用,我们只了解一下,我们主要还是讲解这7个垃圾回收器。 十个垃圾回收器 目…

天空卫士为集度智能汽车系上“安全带”

10月27日&#xff0c;集度汽车在北京正式发布了旗下首款量产车型——极越 01 SUV。极越 01 SUV 是一款集科技、智能、美学于一身的纯电动中大型SUV&#xff0c;号称全球首款“AI 汽车机器人”。作为集度的合作伙伴&#xff0c;天空卫士第一时间送上祝福&#xff0c;祝愿极越大卖…

鸿蒙应用开发取消标题栏

在config.json中的module下添加如下内容&#xff1a; "metaData": {"customizeData": [{"name": "hwc-theme","extra": "","value": "androidhwext:style/Theme.Emui.Light.NoTitleBar"}] }…

深度学习_4 数据训练之线性回归

训练数据 线性回归 基本原理 比如我们要买房&#xff0c;机器学习深度学习来预测房价。房价的影响因素有&#xff1a;卧室数量&#xff0c;卫生间数量&#xff0c;居住面积。此外&#xff0c;还需要加上偏差值来计算。我们要找到一个正确率高的计算方法来计算。 首先&#…

web3 React dapp中编写balance组件从redux取出并展示用户资产

好啊 上文WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量中 我们拿到了用户的一个本身 和 交易所token数量 并放进了redux中做了一个全局管理 然后 我们继续 先 起来ganache的一个模拟环境 ganache -d然后 我们启动自己的项目 顺手发…

SaveToDisk属性

大家好&#xff0c;才是真的好。 Domino Designer的帮助文档里面充满了宝藏&#xff0c;最近就发现一个notesitem对象的SaveToDisk属性&#xff0c;你可以设置它为false&#xff0c;这样&#xff0c;虽然文档保存了&#xff0c;但这个字段本身可以不用保存&#xff0c;不仅可以…

激光雷达标定板如何提高激光雷达避免误判的精准度

激光雷达在提高自动驾驶的安全性方面具有重要作用。它通过高精度测量、避免误判、实时感知、适应不同环境和结合其他传感器等方式&#xff0c;为自动驾驶系统提供准确、可靠的感知数据&#xff0c;从而确保行驶的安全性和稳定性。 激光雷达可以通过以下方式避免误判&#xff1a…

测试用例设计方法:正交试验法详解!

01、正交试验法介绍 正交试验法是研究多因素、多水平的一种试验法&#xff0c;它是利用正交表来对试验进行设计&#xff0c;通过少数的试验替代全面试验&#xff0c;根据正交表的正交性从全面试验中挑选适量的、有代表性的点进行试验&#xff0c;这些有代表性的点具备了“均匀…