当前位置:网站首页>flutter自定义组件
flutter自定义组件
2022-06-30 15:49:00 【一叶飘舟】
分享一个大佬的自定义组件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,
// ),
),
),
],
),
);
}
}
边栏推荐
- redis数据结构分析
- Niuke.com: minimum cost of climbing stairs
- simpleITK读取nii遇到ITK only supports orthonormal direction cosines的错误
- 异常类_日志框架
- geo 读取单细胞csv表达矩阵 单细胞 改列名 seurat
- RT-Thread 堆区大小设置
- Hologres shared cluster helps Taobao subscribe to the extreme refined operation
- TCP socket and TCP connection
- Design of piece counter based on 51 single chip microcomputer
- Delete duplicates in an ordered array ii[double pointers -- unified in multiple cases]
猜你喜欢

Raft introduction

Redis data structure analysis

RT thread heap size setting

Property or method “approval1“ is not defined on the instance but referenced during render

MC Instruction Decoder

Deep learning - (2) several common loss functions

Etcd教程 — 第八章 Etcd之Compact、Watch和Lease API

"Promotion + funny plot", how to collide with the sparks of popular funds?
![[machine learning] K-means clustering analysis](/img/5f/3199fbd4ff2129d3e4ea518812c9e9.png)
[machine learning] K-means clustering analysis
![[BJDCTF2020]The mystery of ip|[CISCN2019 华东南赛区]Web11|SSTI注入](/img/c2/d6760826b81589781574aebff61f9a.png)
[BJDCTF2020]The mystery of ip|[CISCN2019 华东南赛区]Web11|SSTI注入
随机推荐
Etcd教程 — 第九章 Etcd之实现分布式锁
Undistorted resize using pil
Redis elimination strategy
Etcd tutorial - Chapter 8 compact, watch, and lease APIs for etcd
香港回归25周年 香港故宫博物馆正式开放成文化新地标
聊聊遠程辦公那些事兒 | 社區征文
Observation cloud reached in-depth cooperation with tdengine to optimize enterprise cloud experience
定时任务删除指定时间的的数据
巩固入门-C#基础变量和常量
RTP sending PS stream zero copy scheme
Carry two load balancing notes and find them in the future
更多龙蜥自研特性!生产可用的 Anolis OS 8.6 正式发布
Bc1.2 PD protocol
[wechat applet] basic use of common components (view/scroll-view/wiper, text/rich-text, button/image)
Internet R & D efficiency practice qunar core field Devops landing practice
OpenCV中LineTypes各枚举值(LINE_4 、LINE_8 、LINE_AA )的含义
IndexSearch
redis数据结构分析
Niuke.com: minimum cost of climbing stairs
IO stream_ recursion
https://github.com/shang1219178163/flutter_templet_projec