0

我在我的颤动应用程序中使用了一个 BottomNavigationBar,其中保存了每个选项卡的状态,并且我还使我的 BottomNavigationBar 可见,除了具有文本输入的屏幕。我做到了,但是当我想添加文本输入时出现了一个大问题。我无法专注于我的键盘。它会在不到一秒钟的时间内启动并返回。已经看到了一些人的解决方案,但它对我不起作用。我真的很高兴在这里得到帮助以修复键盘故障。谢谢

当我单击输入文本字段时,这会出现在我的终端上

    W/IInputConnectionWrapper(29345): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(29345): requestCursorAnchorInfo on inactive InputConnection
3
W/IInputConnectionWrapper(29345): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(29345): getSelectedText on inactive InputConnection
D/InputConnectionAdaptor(29345): The input method toggled cursor monitoring on
I/SurfaceView(29345): updateWindow -- setFrame, this = io.flutter.embedding.android.FlutterSurfaceView{f394ae6 V.E...... ......I. 0,0-720,1204}

这是我的颤振医生,如果您需要更多文件,请告诉我。谢谢。

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.0.6, on Microsoft Windows [Version 10.0.19043.985], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[X] Chrome - develop for the web (Cannot find Chrome executable at .\Google\Chrome\Application\chrome.exe)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[√] Android Studio (version 4.1.0)
[√] VS Code (version 1.56.2)
[√] Connected device (2 available)
> 

这是我的主页类文件

    import 'package:flutter/material.dart';
    import 'package:my_time_tracker/app/home/account/account_page.dart';
    import 'package:my_time_tracker/app/home/entries/entries_page.dart';
    import 'package:my_time_tracker/app/home/home_scaffold.dart';
    import 'package:my_time_tracker/app/home/jobs/edit_job_page.dart';
    import 'package:my_time_tracker/app/home/tab_item.dart';
    import 'jobs/jobs_page.dart';



class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);

@override
_HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
 TabItem _currentTab = TabItem.jobs;
 int _selectedIndex = 0;

 List<GlobalKey<NavigatorState>> navigatorKeys = [
 GlobalKey<NavigatorState>(),
 GlobalKey<NavigatorState>(),
 GlobalKey<NavigatorState>(),
 ];

  Map<int, Widget> get widgets {
   return {
    0: JobsPage(),
    1: EntriesPage.create(context),
    2: AccountPage(),
   };
 }


 void _onItemTapped(int index) {
   if (_selectedIndex == index) {
   navigatorKeys[index].currentState.popUntil((route) => route.isFirst);
    } else {
     setState(() {
    _selectedIndex = index;
   });
 }
}

 @override
 Widget build(BuildContext context) {
 return WillPopScope(
   onWillPop: () async {
     final isFirstRouteInCurrentTab =
         !await navigatorKeys[_selectedIndex].currentState.maybePop();
     print(
        'isFirstrouteInCurrentTab:' + isFirstRouteInCurrentTab.toString());
     return isFirstRouteInCurrentTab;
   },
   child: HomeScaffold(
     navigatorKeys: navigatorKeys,
     currentTabItem: _currentTab,
     onSelectTab: _onItemTapped,
     currentIndex: _selectedIndex,
     widget: widgets,
   ),
  );
 }
}

这是我的 HomeScaffold 课程

import 'package:flutter/material.dart';
import 'package:my_time_tracker/app/home/account/account_page.dart';
import 'package:my_time_tracker/app/home/entries/entries_page.dart';
import 'package:my_time_tracker/app/home/jobs/jobs_page.dart';
import 'package:my_time_tracker/app/home/tab_item.dart';
import 'package:my_time_tracker/common_widgets/custom_text_style.dart';

class HomeScaffold extends StatefulWidget {
  const HomeScaffold({
    Key key,
    @required this.currentTabItem,
    @required this.onSelectTab,
    @required this.navigatorKeys,
    @required this.currentIndex,
    @required this.widget,
  }) : super(key: key);

  final TabItem currentTabItem;
  final int currentIndex;
  final ValueChanged<int> onSelectTab;
  final Map<int, Widget> widget;

  final List<GlobalKey<NavigatorState>> navigatorKeys;

  @override
  _HomeScaffoldState createState() => _HomeScaffoldState();
}

class _HomeScaffoldState extends State<HomeScaffold> {
 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      bottomNavigationBar: BottomNavigationBar(
        items: [
          _buildItem(TabItem.jobs),
          _buildItem(TabItem.entries),
          _buildItem(TabItem.account),
        ],
        type: BottomNavigationBarType.shifting,
        onTap: (index) => widget.onSelectTab(index),
        selectedItemColor: Colors.teal,
        unselectedItemColor: Colors.grey[700].withOpacity(.60),
        backgroundColor: Colors.white,
        elevation: 5.0,
        currentIndex: widget.currentIndex,
        showUnselectedLabels: true,
        selectedLabelStyle: CustomTextStyles.textStyleBold(),
      ),
      body: Stack(
        children: [
          _buildOffStageNavigator(0),
          _buildOffStageNavigator(1),
          _buildOffStageNavigator(2),
        ],
      ),
    );
  }

  BottomNavigationBarItem _buildItem(TabItem tabItem) {
    final itemData = TabItemData.allTabs[tabItem];
    return BottomNavigationBarItem(
      icon: Icon(itemData.icon),
      label: itemData.label,
      backgroundColor: itemData.backgroundColor,
    );
  }

  Map<String, WidgetBuilder> _routeBuilders(BuildContext context, int index) {
    return {
      '/': (context) {
        return [
          JobsPage(),
          EntriesPage.create(context),
          AccountPage(),
        ].elementAt(index);
      }
    };
  }

  Widget _buildOffStageNavigator(int index) {
    var routeBuilders = _routeBuilders(context, index);

    return Offstage(
      offstage: widget.currentIndex != index,
      child: Navigator(
        key: widget.navigatorKeys[index],
        onGenerateRoute: (routeSettings) {
          return MaterialPageRoute(
            builder: (context) => routeBuilders[routeSettings.name](context),
          );
        },
      ),
    );
  }
}

这是我的 TabItem 类

import 'package:flutter/material.dart';

enum TabItem { jobs, entries, account }

class TabItemData {
  const TabItemData({
    @required this.label,
    @required this.icon,
    this.backgroundColor,
  });

  final String label;
  final IconData icon;
  final Color backgroundColor;

  static const Map<TabItem, TabItemData> allTabs = {
    TabItem.jobs: TabItemData(
      label: 'Jobs',
      icon: Icons.work,
      //backgroundColor: Colors.white,
    ),
    TabItem.entries: TabItemData(
      label: 'Entries',
      icon: Icons.view_headline,
      //backgroundColor: Colors.tealAccent,
    ),
    TabItem.account: TabItemData(
      label: 'Account',
      icon: Icons.account_circle,
      //backgroundColor: Colors.lightBlueAccent,
    ),
  };
}

这是我的 EditJob 页面,其中包含文本输入

import 'package:flutter/material.dart';
import 'package:my_time_tracker/common_widgets/custom_text_style.dart';
//import 'package:my_time_tracker/common_widgets/firebase_exception_alert_dialog.dart';
import 'package:my_time_tracker/common_widgets/form_submit_button.dart';
import 'package:my_time_tracker/common_widgets/platform_alert_dialog.dart';
import 'package:my_time_tracker/common_widgets/show_snack_bar.dart';
import 'package:my_time_tracker/services/database.dart';
import 'package:provider/provider.dart';

import '../models/job.dart';

class EditJobPage extends StatefulWidget {
  final Database database;
  final Job job;
  final ValueChanged<int> onPush;

  const EditJobPage({Key key, @required this.database, this.job, this.onPush})
      : super(key: key);

  static Future<void> show(BuildContext context, {Job job}) async {
    final database = Provider.of<Database>(context, listen: false);
    await Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(
      fullscreenDialog: true,
      builder: (context) => EditJobPage(
        database: database,
        job: job,
      ),
    ));
  }

  @override
  _EditJobPageState createState() => _EditJobPageState();
}

class _EditJobPageState extends State<EditJobPage> {
  final _formKey = GlobalKey<FormState>();

  String _name;
  int _ratePerHour;
  bool isLoading = false;

  @override
  void initState() {
    super.initState();
    if (widget.job != null) {
      _name = widget.job.name;
      _ratePerHour = widget.job.ratePerHour;
    }
  }

  bool _validateAndSaveForm() {
    final form = _formKey.currentState;
    if (form.validate()) {
      form.save();
      return true;
    }
    return false;
  }

  String get scaffoldContent {
    if (widget.job != null) {
      return '${widget.job.name} updated successfully.';
    } else {
      return '$_name added successfully.';
    }
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(
        iconTheme: IconThemeData(color: Colors.teal),
        backgroundColor: Colors.white,
        title: Text(
          widget.job == null ? 'New Job' : 'Edit Job',
          style: CustomTextStyles.textStyleTitle(
            fontSize: size.height * 0.035,
            color: Colors.teal,
          ),
        ),
        centerTitle: true,
        elevation: 0.0,
      ),
      body: _buildContent(),
      backgroundColor: Colors.white,
    );
  }

  InputDecoration _buildInputDecoration(
    String labelText,
    IconData icon,
    bool value,
  ) {
    Size size = MediaQuery.of(context).size;
    return InputDecoration(
      labelText: labelText,
      labelStyle: CustomTextStyles.textStyleBold(fontSize: size.height * 0.025),
      icon: Icon(
        icon,
        color: Colors.teal[700],
        size: size.height * 0.05,
      ),
      enabled: value,
    );
  }

  Widget _buildContent() {
    return SingleChildScrollView(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Card(
          elevation: 5.0,
          child: Column(
            children: [
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: _buildForm(),
              ),
              SizedBox(
                height: 5.0,
              ),
              SizedBox(
                width: MediaQuery.of(context).size.width * 0.62,
                child: FormSubmitButton(
                  onPressed: isLoading ? null : _submit,
                  text: 'Save',
                ),
              ),
              SizedBox(
                height: 15.0,
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildForm() {
    return Form(
      key: _formKey,
      autovalidateMode: AutovalidateMode.onUserInteraction,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: _buildFormChildren(),
      ),
    );
  }

  List<Widget> _buildFormChildren() {
    return [
      _buildJobNameField(),
      _buildJobRateField(),
      SizedBox(
        height: 15.0,
      )
    ];
  }

  Widget _buildJobNameField() {
    return TextFormField(
      decoration: _buildInputDecoration(
        'Job name',
        Icons.work,
        isLoading == false,
      ),
      initialValue: _name,
      validator: (value) =>
          value == null || value.isEmpty ? 'Name can\'t be empty' : null,
      textInputAction: TextInputAction.next,
      textCapitalization: TextCapitalization.words,
      onSaved: (value) => _name = value,
    );
  }

  Widget _buildJobRateField() {
    return TextFormField(
      decoration: _buildInputDecoration(
        'Rate Per Hour',
        Icons.attach_money,
        isLoading == false,
      ),
      initialValue: _ratePerHour != null ? '$_ratePerHour' : '',
      keyboardType:
          TextInputType.numberWithOptions(decimal: false, signed: false),
      onSaved: (value) => _ratePerHour = int.tryParse(value) ?? 0,
      onEditingComplete: _submit,
    );
  }

  Future<void> _submit() async {
    //Future.delayed(Duration(seconds: 5));
    if (_validateAndSaveForm()) {
      print('Error doesnt occur here0');
      setState(() {
        isLoading = true;
      });
      print('Error doesnt occur here1');
      try {
        final jobs = await widget.database
            .jobsStream()
            .first
            .onError((error, stackTrace) {
          return Future.error(error);
        });
        print('Error doesnt occur here2');
        final allNames = jobs.map((job) => job.name).toList();
        if (widget.job != null) {
          allNames.remove(widget.job.name);
        }
        if (allNames.contains(_name)) {
          PlatformAlertDialog(
            title: 'Job already exist',
            content: 'Please use a different job name.',
            defaultActionText: 'Ok',
          ).show(context);
        } else {
          final id = widget.job?.id ?? documentIdFromCurrentDate();
          final job = Job(
            id: id,
            name: _name,
            ratePerHour: _ratePerHour,
          );
          await widget.database.setJob(job);
          print('Error doesnt occur here5');
          Navigator.of(context).pop();
          MyCustomSnackBar(
            enabled: widget.job == null ? true : false,
            text: scaffoldContent,
            onPressed: () => widget.database.deleteJob(job),
          ).show(context);
        }
      } catch (e) {
        // FirebaseExceptionAlertDialog(title: 'Operation Failed', exception: e)
        //     .show(context);
        print(e);
      }
      setState(() {
        isLoading = false;
      });
    }
  }
}
4

0 回答 0