Flutter开发技巧RadialGradient中radius计算详解
作者:SoaringHeart 发布时间:2023-10-05 17:42:22
标签:Flutter,RadialGradient,radius,计算
一、问题来源
项目中遇到 json 模型映射成 RadialGradient 组件的需求,其他参数正常传递即可;
唯独 radius 参数效果有出入,总结记录一下;
二、四种情况
通过 RadialGradient 参数 center 可以分为四种情况,这四种情况分别对应四种 radius 的值:
1、情况一
Alignment.center,
贪婪模式下组件的宽高中最大值的一半/最小值的一半为 radius;否则radius是0.5;
【贪婪模式】
p>【非贪婪模式】
2、情况二
Alignment.centerLeft,
Alignment.centerRight,
【贪婪模式】
【非贪婪模式】
3、情况三
Alignment.topCenter,
Alignment.bottomCenter,
【贪婪模式】
【非贪婪模式】
4、情况四
Alignment.topLeft,
Alignment.topRight,
Alignment.bottomLeft,
Alignment.bottomRight,
【贪婪模式】
【非贪婪模式】
【使用对角线半径】(注意左下角的一点点留白,基本实现全覆盖)
三、实现源码
GradientOfRadialDemo
import 'package:flutter/material.dart';
import 'package:flutter_templet_project/basicWidget/SectionHeader.dart';
import 'package:flutter_templet_project/extension/alignment_ext.dart';
import 'package:tuple/tuple.dart';
class GradientOfRadialDemo extends StatefulWidget {
GradientOfRadialDemo({ Key? key, this.title}) : super(key: key);
final String? title;
@override
_GradientOfRadialDemoState createState() => _GradientOfRadialDemoState();
}
class _GradientOfRadialDemoState extends State<GradientOfRadialDemo> {
var maxWidth = double.infinity;
var maxHeight = double.infinity;
/// 是否是贪婪模式
var isGreed = true;
/// 是否使用对角线做半径
bool isDiagonal = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title ?? "$widget"),
bottom: buildAppBottom(),
),
body: Container(
// height: 300,
child: buildRadial(),
),
// body: ListView(
// children: [
// SectionHeader.h4(title: 'RadialGradient',),
// buildRadial(),
// ],
// )
);
}
buildAppBottom() {
return PreferredSize(
preferredSize: Size(double.infinity, 50),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildDropdownButton(),
_buildButton(
text: "isGreed: ${isGreed.toString()}",
onPressed: () {
this.isGreed = !this.isGreed;
setState(() {});
},
),
_buildButton(
text: "isDiagonal: ${isDiagonal.toString()}",
onPressed: () {
this.isDiagonal = !this.isDiagonal;
setState(() {});
},
),
],
)
);
}
var _dropValue = AlignmentExt.allCases[0];
var _radius = 0.5;
_buildDropdownButton() {
return DropdownButton<Alignment>(
value: _dropValue,
items: AlignmentExt.allCases.map((e) => DropdownMenuItem(
child: Text(e.toString().split('.')[1]),
value: e,
),
).toList(),
onChanged: (Alignment? value) {
if (value == null) return;
_dropValue = value;
setState(() {});
},
);
}
_buildButton({
required String text,
required VoidCallback onPressed
}) {
return TextButton(
onPressed: onPressed,
child: Center(
child: Text(text,
style: TextStyle(color: Colors.white),
)
),
);
}
Widget _buildBox({
required String text,
required Decoration decoration,
double height: 100,
double? width,
}) {
return LayoutBuilder(
builder: (context, constraints) {
this.maxWidth = constraints.maxWidth;
this.maxHeight = constraints.maxHeight;
return Container(
// width: width,
// height: height,
margin: const EdgeInsets.all(8.0),
decoration: decoration,
alignment: Alignment.center,
child: Text(text, style: TextStyle(color: Colors.white, fontSize: 16.0)),
);
}
);
}
buildRadial() {
var tuples = <Tuple2<Color, double>>[ Tuple2(Colors.red, 0.1), Tuple2(Colors.blue, 0.3), Tuple2(Colors.yellow, 0.5), Tuple2(Colors.green, 1), ];
_radius = _dropValue.radiusOfRadialGradient(
width: this.maxWidth,
height: this.maxHeight,
isGreed: this.isGreed,
isDiagonal: this.isDiagonal
) ?? 0.5;
print("_dropValue:${_dropValue} _radius:${_radius} maxWidth:${maxWidth} maxHeight:${maxHeight}");
print("_radius: $_radius");
return _buildBox(
height: 100,
text: 'RadialGradient',
decoration: BoxDecoration(
border: Border.all(),
gradient: RadialGradient(
// tileMode: this.tileMode,
// tileMode: TileMode.mirror,
radius: _radius,
tileMode: TileMode.decal,
center: _dropValue,
// focal: Alignment.bottomCenter,
colors: tuples.map((e) => e.item1).toList(),
stops: tuples.map((e) => e.item2).toList(),
),
),
);
}
}
四、radiusOfRadialGradient 方法实现
// AlignmentExtension.dart
// flutter_templet_project
//
// Created by shang on 2023/1/12 20:57.
// Copyright © 2023/1/12 shang. All rights reserved.
//
import 'dart:math' as math;
import 'package:flutter/cupertino.dart';
extension AlignmentExt on Alignment{
/// 获取雷达渐进色 radius
/// isGreed 是否贪婪模式(贪婪模式用大半径,否则小半径)
/// isDiagonal 四角是否使用对角线(为 true 则 isGreed 参数无效)
double? radiusOfRadialGradient({
required double? width,
required double? height,
bool isGreed = true,
bool isDiagonal = true,
}) {
if(width == null || height == null
|| width <= 0 || height <= 0) {
return null;
}
final max = math.max(width, height);
final min = math.min(width, height);
double result = 0.5;
if([
Alignment.center,
].contains(this)){
result = isGreed == true ? max/min * 0.5 : 0.5;
} else if ([
Alignment.topCenter,
Alignment.bottomCenter,
].contains(this)) {
result = isGreed == true ? max/min : 0.5;
} else if ([
Alignment.topLeft,
Alignment.topRight,
Alignment.bottomLeft,
Alignment.bottomRight
].contains(this)) {
if (isDiagonal) {
final tmp = math.sqrt(math.pow(max, 2) + math.pow(min, 2)).ceil();
// result = isGreed == true ? tmp/min : max/min;
result = tmp/min;
} else {
result = isGreed == true ? max/min : 1;
}
} else if ([
Alignment.centerLeft,
Alignment.centerRight,
].contains(this)) {
result = isGreed == true ? 1 : max/min * 0.5;
}
return result;
}
}
最后
项目中为了方便查看差异使用了 TileMode.decal 模式,正常使用默认模式即可;
github
来源:https://juejin.cn/post/7188426039587143738


猜你喜欢
- 一、概述顶部ViewPager指示器的字体变色,该效果图是这样的:大概是今天头条的app,神奇的地方就在于,切换ViewPager页面的时候
- 单例模式为什么要用单例确保某个类只有一个对象,常用于访问数据库操作,服务的配置文件等。单例的关键点1、默认构造函数为private,复制构造
- 实现手机电话状态的监听,主要依靠两个类:TelephoneManger和PhoneStateListener。 TelephonseMang
- 首先,建立图片与鼠标的对应关系。class MouseStyle{ [DllImport("user32.dll&qu
- 对于使用avalonia的时候某些功能需要到一些提示,比如异常或者成功都需要对用户进行提示,所以需要单独实现弹窗功能,并且可以自定义内部组件
- WPF 实现步骤控件框架使用.NET40;Visual Studio 2019;Step 继承 ItemsControl
- 有时候在配置中心有些参数是需要修改的,这时候如何不重启而达到实时生效的效果呢?添加依赖<dependencies>
- 现在基于信息安全问题,特别是版本是23以上权限越严格。特别是拍照,读,写权限一般权限允许过,下次就不用询问了的,所以很多应用都喜欢在首页或者
- 在C#的继承中尝尝会用到相关的修饰词:override和new。这两个修饰符都可以在新的子类中,重写同名的父类方法。
- 一、Feign简介Feign是netflix开发的声明式、模板化的http客户端,在使用时就像调用本地(服务消费者自己)的方法一般,帮助我们
- 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还
- VelocityTracker顾名思义即速度跟踪,在android中主要应用于touch even。Velocit
- RestTemplate未设置超时时间,导致RabbitMQ队列大量堆积,消费者假死,不进行消费,类似线程堵塞。排查:从日志排查问题,在从进
- 1)首先启动hadoop2个进程,进入hadoop/sbin目录下,依次启动如下命令[root@node02 sbin]# pwd/usr/
- 说明:在填写表数据时当输入完一个文本框后,输入下一个文本框时需要用Tab键切换,但是有的人喜欢用Enter键切换下一个,此方法是Enter取
- 一:引入依赖包<!-- https://mvnrepository.com/artifact/org.springframework.
- 在前面的博客中,https://www.jb51.net/article/134866.htm 我们使用了spring boot的异步操作,
- 1、@Configuration&@Bean给容器中注册组件@Configuration及@Bean的使用参考如下代码:packag
- 第一步:获取存储的路径 我们用/sdcard/Android/data/包名/的路径 方便我们测试查看 String path=MyAppl
- 前言这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!!这里就对自己学过来的内容进