软件编程
位置:首页>> 软件编程>> Android编程>> Flutter开发技巧RadialGradient中radius计算详解

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;

【贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

p>【非贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

2、情况二

Alignment.centerLeft,
Alignment.centerRight,

【贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

【非贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

3、情况三

Alignment.topCenter,
Alignment.bottomCenter,

【贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

【非贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

4、情况四

Alignment.topLeft,
Alignment.topRight,
Alignment.bottomLeft,
Alignment.bottomRight,

【贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

【非贪婪模式】

Flutter开发技巧RadialGradient中radius计算详解

【使用对角线半径】(注意左下角的一点点留白,基本实现全覆盖)

Flutter开发技巧RadialGradient中radius计算详解

三、实现源码

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

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com