在实际开发中,如果 Flutter 现有的组件不能满足我们的需求,那么就需要自定义组件。Flutter中自定义组件有三种方式:通过组合其它组件、自绘和实现RenderObject。先来个简单的,组合其他组件,实现一个自定义按钮组件。
业务需求:
1. 按钮颜色渐变;
2. 按钮可设置圆角;
3. 按钮点击时,按钮颜色有涟漪效果;
4. 实现点击事件,包括状态保持;
第一步,自定义按钮组件;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
/// 自定义按钮
class CustomButton extends StatelessWidget{
// 渐变色设置
final List<Color>? colors;
// 宽度设置
final double? width;
// 高度设置
final double? height;
// 子组件
final Widget child;
/// 触发回调
final GestureTapCallback? onTap;
//圆角设置
final BorderRadius? borderRadius;
/// 构造方法
CustomButton({this.colors, this.width, this.height,this.onTap, this.borderRadius,required this.child});
@override
Widget build(BuildContext context) {
//通过context获取主题
ThemeData theme = Theme.of(context);
// 如果 colors 为null时,使用上下文中的主颜色,colors时,使用系统主色
List<Color> _colors = colors ?? [theme.primaryColor,theme.primaryColorDark];
// 构建装饰类容器
DecoratedBox decoratedBox = DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(colors:_colors),
borderRadius: borderRadius,
),
child: Material(
type: MaterialType.transparency,
// 水波纹效果
child: InkWell(
splashColor: colors!.last,
highlightColor: Colors.transparent,
// 点击事件
onTap: onTap,
// 约束盒子
child: ConstrainedBox(
constraints: BoxConstraints.tightFor(height: height,width: width),
// 布局方位类
child: Center(
// 设置边距
child: Padding(
padding: const EdgeInsets.all(8.0),
// 设置样式
child: DefaultTextStyle(
style: TextStyle(fontWeight: FontWeight.bold),
child: child,
),
),
),
),
),
),
);
// 如果组合控件中没有点击事件,则需要自己实现点击回调事件
// final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};
// // 如果传递回调事件时,回调事件的关键代码
// if(onTap != null){
// gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
// () => TapGestureRecognizer(debugOwner: this),
// (TapGestureRecognizer instance) {
// instance
// ..onTap = onTap;
// },
// );
// }
// // 使用 RawGestureDetector 构造控件,RawGestureDetector是有状态的组件
// return RawGestureDetector(
// gestures: gestures,
// child: decoratedBox,
// );
return decoratedBox;
}
}
备注:
- 在这一组组合组件中,既有无状态组件(InkWell),也有有状态组件(Material),还有实现RenderObject类的组件,ConstrainedBox、DecoratedBox类间接继承了RenderObject类。
- 在处理点击事件时,刚开始不知道把点击事件放在哪个控件下,查看GestureDetector 源码写了注释掉的那段代码,后来发现 InkWell 类中已经包含了 onTap事件,就把那一段代码注释掉了。
第二步,调用自定义组件;
功能说明:使用自定义按钮,传递高度、宽度、颜色组等参数,并在点击按钮时,记录点击次数。
import 'package:flutter/material.dart';
import 'CustomButton.dart';
//调用自定义组件
class CustomWidgetRoute extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return _CustomWidgetRouteState();
}
}
class _CustomWidgetRouteState extends State<CustomWidgetRoute>{
int _counter = 0;
void doClick(){
setState(() {
debugPrint("组合组件被点击了");
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
CustomButton(
colors: [Colors.lime, Colors.green],
width: 200,
height: 50,
child: Text("自定义按钮"),
borderRadius: BorderRadius.circular(20),
onTap: doClick,
),
],
),
);
}
}
第三步,加入主程序,运行代码;
import 'package:flutter/material.dart';
import 'CustomWidgetRoute.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text("welocom to flutter"),
),
body: CustomWidgetRoute(),
),
);
}
}

网友评论