开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
AlertDialog 背景支持渐变色
背景
设计图上的弹框背景是个渐变色,系统自带的AlertDialog
可以更改背景颜色,却不支持设置渐变,不准备自己全新搞一个,查看AlertDialog
的源码
我们只要对dialogChild变量,进行扩展,支持渐变背景就可以了。
思路
- 支持背景色渐变我们可以使用Container
- decoration 作为参数传递
- decoration 和 color 有冲突,需要填一个判断
- 增加宽度,支持对弹框的宽度进行自定义
主要更改部分如下
代码
代码太多,更改部分如下:
import 'package:flutter/material.dart';
import 'dart:ui';
const EdgeInsets _defaultInsetPadding =
EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0);
class CustomDialog extends StatelessWidget {
const CustomDialog({
Key? key,
this.title,
this.decoration,
this.width,
.....
}) : assert(contentPadding != null),
assert(clipBehavior != null),
super(key: key);
final Widget? title;
// 添加一个container 支持dialog的样式自定义
final Decoration? decoration;
// 添加一个container 支持dialog的样式自定义
final double? width;
...
Widget dialogChild = Container(
decoration: decoration,
color: decoration!=null?null:Colors.white,
width: width,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: columnChildren,
),
);
....
return Dialog(
backgroundColor: Colors.transparent,
elevation: elevation,
insetPadding: insetPadding,
clipBehavior: clipBehavior,
shape: shape,
child: dialogChild,
);
}
}
double _paddingScaleFactor(double textScaleFactor) {
final double clampedTextScaleFactor =
textScaleFactor.clamp(1.0, 2.0).toDouble();
return lerpDouble(1.0, 1.0 / 3.0, clampedTextScaleFactor - 1.0)!;
}
加减框
思路
经常会遇到不是特别大的功能点,项目用的地方也挺多,找个框架不一定合适,还有点大,自己写吧~
- 一个"+"号
IconButton
- 一个"-"号
IconButton
- 一个输入框
TextField
- 上面的放一行
Row
- 每部分有边框,有颜色,各加一个
Container
- 参数分析:按钮宽高可自定义、整体宽度可定义,可以支持输入的最大值、点击加、减、编辑输入框的事件,
disabled
属性
代码
import 'package:flutter/material.dart';
class NumberControllerWidget extends StatefulWidget {
//高度
final double height;
//输入框的宽度 总体宽度为自适应
final double width;
//按钮的宽度
final double iconWidth;
//默认输入框显示的数量
final String numText;
//点击加号回调 数量
final ValueChanged? addValueChanged;
//点击减号回调 数量
final ValueChanged? subValueChanged;
//输入框更改数量回调
final ValueChanged? updateValueChanged;
//最大可以加到的数字
final int maxCount;
final bool disabled;
NumberControllerWidget(
{this.height = 30,
this.width = 30,
this.iconWidth = 25,
this.numText = '0',
this.addValueChanged,
this.subValueChanged,
this.updateValueChanged,
this.disabled = false,
this.maxCount = 99});
@override
_NumberControllerWidgetState createState() => _NumberControllerWidgetState();
}
class _NumberControllerWidgetState extends State<NumberControllerWidget> {
var textController = new TextEditingController();
late FocusNode focusNode;
@override
void initState() {
super.initState();
this.textController.text = widget.numText;
focusNode = new FocusNode();
// 初始化时,监听输入框失去焦点事件
focusNode.addListener(() {
if (!focusNode.hasFocus) {
if (widget.updateValueChanged != null)
widget.updateValueChanged?.call(textController.text);
}
});
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
height: widget.height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(width: 1, color: Colors.black12)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
//减号
coustomIconButton(icon: Icons.remove, isAdd: false),
//输入框
Container(
width: widget.width,
decoration: BoxDecoration(
border: Border(
left: BorderSide(width: 1, color: Colors.black12),
right: BorderSide(width: 1, color: Colors.black12))),
child: TextField(
controller: textController,
focusNode: focusNode,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
readOnly: widget.disabled,
style: TextStyle(fontSize: 12),
enableInteractiveSelection: false,
decoration: InputDecoration(
contentPadding:
EdgeInsets.only(left: 0, top: 2, bottom: 2, right: 0),
border: const OutlineInputBorder(
gapPadding: 0,
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
),
),
),
//加号
coustomIconButton(icon: Icons.add, isAdd: true),
],
),
)
],
);
}
Widget coustomIconButton({IconData? icon,required bool isAdd}) {
return Container(
width: widget.iconWidth,
child: IconButton(
padding: EdgeInsets.all(0),
icon: Icon(icon),
onPressed: () {
FocusScope.of(context).requestFocus(new FocusNode());
int number = int.parse(textController.text);
if (!isAdd && number == 0) return;
if (isAdd) {
if ((number < widget.maxCount)) {
number++;
if (widget.addValueChanged != null)
widget.addValueChanged?.call(number);
}
} else {
if (number == 1) return;
number--;
if (widget.subValueChanged != null)
widget.subValueChanged?.call(number);
}
textController.text = '$number';
if (widget.updateValueChanged != null)
widget.updateValueChanged?.call(number);
},
),
);
}
}
事件进度节点
思路
- 第一画圆球和下边线
- 中间的话圆圈、上边线、下边线
- 最后一个画上边线和圆球
- 为了区分,需要传参:是否显示上边线,是否显示下边线、是否点亮
代码
import 'package:flutter/material.dart';
class LeftLineView extends StatelessWidget {
final bool showTop;
final bool showBottom;
final bool isLight;
const LeftLineView(this.showTop, this.showBottom, this.isLight);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16),//圆和线的左右外边距
width: 16,
child: CustomPaint(
painter: LeftLinePainter(showTop, showBottom, isLight),
),
);
}
}
class LeftLinePainter extends CustomPainter {
static const double _topHeight = 16; //圆上的线高度
static const Color _lightColor = Color(0xfffe3536);//圆点亮的颜色
static const Color _normalColor = Color(0xff999999);//圆没点亮的颜色
final bool showTop; //是否显示圆上面的线
final bool showBottom;//是否显示圆下面的线
final bool isLight;//圆形是否点亮
const LeftLinePainter(this.showTop, this.showBottom, this.isLight);
@override
void paint(Canvas canvas, Size size) {
double lineWidth = 2; // 竖线的宽度
double centerX = size.width / 2; //容器X轴的中心点
Paint linePain = Paint();// 创建一个画线的画笔
linePain.color = showTop ? Colors.red : Colors.transparent;
linePain.strokeWidth = lineWidth;
linePain.strokeCap = StrokeCap.square;//画线的头是方形的
//画圆上面的线
canvas.drawLine(Offset(centerX, 0), Offset(centerX, _topHeight), linePain);
//依据下面的线是否显示来设置是否透明
linePain.color = showBottom ? Colors.red : Colors.transparent;
// 画圆下面的线
canvas.drawLine(
Offset(centerX, _topHeight), Offset(centerX, size.height), linePain);
// 创建画圆的画笔
Paint circlePaint = Paint();
circlePaint.color = isLight ? _lightColor : _normalColor;
circlePaint.style = PaintingStyle.fill;
// 画中间的圆
canvas.drawCircle(Offset(centerX, _topHeight), centerX, circlePaint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
if(oldDelegate is LeftLinePainter){
LeftLinePainter old = oldDelegate;
if(old.showBottom!=showBottom){
return true;
}
if(old.showTop!=showTop){
return true;
}
if(old.isLight!=isLight){
return true;
}
return false;
}
return true;
}
}