flutter

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,
            )
          ])),
    );
  }
}

上一篇下一篇

猜你喜欢

热点阅读