flutter 自定义单列下拉筛选组件
2021-08-16 本文已影响0人
卢融霜
运行效果:
QQ录屏2021081617505520218161752432.gif筛选组件类
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// @description 作用:列表筛选组件
/// @date: 2021/8/16
/// @author:卢融霜
class ScreenWidget extends StatefulWidget {
//筛选视图高度
double topBarHeight;
//显示标题
Widget titleWidget;
//筛选组件
Widget screenListWidget;
//子组件
Widget child;
//控制器,开关
ScreenController controller;
//打开监听
Function screenOpen;
//关闭监听
Function screenClose;
ScreenWidget(
{Key key,
this.controller,
this.topBarHeight = 0,
this.screenOpen,
this.screenClose,
@required this.titleWidget,
@required this.screenListWidget,
@required this.child})
: super(key: key);
@override
_ScreenWidgetState createState() => _ScreenWidgetState();
}
AnimationController raController;
Animation _raAnimation;
Animation<double> _heAnimation;
double viewHegin = 0;
class _ScreenWidgetState extends State<ScreenWidget>
with SingleTickerProviderStateMixin {
@override
void dispose() {
raController.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
if (widget.topBarHeight == null || widget.topBarHeight == 0) {
widget.topBarHeight = 45.r;
}
raController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
_raAnimation = Tween(begin: .0, end: .5).animate(raController);
_heAnimation = Tween(begin: .0, end: 0.1).animate(raController);
Future.delayed(Duration.zero, () {
_heAnimation =
Tween(begin: .0, end: MediaQuery.of(context).size.height / 2.5)
.animate(raController)
..addListener(() {
setState(() {
viewHegin = _heAnimation.value;
});
if (raController.isCompleted) {
if (widget.screenOpen != null) {
widget.screenOpen();
}
} else if (raController.isDismissed) {
if (widget.screenClose != null) {
widget.screenClose();
}
}
});
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned(
child: Container(
height: widget.topBarHeight,
alignment: Alignment.center,
color: Colors.white,
child: InkWell(
onTap: () {
if (raController.isCompleted) {
raController?.reverse();
} else {
raController?.forward();
}
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
widget.titleWidget,
RotationTransition(
turns: _raAnimation,
child: Icon(
Icons.arrow_drop_down_sharp,
size: 30.r,
),
)
],
),
),
)),
Stack(
children: [
Align(
child: Container(
margin: EdgeInsets.only(top: widget.topBarHeight),
width: MediaQuery.of(context).size.width,
height: double.maxFinite,
child: Column(
children: [Expanded(child: widget.child)],
),
)),
Align(
alignment: Alignment.topCenter,
child: Container(
height:
(viewHegin > 0) ? MediaQuery.of(context).size.height : 0,
decoration: BoxDecoration(
color: Colors.black26,
border: Border(
top: BorderSide(
color: const Color.fromRGBO(230, 230, 230, 1),
width: 0.4.r))),
margin: EdgeInsets.only(top: widget.topBarHeight),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: viewHegin,
child: widget.screenListWidget,
)
],
),
))
],
)
],
);
}
}
class ScreenController {
//打开
void open() {
raController?.forward();
}
//关闭
void close() {
raController?.reverse();
}
}
使用组件
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:lnsl_credit_flutter/base/base_routes_widget.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:lnsl_credit_flutter/widget/screen_widget.dart';
/// @description 作用:人员查询
/// @date: 2021/8/16
/// @author:卢融霜
class PersonnelSearch extends StatefulWidget {
const PersonnelSearch({Key key}) : super(key: key);
@override
_PersonnelSearchState createState() => _PersonnelSearchState();
}
class _PersonnelSearchState extends State<PersonnelSearch>{
ScreenController controller = ScreenController();
List<String> option = [
"总监",
"监理工程师",
"监理员",
"造价工程师",
"质量检测员",
"建造师",
"安全工程师",
"造价员",
"五大员",
"三类人员",
"其他执业人员"
];
String indexTitle = "总监";
int selectIndex = 0;
final ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return
BaseRoutesWidget(
isSearchBar: true,
search: (String searchTitle) {},
child:
ScreenWidget(
screenOpen: () {
_scrollController.animateTo(selectIndex * 30.r,
duration: const Duration(microseconds: 1), curve: Curves.ease);
},
topBarHeight: 45.r,
controller: controller,
titleWidget: Text(
indexTitle,
style: TextStyle(
fontSize: 15.r, color: const Color.fromRGBO(51, 51, 51, 1)),
),
screenListWidget: Container(
color: Colors.white,
child: ListView.builder(
controller: _scrollController,
itemCount: option.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
setState(() {
indexTitle = option[index];
selectIndex = index;
controller.close();
});
},
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: const Color.fromRGBO(230, 230, 230, 1),
width: 0.4.r))),
child: Text(
option[index],
style: TextStyle(
color: selectIndex == index
? const Color.fromRGBO(41, 121, 255, 1)
: const Color.fromRGBO(51, 51, 51, 1),
fontSize: 14.r),
),
padding: EdgeInsets.all(10.r),
),
);
}),
),
child: ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {},
child: Container(
padding: EdgeInsets.all(10.r),
child: Text("1111111"),
),
);
})),
);
}
}
涉及到的其他组件 BaseRoutesWidget
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// @description 作用:封装导航栏
/// @date: 2021/7/14
/// @author:卢融霜
class BaseRoutesWidget extends StatefulWidget {
//标题
String title;
double titleFontSize = 14.r;
double toolBarHeight = 40.r;
List<Widget> actions;
Widget child;
PreferredSizeWidget titleBottom;
Color titleBgColor;
bool showAppBar = true;
bool isSearchBar = false;
Function(String searchText) search;
FloatingActionButton floatingActionButton;
BaseRoutesWidget(
{Key key,
this.title,
this.actions,
this.child,
this.titleBottom,
this.titleBgColor,
this.showAppBar = true,
this.isSearchBar = false,
this.search,
this.floatingActionButton})
: super(key: key);
@override
_BaseRoutesWidgetState createState() => _BaseRoutesWidgetState();
}
class _BaseRoutesWidgetState extends State<BaseRoutesWidget> {
TextEditingController controller;
@override
void initState() {
if (widget.isSearchBar) {
controller = TextEditingController();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: widget.floatingActionButton,
resizeToAvoidBottomInset: false,
appBar: widget.showAppBar
? (widget.isSearchBar
? AppBar(
leadingWidth: 30.r,
toolbarHeight: widget.toolBarHeight,
centerTitle: true,
actions: widget.actions,
bottom: widget.titleBottom,
title: Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(right: 10.r),
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(20.r)),
color: const Color.fromRGBO(242, 242, 242, 1)),
padding: EdgeInsets.only(
left: 10.r, right: 10.r, top: 4.r, bottom: 4.r),
child: TextField(
textInputAction: TextInputAction.search,
controller: controller,
style: TextStyle(fontSize: 13.r),
onEditingComplete: () {
widget.search(controller.text);
},
decoration: InputDecoration(
hintText: "请输入关键字",
hintStyle: TextStyle(fontSize: 13.r),
border: InputBorder.none,
isCollapsed: true,
icon: Icon(
Icons.search_outlined,
size: 18.r,
),
),
),
)),
InkWell(
splashColor: Colors.transparent,
child: Text(
"搜索",
style: TextStyle(fontSize: 14.r),
),
onTap: () {
widget.search(controller.text);
},
)
],
),
)
: AppBar(
toolbarHeight: widget.toolBarHeight,
centerTitle: true,
actions: widget.actions,
bottom: widget.titleBottom,
title: Text(widget.title,
style: TextStyle(fontSize: widget.titleFontSize)),
))
: null,
body: widget.child,
);
}
}