Flutter开发技巧RadialGradient中radius计算详解
SoaringHeart 人气:0一、问题来源
项目中遇到 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,
【贪婪模式】
【非贪婪模式】
【使用对角线半径】(注意左下角的一点点留白,基本实现全覆盖)
三、实现源码
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 模式,正常使用默认模式即可;
加载全部内容