flutter 下拉筛选组件
2021-10-19 本文已影响0人
卢融霜
效果图
QQ录屏20211019151055202110191512221.gif网页版(第一次打开网址加载会很慢)
网页版
代码
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter1/widget/drop_down_widget.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'base/base_routes_widget.dart';
/// @description 作用:筛选组件演示
/// @date: 2021/10/14
/// @author:卢融霜
class DropDownPage extends StatefulWidget {
const DropDownPage({Key key}) : super(key: key);
@override
_DropDownPageState createState() => _DropDownPageState();
}
class _DropDownPageState extends State<DropDownPage> {
List<String> titles = ["北京", "招标类型", "更多筛选"];
List<Widget> listWidget = [];
ScreenControl screenControl = ScreenControl();
List<String> types = ["全部", "招标", "中标", "公示"];
@override
void initState() {
listWidget = [
Row(
children: [
Expanded(
flex: 1,
child: ListView.builder(itemBuilder: (context, index) {
return InkWell(
onTap: () {},
child: Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(color: Color(0xffdddddd)))),
padding: EdgeInsets.all(10.r),
child: Text("北京", style: TextStyle(fontSize: 14.sp)),
),
);
})),
Expanded(
flex: 1,
child: ListView.builder(itemBuilder: (context, index) {
return InkWell(
onTap: () {
titles[0] = "省份";
screenControl.screenHide();
},
child: Container(
decoration: const BoxDecoration(
color: Color(0xffdddddd),
border: Border(
bottom: BorderSide(color: Color(0xffffffff)))),
padding: EdgeInsets.all(10.r),
child: Text("北京", style: TextStyle(fontSize: 14.sp)),
),
);
}))
],
),
ListView.builder(
shrinkWrap: true,
itemCount: types.length,
itemBuilder: (context, index) {
return Container(
width: double.infinity,
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Color(0xffdddddd)))),
padding: EdgeInsets.all(10.r),
child: InkWell(
onTap: () {
titles[1] = types[index];
screenControl.screenHide();
},
child: Text(
types[index],
style: TextStyle(fontSize: 14.sp),
)),
);
}),
ListView(
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.only(
left: 15.r, top: 10.r, right: 15.r, bottom: 10.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("检索内容",
style:
TextStyle(fontSize: 14.r, fontWeight: FontWeight.bold)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: Text(
"全部",
style: TextStyle(fontSize: 14.r),
),
),
MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: Text(
"标题",
style: TextStyle(fontSize: 14.r),
),
),
MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: Text(
"内容",
style: TextStyle(fontSize: 14.r),
),
)
],
)
],
),
),
Container(
padding: EdgeInsets.only(left: 15.r, right: 15.r, bottom: 10.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("匹配方式",
style:
TextStyle(fontSize: 14.r, fontWeight: FontWeight.bold)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: Text(
"全部",
style: TextStyle(fontSize: 14.r),
),
),
MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: Text(
"模糊",
style: TextStyle(fontSize: 14.r),
),
),
MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: Text(
"精准",
style: TextStyle(fontSize: 14.r),
),
)
],
)
],
),
)
],
)
];
super.initState();
}
@override
Widget build(BuildContext context) {
return BaseRoutesWidget(
title: '筛选组件',
child: DropDownWidget(
titles,
listWidget,
height: 40.r,
bottomHeight: 400.r,
screenControl: screenControl,
child: Container(
margin: EdgeInsets.only(top: 40.4.r),
child: ListView.builder(itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(15.r),
child: Text("item $index"),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: const Color(0xffeeeeee), width: 0.4.r))),
);
}),
),
));
}
}
筛选组件
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter1/widget/drop_down_head_widget.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// @description 作用:多级筛选
/// @date: 2021/10/14
/// @author:卢融霜
class DropDownWidget extends StatefulWidget {
//标题集合
List<String> titles;
//展开视图集合
List<Widget> listWidget;
// 高度
double height;
//子集
Widget child;
//筛选文字大小
double headFontSize;
// 筛选图标icons
IconData iconData;
//筛选高度 限制
// BoxConstraints constraints;
double bottomHeight;
ScreenControl screenControl;
DropDownWidget(this.titles, this.listWidget,
{this.child,
this.height = 42,
this.headFontSize,
this.iconData,
this.bottomHeight,
this.screenControl,
Key key})
: super(key: key);
@override
_DropDownWidgetState createState() => _DropDownWidgetState();
}
AnimationController _controller;
Animation<double> curve;
//按钮旋转状态
List<bool> rotateState = [];
class _DropDownWidgetState extends State<DropDownWidget>
with SingleTickerProviderStateMixin {
int tabIndex = 0;
final ScreenControl _screenControl = ScreenControl();
bool showBottom = false;
@override
void initState() {
super.initState();
widget.bottomHeight ??= 400.r;
//展开隐藏控制器,动画初始化
_controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
curve = CurvedAnimation(parent: _controller, curve: Curves.decelerate);
curve = Tween(begin: 0.0, end: widget.bottomHeight).animate(curve)
..addListener(() {
setState(() {
if (curve.value > 0) {
showBottom = true;
} else {
showBottom = false;
}
});
});
rotateState = [];
widget.titles.toList().forEach((element) {
rotateState.add(false);
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
alignment: Alignment.center,
height: widget.height,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: const Color(0xffe4e7ed), width: 0.4.r))),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: getScreenTitle(),
),
),
widget.child,
getBottomScreen()
],
);
}
List<Widget> getScreenTitle() {
List<Widget> widgets = [];
if (widget.titles.isNotEmpty) {
for (int i = 0; i < widget.titles.length; i++) {
widgets.add(Expanded(
flex: 1,
child: DropDownHeadWidget(
widget.titles[i],
getRoState(i),
() {
print("click${rotateState.length}");
setState(() {
tabIndex = i;
for (int j = 0; j < rotateState.length; j++) {
if (i == j) {
if (rotateState[j]) {
rotateState = rotateState.map((e) => false).toList();
_controller.reverse();
} else {
rotateState = rotateState.map((e) => false).toList();
rotateState[j] = !rotateState[j];
_controller.forward();
}
}
}
});
},
headFontSize: widget.headFontSize,
iconData: widget.iconData,
)));
}
} else {
widgets.add(Text(
"数组为空",
style: TextStyle(fontSize: 14.sp),
));
}
return widgets;
}
Widget getBottomScreen() {
return SizedBox(
height: showBottom ? double.infinity : 0.0,
child: GestureDetector(
onTap: () {
_screenControl.screenHide();
},
child: getBottomIndex(),
),
);
}
bool getRoState(int i) {
if (rotateState.isEmpty || rotateState.length < i + 1) {
return false;
}
return rotateState[i];
}
Widget getBottomIndex() {
widget.bottomHeight ??= 400.r;
return Container(
margin: EdgeInsets.only(top: widget.height),
alignment: Alignment.topCenter,
color: Colors.black26,
height: MediaQuery.of(context).size.height - widget.height,
width: double.infinity,
child: Container(
width: double.infinity,
constraints: BoxConstraints(maxHeight: curve.value),
color: Colors.white,
child: widget.listWidget[tabIndex],
),
);
}
}
class ScreenControl {
//自动
void autoDisplay() {
if (_controller.isDismissed) {
_controller.forward();
} else {
_controller.reverse();
rotateState = rotateState.map((e) => false).toList();
}
}
//显示
void screenShow() {
_controller.forward();
}
//隐藏
void screenHide() {
_controller.reverse();
rotateState = rotateState.map((e) => false).toList();
}
}
筛选头部组件
import 'dart:ui';
import 'package:flutter/animation.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// @description 作用:多级筛选item
/// @date: 2021/10/14
/// @author:卢融霜
class DropDownHeadWidget extends StatefulWidget {
String title;
bool isForward;
Function onClick;
double headFontSize;
IconData iconData;
DropDownHeadWidget(this.title, this.isForward, this.onClick,
{this.headFontSize = 12.0, this.iconData = Icons.arrow_drop_down_outlined, key})
: super(key: key);
@override
State<StatefulWidget> createState() {
return _DropDownHeadWidgetState();
}
}
class _DropDownHeadWidgetState extends State<DropDownHeadWidget>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation shAnimation;
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
void didUpdateWidget(covariant DropDownHeadWidget oldWidget) {
if (widget.isForward) {
controller.forward();
} else {
controller.reverse();
}
super.didUpdateWidget(oldWidget);
}
@override
void initState() {
controller = AnimationController(
duration: const Duration(milliseconds: 200), vsync: this);
shAnimation = Tween(begin: .0, end: .5).animate(controller)
..addStatusListener((status) {
setState(() {
if (status == AnimationStatus.completed) {
} else {}
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
TextStyle headTextStyle;
Icon iconData;
if (shAnimation.isCompleted) {
headTextStyle ??=
TextStyle(fontSize: widget.headFontSize, color: Colors.blue);
iconData = Icon(
widget.iconData??Icons.arrow_drop_down_sharp,
color: Colors.blue,
size: 20.sp,
);
//
} else {
headTextStyle = TextStyle(
fontSize: widget.headFontSize, color: const Color(0xff333333));
iconData = Icon(
widget.iconData??Icons.arrow_drop_down_sharp,
size: 20.sp,
color: const Color(0xff333333),
);
}
return InkWell(
onTap: () {
widget.onClick();
},
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: double.infinity,
padding: EdgeInsets.only(left: 5.r, right: 5.r),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text(widget.title, style: headTextStyle),
RotationTransition(
turns: shAnimation,
child: iconData,
)
])),
);
}
}