flutter弹窗高度过高,在弹出键盘后布局溢出问题

发布于:2024-07-11 ⋅ 阅读:(19) ⋅ 点赞:(0)

1.最外层套脚手架控件:Scaffold,设置背景为透明或半透明。目的是将弹出键盘是的高度计算调整交给Scaffold。(直接用SingleChildScrollView仍然会出现布局溢出)
2.使用SingleChildScrollView包裹弹窗布局。
示例:

import 'package:jade/bean/createExpParam/BuyChargeDetail.dart';
import 'package:jade/configs/PathConfig.dart';
import 'package:jade/customWidget/CusBehavior.dart';
import 'package:jade/utils/JadeColors.dart';
import 'package:jade/utils/Utils.dart';
import 'package:util/easy_loading_util.dart';
import 'package:util/navigator_util.dart';
import 'package:util/number_text_input_formatter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class CellPriceInfo{
  int monthNum; //月数
  double price;//价格
  double originPrice;//原价
//  double oneMonthPrice;//单月价格
  bool isSelect; //是否选中
  TextEditingController priceController;
  TextEditingController originPriceController;
  CellPriceInfo({this.monthNum,this.price,this.originPrice,this.isSelect = false,this.priceController,this.originPriceController}){
    this.priceController = priceController ?? TextEditingController();
    this.originPriceController = originPriceController ?? TextEditingController();
  }
}

class FillInCellPriceDialog extends StatefulWidget{
  final int showNum;
  final Function sureCallBack;
  final List<BuyChargeDetail> viewedPriceInfoList;
  const FillInCellPriceDialog({this.sureCallBack,this.showNum,this.viewedPriceInfoList});
  
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _FillInCellPriceDialog();
  }
}

class _FillInCellPriceDialog extends State<FillInCellPriceDialog>{

  List<CellPriceInfo> _priceInfoList = []; //绘制ui的数组
  List<BuyChargeDetail> _buyChargeDetailList = [];//从弹窗返出去的数组

  
  void initState() {
    // TODO: implement initState
    super.initState();
    _priceInfoList = [CellPriceInfo(monthNum: 10007),CellPriceInfo(monthNum: 10014),CellPriceInfo(monthNum: 1),CellPriceInfo(monthNum: 3),CellPriceInfo(monthNum: 6),CellPriceInfo(monthNum: 12)];

    if(widget.viewedPriceInfoList != null && widget.viewedPriceInfoList.isNotEmpty){
      for (var viewedPriceInfo in widget.viewedPriceInfoList) {
        for (var priceInfo in _priceInfoList) {
         if(viewedPriceInfo.monthNum == priceInfo.monthNum){
           priceInfo.priceController.text = '${viewedPriceInfo.price}';
           priceInfo.originPriceController.text = '${viewedPriceInfo.originPrice ?? ''}';
           priceInfo.isSelect = true;
         }
        }
      }
    }
  }

  
  void dispose() {
    // TODO: implement dispose
    if(_priceInfoList.isNotEmpty){
      _priceInfoList.forEach((element) {
        element.priceController.dispose();
        element.originPriceController.dispose();
      });
    }
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      backgroundColor: Colors.transparent,
      body:ScrollConfiguration(
          behavior: CusBehavior(),
          child: SingleChildScrollView(
              child: Container(
                alignment: Alignment.center,
                margin: EdgeInsets.only(top: Utils().screenWidth(context) * 0.18),
                child: UnconstrainedBox(
                    child: Container(
                        alignment: Alignment.center,
                        width: Utils().screenWidth(context) * 0.76,
                        padding: EdgeInsets.only(top: 40.w, bottom: 30.w),
                        decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10)),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Container(
                              padding: EdgeInsets.only(left: 30.w, right: 40.w,),
                              child: Text(widget.showNum == null ? '展位(格口)价格设置' : '${widget.showNum}号展位(格口)价格设置',
                                  style: TextStyle(color: JadeColors.grey_2,fontSize: 30.sp,fontWeight: FontWeight.w600)),
                            ),
                            Container(
                              padding: EdgeInsets.only(left: 30.w, right: 40.w,),
                              child: Text('需设置原价与活动价(即实际售卖价格)',style: TextStyle(color: JadeColors.grey,fontSize: 24.sp,fontWeight: FontWeight.w600)),
                            ),
                            Container(height: 1,color: JadeColors.grey_5,margin: EdgeInsets.only(top: 30.w,bottom: 30.w)),
                            _listView(),
                            SizedBox(height: 40.w),
                            _btnView()
                          ],
                        )
                    )),
              )
          ),
      )
    );
  }

  _listView(){
    return ListView.separated(
          itemBuilder: (context, index) {
            return _itemView(index);
          },
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          separatorBuilder: (context,index) =>Container(height: 30.w,),
          itemCount: _priceInfoList.length)
      ;
  }

  _itemView(int index){
    return Container(
      padding: EdgeInsets.only(left: 30.w, right: 40.w),
      child: Row(
        children: [
          GestureDetector(
            child: Container(
              color: Colors.white,
              padding: EdgeInsets.all(5),
              child: Image.asset(_priceInfoList[index].isSelect ? PathConfig.iconSelectBlue2 : PathConfig.iconUnselect, width: 34.w,height: 34.w),
            ),
            onTap: (){
              setState(() {
                _priceInfoList[index].isSelect = !_priceInfoList[index].isSelect;
              });
            },
          ),
          SizedBox(width: Utils().monthNumToDayNum(_priceInfoList[index].monthNum) > 99 ? 24.w : Utils().monthNumToDayNum(_priceInfoList[index].monthNum) < 10 ? 50.w :40.w),
          Text('${Utils().monthNumToDayNum(_priceInfoList[index].monthNum)}天:',
              style: TextStyle(color: JadeColors.grey_3,fontSize: 28.sp)),
          Expanded(child: Column(
            children: [
              Container(
                  width: double.infinity,
                  height: 54.w,
                  padding: EdgeInsets.symmetric(horizontal: 20.w),
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(5),
                      border: Border.all(width: 1.w,color: JadeColors.grey)
                  ),
                  child: TextField(
                    enabled: _priceInfoList[index].isSelect,
                    textAlign: TextAlign.start,
                    controller: _priceInfoList[index].priceController,
                    style: TextStyle(fontSize: 24.sp, color: JadeColors.grey_2),
                    keyboardType: TextInputType.number,
                    textInputAction: TextInputAction.done,
                    inputFormatters: [
                      NumberTextInputFormatter(2),
                      FilteringTextInputFormatter(RegExp("[0-9.]"), allow: true),
                    ],
                    maxLines: 1,
                    maxLength: 40,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: Colors.white,
                        isCollapsed: true,
                        isDense: true,
                        contentPadding: EdgeInsets.zero,
                        hintText: '请输入活动价(必填)',
                        hintStyle: TextStyle(
                          fontSize: 24.sp,
                          color: JadeColors.grey,
                        ),
                        disabledBorder: OutlineInputBorder(
                            borderSide: BorderSide.none,
                            borderRadius: BorderRadius.circular(8.w)
                        ),
                        enabledBorder: OutlineInputBorder(
                            borderSide: BorderSide.none),
                        focusedBorder: OutlineInputBorder(
                            borderSide: BorderSide.none),
                        border: OutlineInputBorder(
                            borderSide: BorderSide.none),
                        counterText: ''
                    ),
                    onChanged: (value) {
                      if(value.isNotEmpty){
                        double _parsedDouble = double.tryParse(value);
                        if(_parsedDouble == null || _parsedDouble < 1){
                          esLoadingToast('活动价格不能低于1元');
                        }
                      }
                    },
                    cursorColor: JadeColors.grey,
                  )),
              SizedBox(height: 10.w),
              Container(
                  width: double.infinity,
                  height: 54.w,
                  padding: EdgeInsets.symmetric(horizontal: 20.w),
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(5),
                      border: Border.all(width: 1.w,color: JadeColors.grey)
                  ),
                  child: TextField(
                    enabled: _priceInfoList[index].isSelect,
                    textAlign: TextAlign.start,
                    controller: _priceInfoList[index].originPriceController,
                    style: TextStyle(fontSize: 24.sp, color: JadeColors.grey_2),
                    keyboardType: TextInputType.number,
                    textInputAction: TextInputAction.done,
                    inputFormatters: [
                      NumberTextInputFormatter(2),
                      FilteringTextInputFormatter(RegExp("[0-9.]"), allow: true),
                    ],
                    maxLines: 1,
                    maxLength: 40,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: Colors.white,
                        isCollapsed: true,
                        isDense: true,
                        contentPadding: EdgeInsets.zero,
                        hintText: '请输入原价',
                        hintStyle: TextStyle(
                          fontSize: 24.sp,
                          color: JadeColors.grey,
                        ),
                        disabledBorder: OutlineInputBorder(
                            borderSide: BorderSide.none,
                            borderRadius: BorderRadius.circular(8.w)
                        ),
                        enabledBorder: OutlineInputBorder(
                            borderSide: BorderSide.none),
                        focusedBorder: OutlineInputBorder(
                            borderSide: BorderSide.none),
                        border: OutlineInputBorder(
                            borderSide: BorderSide.none),
                        counterText: ''
                    ),
                    onChanged: (value) {},
                    cursorColor: JadeColors.grey,
                  )),
            ],
          ))
        ],
      )
    );
  }

  _btnView(){
    return Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        GestureDetector(
            child: Container(
              height: 44.w,
              padding: EdgeInsets.symmetric(horizontal: 40.w),
              margin: EdgeInsets.only(right: 20.w),
              alignment: Alignment.center,
              decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(20),
                  border: Border.all(color: JadeColors.blue_2,width: 1.w)
              ),
              child: Text('取消',style: TextStyle(color: JadeColors.blue_2,fontSize: 26.sp)),
            ),onTap: (){
          NavigatorUtil.pop();
        }
        ),
        GestureDetector(
          child: Container(
            height: 44.w,
            padding: EdgeInsets.symmetric(horizontal: 40.w),
            margin: EdgeInsets.only(right: 40.w),
            alignment: Alignment.center,
            decoration: BoxDecoration(
                color: JadeColors.blue_2,
                borderRadius: BorderRadius.circular(20)
            ),
            child: Text('确定',style: TextStyle(color: Colors.white,fontSize: 26.sp)),
          ),
          onTap: () async {
            print('_getPriceData= ${_getPriceData()}');
            if(_getPriceData() == null || !_getPriceData()){
              return;
            }
            if(widget.sureCallBack != null){
              widget.sureCallBack(_buyChargeDetailList);
            }
            NavigatorUtil.pop();
          },
        )
      ],
    );
  }

  //要返出去的参数
  _getPriceData(){
    _buyChargeDetailList.clear();
    bool _canCallback = false;
    for(var element in _priceInfoList){
      if(element.isSelect){
        String _price = element.priceController.text.trim();
        String _originPrice = element.originPriceController.text.trim();
        double _parsedPriceDouble = double.tryParse(_price);
        double _parsedOriginPriceDouble = double.tryParse(_originPrice);
        if(_price.isEmpty){
          esLoadingToast('请输入${Utils().monthNumToDayNum(element.monthNum)}天活动价');
          _canCallback = false;
          return;
        }else if(_price.isNotEmpty && _parsedPriceDouble == null || _parsedPriceDouble < 1){
          esLoadingToast('${Utils().monthNumToDayNum(element.monthNum)}天活动价不能低于1元');
          _canCallback = false;
          return;
        }else{
          _canCallback = true;
        }
        if(_parsedOriginPriceDouble != null && _parsedOriginPriceDouble < 1){
          esLoadingToast('${Utils().monthNumToDayNum(element.monthNum)}天原价不能低于1元');
          _canCallback = false;
          return;
        }
        BuyChargeDetail _buyChargeDetail = BuyChargeDetail(
          monthNum: element.monthNum,
          price: double.parse(_price),
          originPrice: _originPrice.isNotEmpty ? double.parse(_originPrice) : null,
        );
        _buyChargeDetailList.add(_buyChargeDetail);
      }
    }
    return _canCallback;
  }


}