Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter 颤振:为什么表单(编辑页面)在提交并保存表单数据之后,在导航到其他地方之前重新加载_Flutter_Navigation_Widget - Fatal编程技术网

Flutter 颤振:为什么表单(编辑页面)在提交并保存表单数据之后,在导航到其他地方之前重新加载

Flutter 颤振:为什么表单(编辑页面)在提交并保存表单数据之后,在导航到其他地方之前重新加载,flutter,navigation,widget,Flutter,Navigation,Widget,我正在编写一个教程,并尝试按原样编写代码。但是,在提交表单之后,就在导航之前,它尝试重新加载表单,而我没有这样的意图。我使用标签创建产品,并加载新页面编辑产品 main.dart import 'package:scoped_model/scoped_model.dart'; // import 'package:flutter/rendering.dart'; import './pages/auth.dart'; import './pages/products_admin.dart';

我正在编写一个教程,并尝试按原样编写代码。但是,在提交表单之后,就在导航之前,它尝试重新加载表单,而我没有这样的意图。我使用标签创建产品,并加载新页面编辑产品

main.dart

import 'package:scoped_model/scoped_model.dart';
// import 'package:flutter/rendering.dart';

import './pages/auth.dart';
import './pages/products_admin.dart';
import './pages/products.dart';
import './pages/product.dart';

import './scoped-models/products.dart';

void main() {
  // debugPaintSizeEnabled = true;
  // debugPaintBaselinesEnabled = true;
  // debugPaintPointersEnabled = true;
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return ScopedModel<ProductsModel>(
      model: ProductsModel(),
      child: MaterialApp(
        // debugShowMaterialGrid: true,
        theme: ThemeData(
            brightness: Brightness.light,
            primarySwatch: Colors.deepOrange,
            accentColor: Colors.green,
            buttonTheme: ButtonThemeData(
              buttonColor: Colors.deepOrange,
              textTheme: ButtonTextTheme.primary,
            )),

//      home: AuthPage(),
        routes: {
          '/': (BuildContext context) => AuthPage(),
          '/products': (BuildContext context) => ProductsPage(),
          '/admin': (BuildContext context) => ProductsAdminPage(),
        },
        onGenerateRoute: (RouteSettings settings) {
          final List<String> pathElements = settings.name.split('/');
          if (pathElements[0] != '') {
            return null;
          }
          if (pathElements[1] == 'product') {
            final int index = int.parse(pathElements[2]);
            return MaterialPageRoute<bool>(
              builder: (BuildContext context) {
                return ProductPage(index);
              },
            );
          }
          return null;
        },
        onUnknownRoute: (RouteSettings settings) {
          return MaterialPageRoute(
            builder: (BuildContext context) => ProductsPage(),
          );
        },
      ),
    );
  }
}
import 'package:flutter/material.dart';

import '../widgets/navigation/products_admin.dart';

import './product_list.dart';
import 'product_edit.dart';


class ProductsAdminPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        drawer: NavigationProductsAdminPage(),
        appBar: AppBar(
          title: Text('Manage Products'),
          bottom: TabBar(
            tabs: [
              Tab(
                icon: Icon(Icons.create),
                text: 'Create Product',
              ),
              Tab(
                icon: Icon(Icons.list),
                text: 'My Products',
              ),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            ProductEditPage(),
            ProductListPage(),
          ],
        ),
      ),
    );
  }
}
标签页产品\管理dart

import 'package:scoped_model/scoped_model.dart';
// import 'package:flutter/rendering.dart';

import './pages/auth.dart';
import './pages/products_admin.dart';
import './pages/products.dart';
import './pages/product.dart';

import './scoped-models/products.dart';

void main() {
  // debugPaintSizeEnabled = true;
  // debugPaintBaselinesEnabled = true;
  // debugPaintPointersEnabled = true;
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return ScopedModel<ProductsModel>(
      model: ProductsModel(),
      child: MaterialApp(
        // debugShowMaterialGrid: true,
        theme: ThemeData(
            brightness: Brightness.light,
            primarySwatch: Colors.deepOrange,
            accentColor: Colors.green,
            buttonTheme: ButtonThemeData(
              buttonColor: Colors.deepOrange,
              textTheme: ButtonTextTheme.primary,
            )),

//      home: AuthPage(),
        routes: {
          '/': (BuildContext context) => AuthPage(),
          '/products': (BuildContext context) => ProductsPage(),
          '/admin': (BuildContext context) => ProductsAdminPage(),
        },
        onGenerateRoute: (RouteSettings settings) {
          final List<String> pathElements = settings.name.split('/');
          if (pathElements[0] != '') {
            return null;
          }
          if (pathElements[1] == 'product') {
            final int index = int.parse(pathElements[2]);
            return MaterialPageRoute<bool>(
              builder: (BuildContext context) {
                return ProductPage(index);
              },
            );
          }
          return null;
        },
        onUnknownRoute: (RouteSettings settings) {
          return MaterialPageRoute(
            builder: (BuildContext context) => ProductsPage(),
          );
        },
      ),
    );
  }
}
import 'package:flutter/material.dart';

import '../widgets/navigation/products_admin.dart';

import './product_list.dart';
import 'product_edit.dart';


class ProductsAdminPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        drawer: NavigationProductsAdminPage(),
        appBar: AppBar(
          title: Text('Manage Products'),
          bottom: TabBar(
            tabs: [
              Tab(
                icon: Icon(Icons.create),
                text: 'Create Product',
              ),
              Tab(
                icon: Icon(Icons.list),
                text: 'My Products',
              ),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            ProductEditPage(),
            ProductListPage(),
          ],
        ),
      ),
    );
  }
}
问题页面product\u edit.dart(提交后,导航前,尝试重新加载表单,并给出材料错误,当前列表索引为空

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import '../models/product.dart';
import '../scoped-models/products.dart';

class ProductEditPage extends StatefulWidget {
  @override
  _ProductEditPageState createState() => _ProductEditPageState();
}

// good habit to set your variables as private by prefixing with _, inside the state of a widget
class _ProductEditPageState extends State<ProductEditPage> {
  final Map<String, dynamic> _formData = {
    'title': null,
    'description': null,
    'price': null,
    'image': 'assets/food.jpg',
  };
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return ScopedModelDescendant<ProductsModel>(
      builder: (BuildContext context, Widget child, ProductsModel model) {
        Product selectedProduct = model.selectedProduct;
        final Widget pageContent = _buildPageContent(context, selectedProduct);
        print('[selected index] ' + model.selectedProductIndex.toString());
        return model.selectedProductIndex == null
            ? pageContent
            : Scaffold(
                appBar: AppBar(
                  title: Text('Edit Product'),
                ),
                body: pageContent,
              );
      },
    );
  }

  Widget _buildTitleTextField(Product selectedProduct) {
    print('[just before title text field]');
    return TextFormField(
      initialValue: selectedProduct == null ? '' : selectedProduct.title,
      decoration: InputDecoration(
        labelText: 'Product Title',
      ),
      validator: (value) {
        if (value.isEmpty || value.length < 5) {
          return 'Title is required and should be 5+ characters.';
        }
        return null;
      },
      onSaved: (value) {
        _formData['title'] = value;
      },
    );
  }

  Widget _buildDescriptionTextField(Product selectedProduct) {
    print('[just before description text field]');
    return TextFormField(
      initialValue: selectedProduct == null ? '' : selectedProduct.description,
      decoration: InputDecoration(
        labelText: 'Product Description',
      ),
      validator: (value) {
        if (value.isEmpty || value.length < 10) {
          return 'Description is required and should be 10+ characters.';
        }
        return null;
      },
      maxLines: 4,
      onSaved: (value) {
        _formData['description'] = value;
      },
    );
  }

  Widget _buildPriceTextField(Product selectedProduct) {
    print('[just before price text field]');
    return TextFormField(
      initialValue:
          selectedProduct == null ? '' : selectedProduct.price.toString(),
      decoration: InputDecoration(
        labelText: 'Product Price',
      ),
      validator: (value) {
        if (value.isEmpty ||
            !RegExp(r'^(?:[1-9]\d*|0)?(?:\.\d+)?$').hasMatch(value)) {
          return 'Price is required and should be a number.';
        }
        return null;
      },
      keyboardType: TextInputType.number,
      onSaved: (String value) {
        _formData['price'] = double.parse(value);
      },
    );
  }

  _buildSubmitButton() {
    return ScopedModelDescendant<ProductsModel>(
      builder: (BuildContext context, Widget child, ProductsModel model) {
        return RaisedButton(
          child: Text('Save'),
          onPressed: () => _submitForm(model.addProduct, model.updateProduct,
              model.selectedProductIndex),
        );
      },
    );
  }

  void _submitForm(Function addProduct, Function updateProduct,
      [int selectedProductIndex]) {
    if (!_formKey.currentState.validate()) {
      // this will force post-validation error messages to show and not submit further
      return;
    }
    _formKey.currentState
        .save(); // this will initiate the onSaved event of formfields

    if (selectedProductIndex == null) {
      addProduct(
        Product(
            title: _formData['title'],
            description: _formData['description'],
            price: _formData['price'],
            image: _formData['image']),
      );
    } else {
      updateProduct(
        Product(
            title: _formData['title'],
            description: _formData['description'],
            price: _formData['price'],
            image: _formData['image']),
      );
    }

    // pushReplacementNamed prevents it from going back by pressing BACK buttons
    print('[So far so good] before navigation');
    Navigator.pushReplacementNamed(context, '/products');
    print('[So far so good] after navigation');
  }

  Widget _buildPageContent(BuildContext context, Product selectedProduct) {
    final deviceWidth = MediaQuery.of(context).size.width;
    final targetWidth = deviceWidth > 550.0 ? 500.0 : deviceWidth * 0.95;
    final targetPadding = deviceWidth - targetWidth;
    print('[just before gesture detector]');
    return GestureDetector(
      onTap: () {
        // hide keyboard if container is tapped anywhere other than form
        FocusScope.of(context).requestFocus(FocusNode());
      },
      child: Container(
        padding: EdgeInsets.all(10.0),
        // Use ListView.builder only when the listCount is unknown and can grow
        child: Form(
          key: _formKey,
          child: ListView(
            // so the leftover space is distributed on left and right evenly
            padding: EdgeInsets.symmetric(horizontal: targetPadding / 2),
            children: [
              _buildTitleTextField(selectedProduct),
              _buildDescriptionTextField(selectedProduct),
              _buildPriceTextField(selectedProduct),
              SizedBox(
                height: 20.0,
              ),
              _buildSubmitButton(),
            ],
          ),
        ),
      ),
    );
  }
}
IMP代码无论如何都不会中断。只会给出错误,并根据需要导航到路由“/products”。此外,它不会在错误后执行/输出任何打印(“…”)行


更新我注意到它在保存/提交表单后再次进入ScopedModeldeCentent
ScopedModeldScentant的builder()(builder:(BuildContext context,Widget child,ProductsModel model model)
,而不是
的build()方法
就在它上面一行。有人能解释一下这里发生了什么吗?

这就是我解决问题的方法。我将
手势检测器
包装在
材料
小部件中

      child: GestureDetector(
        onTap: () {
          // hide keyboard if container is tapped anywhere other than form
          FocusScope.of(context).requestFocus(FocusNode());
        },
        child: Container(
          padding: EdgeInsets.all(10.0),
          // Use ListView.builder only when the listCount is unknown and can grow
          child: Form(
            key: _formKey,
            child: ListView(
              // so the leftover space is distributed on left and right evenly
              padding: EdgeInsets.symmetric(horizontal: targetPadding / 2),
              children: [
                _buildTitleTextField(selectedProduct),
                _buildDescriptionTextField(selectedProduct),
                _buildPriceTextField(selectedProduct),
                SizedBox(
                  height: 20.0,
                ),
                _buildSubmitButton(),
              ],
            ),
          ),
        ),
      ),
    );

我如何在这里捕获异常?虽然修复了一个解决方法,但我不喜欢它。我已经用
材料
包装了
手势检测器
(如异常消息中建议的那样).但是我不明白为什么它会两次呈现
ScopedModelSchedent
builder..一次是在表单加载时,一次是在表单保存时。有人能指导我吗?
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 1.20.1, on Microsoft Windows [Version 10.0.18362.1082], locale en-US)

[√] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
[√] Android Studio (version 4.0)
[√] VS Code (version 1.48.2)
[√] Connected device (1 available)

• No issues found!
      child: GestureDetector(
        onTap: () {
          // hide keyboard if container is tapped anywhere other than form
          FocusScope.of(context).requestFocus(FocusNode());
        },
        child: Container(
          padding: EdgeInsets.all(10.0),
          // Use ListView.builder only when the listCount is unknown and can grow
          child: Form(
            key: _formKey,
            child: ListView(
              // so the leftover space is distributed on left and right evenly
              padding: EdgeInsets.symmetric(horizontal: targetPadding / 2),
              children: [
                _buildTitleTextField(selectedProduct),
                _buildDescriptionTextField(selectedProduct),
                _buildPriceTextField(selectedProduct),
                SizedBox(
                  height: 20.0,
                ),
                _buildSubmitButton(),
              ],
            ),
          ),
        ),
      ),
    );