flutter自定义组件
Posted 一叶飘舟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flutter自定义组件相关的知识,希望对你有一定的参考价值。
分享一个大佬的自定义组件demo。
更多demo请移步github:
数量计步器 NumberStepper
//...
NumberStepper(
minValue: 1,
maxValue: 1000,
stepValue: 100,
iconSize: 60,
value: 1000,
color: Colors.blue,
style: NumberStepperStyle.system,
block: (value)
DDLog(value);
,
),
SizedBox(height: 20,),
NumberStepper(
minValue: 1,
maxValue: 1000,
stepValue: 100,
iconSize: 40,
value: 1000,
color: Colors.blue,
style: NumberStepperStyle.outlined,
block: (value)
DDLog(value);
,
),
//...
如果打不开,这里是源码:
//
// NumberStepper.dart
// flutter_templet_project
//
// Created by shang on 6/13/21 6:23 AM.
// Copyright © 6/13/21 shang. All rights reserved.
//
// ignore: must_be_immutable
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_templet_project/extensions/ddlog.dart';
enum NumberStepperStyle
system,
outlined,
textfield,
///自定义数值增减 Stepper
class NumberStepper extends StatefulWidget
NumberStepper(
required this.minValue,
required this.maxValue,
required this.stepValue,
this.iconSize = 24,
required this.value,
this.color = Colors.blue,
this.style = NumberStepperStyle.system,
this.radius = 5.0,
this.wraps = true,
required this.block,
);
final int minValue;
final int maxValue;
final int stepValue;
final double iconSize;
int value;
final bool wraps;
final Color color;
final NumberStepperStyle style;
final double radius;
void Function(int value) block;
@override
_NumberStepperState createState() => _NumberStepperState();
class _NumberStepperState extends State<NumberStepper>
// 控制器
final _textController = TextEditingController();
// 焦点
final focusNode1 = FocusNode();
@override
void initState()
// TODO: implement initState
_textController.text = "$widget.value";
ddlog(_textController.text);
super.initState();
@override
Widget build(BuildContext context)
// return buildOther(context);
switch (widget.style)
case NumberStepperStyle.outlined:
return buildOutlinedStyle(context);
break;
case NumberStepperStyle.textfield:
return buildTexfieldStyle(context);
default:
break;
return buildSystemStyle(context);
Widget buildSystemStyle(BuildContext context)
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: widget.iconSize,
height: widget.iconSize,
decoration: BoxDecoration(
color: widget.color,
borderRadius: BorderRadius.circular(widget.radius),
border: Border.all(color: widget.color, width: 1), // 边色与边宽度
),
child: IconButton(
icon: Icon(Icons.remove, size: widget.iconSize),
// iconSize: widget.iconSize,
padding: EdgeInsets.zero,
color: Colors.white,
onPressed: ()
go(-widget.stepValue);
,
),
),
Container(
width: widget.value.toString().length*18*widget.iconSize/30,
// width: widget.iconSize + 20,
child: Text('$widget.value',
style: TextStyle(
fontSize: widget.iconSize * 0.8,
),
textAlign: TextAlign.center,
),
),
Container(
width: widget.iconSize,
height: widget.iconSize,
decoration: BoxDecoration(
color: widget.color,
borderRadius: BorderRadius.circular(widget.radius),
border: Border.all(color: widget.color, width: 1), // 边色与边宽度
),
child: IconButton(
icon: Icon(Icons.add, size: widget.iconSize,),
// iconSize: widget.iconSize,
padding: EdgeInsets.zero,
color: Colors.white,
onPressed: ()
setState(()
go(widget.stepValue);
);
,
),
),
],
);
Widget buildOutlinedStyle(BuildContext context)
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: widget.iconSize,
height: widget.iconSize,
// color: Theme.of(context).primaryColor,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(widget.radius),
border: Border.all(color: widget.color, width: 1), // 边色与边宽度
),
child: IconButton(
icon: Icon(Icons.remove, size: widget.iconSize),
// iconSize: widget.iconSize,
padding: EdgeInsets.zero,
color: widget.color,
onPressed: ()
go(-widget.stepValue);
,
),
),
Container(
width: widget.value.toString().length*18*widget.iconSize/30,
// width: widget.iconSize + 20,
child: Text('$widget.value',
style: TextStyle(
fontSize: widget.iconSize * 0.8,
),
textAlign: TextAlign.center,
),
),
Container(
width: widget.iconSize,
height: widget.iconSize,
// color: Theme.of(context).primaryColor,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(widget.radius),
border: Border.all(color: widget.color, width: 1), // 边色与边宽度
),
child: IconButton(
icon: Icon(Icons.add, size: widget.iconSize),
// iconSize: widget.iconSize,
padding: EdgeInsets.zero,
color: widget.color,
onPressed: ()
setState(()
go(widget.stepValue);
);
,
),
),
],
);
Widget buildTexfieldStyle(BuildContext context)
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: TextField(
enableInteractiveSelection: false,
toolbarOptions: ToolbarOptions(
copy:false,
paste: false,
cut: false,
selectAll: false,
//by default all are disabled 'false'
),
controller: _textController,
decoration: InputDecoration(
// labelText: "请输入内容",//输入框内无文字时提示内容,有内容时会自动浮在内容上方
// helperText: "随便输入文字或数字", //输入框底部辅助性说明文字
prefixIcon:IconButton(
icon: Icon(
Icons.remove,
size: widget.iconSize,
),
onPressed: ()
// go(-widget.stepValue);
setState(()
go(-widget.stepValue);
_textController.text = "$widget.value";
);
,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0) //圆角大小
),
suffixIcon: IconButton(
icon: Icon(
Icons.add,
size: widget.iconSize,
),
onPressed: ()
// go(widget.stepValue);
setState(()
// FocusScope.of(context).requestFocus(FocusNode());
go(widget.stepValue);
_textController.text = "$widget.value";
);
,
),
contentPadding: const EdgeInsets.only(bottom:8)
),
keyboardType: TextInputType.number,
),
),
],
);
void go(int stepValue)
setState(()
if (stepValue < 0 && (widget.value == widget.minValue || widget.value + stepValue < widget.minValue))
ddlog("it's minValue!");
if (widget.wraps) widget.value = widget.maxValue;
widget.block(widget.value);
return;
if (stepValue > 0 && (widget.value == widget.maxValue || widget.value + stepValue > widget.maxValue))
ddlog("it's maxValue!");
if (widget.wraps) widget.value = widget.minValue;
widget.block(widget.value);
return;
widget.value += stepValue;
);
widget.block(widget.value);
LineSegmentControl / 线条指示器分段组件
//...
SizedBox(height: 15),
buildLineSegmentControl(null, lineColor: Colors.blue),
SizedBox(height: 15),
buildLineSegmentControl(Colors.white, lineColor: Colors.blue),
SizedBox(height: 15),
buildLineSegmentControl(Colors.black87, lineColor: Colors.white),
//...
Widget buildLineSegmentControl(Color? backgroundColor, required Color lineColor)
final Map<int, Widget> children = const <int, Widget>
0: Text("Item 111", style: TextStyle(fontSize: 15), textAlign: TextAlign.center,),
1: Text("Item 222", style: TextStyle(fontSize: 15), textAlign: TextAlign.center,),
2: Text("Item 333", style: TextStyle(fontSize: 15), textAlign: TextAlign.center,),
;
if (backgroundColor != null)
return LineSegmentControl(
groupValue: groupValue,
children: children,
backgroundColor: backgroundColor,
lineColor: lineColor,
onValueChanged: (i)
setState(()
groupValue = int.parse("$i");
);
DDLog(groupValue);
,
);
return LineSegmentControl(
groupValue: groupValue,
children: children,
// backgroundColor: backgroundColor,
lineColor: lineColor,
onValueChanged: (i)
setState(()
groupValue = int.parse("$i");
);
DDLog(groupValue);
,
);
//
// LineSegmentWidget.dart
// fluttertemplet
//
// Created by shang on 6/14/21 8:47 AM.
// Copyright © 6/14/21 shang. All rights reserved.
//
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:fluttertemplet/dartExpand/DDLog.dart';
enum LineSegmentStyle
top,
bottom,
///线条指示器分段组件
class LineSegmentControl<T> extends StatefulWidget
final Map<T, Widget> children;
T? groupValue;
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry margin;
final LineSegmentStyle style;
final Color? backgroundColor;
final Color lineColor;
final double height;
final Radius radius;
void Function(T value) onValueChanged;
LineSegmentControl(
Key? key,
required this.children,
required this.groupValue,
this.style = LineSegmentStyle.bottom,
this.backgroundColor = CupertinoColors.tertiarySystemFill,
this.lineColor = Colors.blue,
this.height = 36,
this.padding = const EdgeInsets.symmetric(horizontal: 0),
this.margin = const EdgeInsets.symmetric(horizontal: 15),
this.radius = const Radius.circular(4),
required this.onValueChanged,
) : super(key: key);
@override
_LineSegmentControlState createState() => _LineSegmentControlState();
class _LineSegmentControlState extends State<LineSegmentControl>
@override
Widget build(BuildContext context)
double screenWidth = MediaQuery.of(context).size.width;
double contentWidth = screenWidth - widget.margin.horizontal - widget.padding.horizontal;
double itemWidth = contentWidth / widget.children.values.length;
return Container(
margin: widget.margin,
padding: widget.padding,
decoration: BoxDecoration(
color: widget.backgroundColor,
borderRadius: BorderRadius.all(widget.radius),
),
child: Stack(
children: [
Row(
children: widget.children.values.map((e) => Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: widget.height,
width: itemWidth,
child: TextButton(
child: e,
onPressed: ()
DDLog(e);
setState(()
widget.groupValue = widget.children.values.toList().indexOf(e);
);
widget.onValueChanged(widget.groupValue);
,
),
),
],
),
).toList(),
),
AnimatedPositioned(
duration: Duration(milliseconds: 200),
top: widget.style == LineSegmentStyle.top ? 0 : widget.height - 2,
left: widget.groupValue*itemWidth,
child: Container(
height: 2,
width: itemWidth,
color: widget.lineColor,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(4),
// color: widget.lineColor,
// ),
),
),
],
),
);
以上是关于flutter自定义组件的主要内容,如果未能解决你的问题,请参考以下文章