You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter横屏模式下ModalBottomSheet唤起键盘后Chart组件溢出求助

Flutter横屏模式下ModalBottomSheet唤起键盘后Chart组件溢出问题

在学习Flutter开发费用追踪练习应用时,遇到布局溢出问题:横屏模式下,打开ModalBottomSheet并点击文本框唤起键盘后,弹窗后方的Chart组件会出现溢出情况。

问题演示

以下是BottomSheet组件及根组件的代码:

BottomSheet.dart

import 'package:expense_tracker/model/expense.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class ExpenseAdd extends StatefulWidget {
 const ExpenseAdd({required this.addExpense,required this.removeExpense ,super.key});
 final void Function(Expense expense) addExpense;
 final void Function(Expense expense) removeExpense;

 

 @override
 State<ExpenseAdd> createState() => _ExpenseAddState();
}

class _ExpenseAddState extends State<ExpenseAdd> {
 final TextEditingController _titleController = TextEditingController();
 final TextEditingController _amountController = TextEditingController();
 Category category = Category.leisure;
 DateTime? daTe;

 void _datePickerOverlay() {
   final date = DateTime.now();
   final firstDate = DateTime(date.year - 1);
   

   showDatePicker(
     context: context,
     firstDate: firstDate,
     lastDate: date,
     initialDate: date,
   ).then((selectedDate) {
     setState(() {
       daTe = selectedDate;
     });
   });
 }

 void _checkSubmittion() {
   final String title = _titleController.text;
   final String amount = _amountController.text;

   if (title.trim().isEmpty || amount.trim().isEmpty || daTe == null) {
     showDialog(
       context: context,
       builder: (ctx) {
         return AlertDialog(
           title: Text('Alert'),
           content: Text(
             'Make sure you have entered correct input and left no required fields empty.',
           ),
         );
       },
     );
     return;
   }
   widget.addExpense(Expense(title: title, amount: double.parse(amount), date: daTe!, category: category,),);
   Navigator.pop(context);
   return;

 }

 @override
 void dispose() {
   _titleController.dispose();
   _amountController.dispose();
   super.dispose();
 }

 @override
 Widget build(context) {
 
   return 
      SizedBox(
       height: double.infinity,
        child: SingleChildScrollView(
          child: Padding(
             padding: EdgeInsets.fromLTRB(16, 48, 16, 0),
             child: Column(
               children: [
                 const SizedBox(height: 20),
                 Text('Add New Expense'),
                 const SizedBox(height: 20),
                 TextField(
                    
                   controller: _titleController,
                   decoration: InputDecoration(
                      prefixIcon: Icon(Icons.edit),
                     label: Text('Title'),
                     border: OutlineInputBorder(),
                   ),
                 ),
                 const SizedBox(height: 20),
                Row(
                     children: [
                       Expanded(
                         child: TextField(
                           keyboardType: TextInputType.number,
                           controller: _amountController,
                           decoration: InputDecoration(
            
                             prefixIcon: Icon(Icons.monetization_on_sharp),
                             label: Text('Amount'),
                             border: OutlineInputBorder(
                                
                             ),
                           ),
                         ),
                       ),
                       const SizedBox(width: 20),
                       Flexible(
                         child: Row(
                           children: [
                             Spacer(),
                             Flexible(
                               child: Text(
                                 (daTe == null
                                     ? 'No date selected'
                                     : formatter.format(daTe!)),
                               ),
                             ),
                             IconButton(
                               onPressed: () {
                                 _datePickerOverlay();
                               },
                               icon: Icon(Icons.calendar_month),
                             ),
                           ],
                         ),
                       ),
                     ],
                   ),
                 
                 const SizedBox(height: 20),
                Row(
                     children: [
                       const SizedBox(width: 10),
                       DropdownButton(
                         value: category,
                         items:
                             Category.values.map((category) {
                               return DropdownMenuItem(
                                 value: category,
                                 child: Text(category.name.toString()),
                               );
                             }).toList(),
                         onChanged: (value) {
                           setState(() {
                             category = value!;
                           });
                         },
                       ),
                       Flexible(
                         child: Row(
                           children: [
                             Spacer(),
                             TextButton(
                               onPressed: () {
                                 Navigator.pop(context);
                               },
                               child: Text('Cancel'),
                             ),
                             const SizedBox(width: 10),
                             FilledButton(onPressed: () {
                               _checkSubmittion();
                             }, child: Text('Save')),
                           ],
                         ),
                       ),
                     ],
                   ),
                 
               ],
             ),
           
                
              ),
        ),
      );
 }
}

expense_tracker.dart

import 'package:expense_tracker/model/expense.dart';
import 'package:expense_tracker/widget/chart.dart';
import 'package:expense_tracker/widget/expense_add.dart';
import 'package:expense_tracker/widget/list_of_expense.dart';
import 'package:flutter/material.dart';

class ExpenseTracker extends StatefulWidget {
  const ExpenseTracker({super.key});

  @override
  State<ExpenseTracker> createState() => _ExpenseTrackerState();
}

class _ExpenseTrackerState extends State<ExpenseTracker> {
  final List<Expense> expenses = [
   
  ];

  void _addExpenseOverlay() {
    showModalBottomSheet(
      useSafeArea: true,
      isScrollControlled: true,
      context: context,
      builder: (ctx) {
        return ExpenseAdd(
          addExpense: _addExpense,
          removeExpense: _removeExpense,
        );
      },
    );
  }

  void _addExpense(Expense expense) {
    setState(() {
      expenses.add(expense);
    });
  }

  void _removeExpense(Expense expense) {
    setState(() {
      expenses.remove(expense);
    });
  }

  void _undoDelete(Expense expense, index) {
    setState(() {
      expenses.insert(index, expense);
    });
  }

  @override
  Widget build(context) {
    final width  = MediaQuery.of(context).size.width;
    return Scaffold(
      resizeToAvoidBottomInset: true,
      appBar: AppBar(
        title: Text('XP Tracker'),
        actions: [
          IconButton(
            onPressed: () {
              _addExpenseOverlay();
            },
            icon: Icon(Icons.add),
          ),
        ],
      ),
      body: Center(
        child: width < 600 ? Column(
          children: [
            Chart(expenses: expenses),
            (expenses.isEmpty
                ? Center(child: Text('No Expense found.'))
                : Expanded(
                  child: ListOfExpense(
                    expenses: expenses,
                    removeExpense: _removeExpense,
                    undoDelete: _undoDelete,
                  ),
                )),
          ],
        ) : Row(
          children: [
            Expanded(child: Chart(expenses: expenses)),
            (expenses.isEmpty
                ? Center(child: Text('No Expense found.'))
                : Expanded(
                  child: ListOfExpense(
                    expenses: expenses,
                    removeExpense: _removeExpense,
                    undoDelete: _undoDelete,
                  ),
                )),
          ],
        ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Sameer Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:24:50