一、问题来源
项目中遇到 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
以上就是Flutter小技巧RadialGradient 中 radius 的计算的详细内容,更多关于Flutter RadialGradient radius计算的资料请关注编程网其它相关文章!