iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
0
自我挑戰組

使用flutter建構Android和iOs APP系列 第 22

管理員可以在商品清單的後台,編輯與刪除商品

目標:
管理員可以在商品清單的後台,編輯與刪除商品

如此動畫

  1. main.dart

class _MyAppState extends State<MyApp> {
    List<Map<String, dynamic>> _products = [];
    ...
    void _updateProduct(int index, Map<String, dynamic> product) {
    setState(() {
        _products[index] = product;
    });
    }

    void _deleteProduct(int index) {
    setState(() {
        _products.removeAt(index);
    });
    }

    @override
    Widget build(BuildContext context) {
    return MaterialApp(
        ...
        routes: {
        ...
        '/admin': (BuildContext context) =>
            ProductsAdminPage(_addProduct, _updateProduct, _deleteProduct, _products),
        },
        ...
    );
    }
}

  1. pages/products_admin.dart
...

class ProductsAdminPage extends StatelessWidget {
    final Function addProduct;
    final Function updateProduct;
    final Function deleteProduct;
    final List<Map<String, dynamic>> products;

    ProductsAdminPage(this.addProduct, this.updateProduct, this.deleteProduct, this.products);
    ....

    @override
    Widget build(BuildContext context) {
    return DefaultTabController(
        length: 2,
        child: Scaffold(
        ...
        appBar: AppBar(...),
        body: TabBarView(
            children: <Widget>[
            ProductEditPage(addProduct: addProduct),
            ProductListPage(products, updateProduct, deleteProduct)
            ],
        ),
        ),
    );
    }
}
  1. pages/product_edit.dart
    基本上跟上一篇一樣
...

class ProductEditPage extends StatefulWidget {
    final Function addProduct;
    final Function updateProduct;
    final Map<String, dynamic> product;
    final int productIndex;

    ProductEditPage({this.addProduct, this.updateProduct, this.product, this.productIndex});

    @override
    State<StatefulWidget> createState() {
    return _ProductEditPageState();
    }
}

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>();
    final _titleFocusNode = FocusNode();
    final _descriptionFocusNode = FocusNode();
    final _priceFocusNode = FocusNode();

    Widget _buildTitleTextField() {
    return EnsureVisibleWhenFocused(
        focusNode: _titleFocusNode,
        child: TextFormField(
        ...
        initialValue: widget.product == null ? '' : widget.product['title'],
        validator: (String value) {...},
        onSaved: (String value) {
            _formData['title'] = value;
        },
        ),
    );
    }

    Widget _buildDescriptionTextField() {
    return EnsureVisibleWhenFocused(
        focusNode: _descriptionFocusNode,
        child: TextFormField(
        ...
        decoration: InputDecoration(labelText: 'Product Description'),
        initialValue: widget.product == null ? '' : widget.product['description'],
        validator: (String value) {...},
        onSaved: (String value) {
            _formData['description'] = value;
        },
        ),
    );
    }

    Widget _buildPriceTextField() {
    return EnsureVisibleWhenFocused(
        focusNode: _priceFocusNode,
        child: TextFormField(
        ...
        decoration: InputDecoration(labelText: 'Product Price'),
        initialValue: widget.product == null ? '' : widget.product['price'].toString(),
        validator: (String value) {...},
        onSaved: (String value) {
            _formData['price'] = double.parse(value);
        },
        ),
    );
    }

    Widget _buildPageContent(BuildContext context) {
    ...
    return GestureDetector(
        ...
        child: Container(
        margin: EdgeInsets.all(10.0),
        child: Form(
            key: _formKey,
            child: ListView(
            ...
            children: <Widget>[
                _buildTitleTextField(),
                _buildDescriptionTextField(),
                _buildPriceTextField(),
                ...
                RaisedButton(
                child: Text('Save'),
                textColor: Colors.white,
                onPressed: _submitForm,
                )
            ],
            ),
        ),
        ),
    );
    }

    void _submitForm() {
    if (!_formKey.currentState.validate()) {
        return;
    }
    _formKey.currentState.save();
    if (widget.product == null) {
        widget.addProduct(_formData);
    } else {
        widget.updateProduct(widget.productIndex, _formData);
    }

    Navigator.pushReplacementNamed(context, '/products');
    }

    @override
    Widget build(BuildContext context) {
    final Widget pageContent = _buildPageContent(context);
    return widget.product == null
        ? pageContent
        : Scaffold(
            appBar: AppBar(
                title: Text('Edit Product'),
            ),
            body: pageContent,
            );
    }
}
  1. pages/product_list.dart
import './product_edit.dart';

class ProductListPage extends StatelessWidget {
    final Function updateProduct;
    final Function deleteProduct;
    final List<Map<String, dynamic>> products;

    ProductListPage(this.products, this.updateProduct, this.deleteProduct);

    Widget _buildEditButton(BuildContext context, int index) {
    return IconButton(
        icon: Icon(Icons.edit),
        onPressed: () {
        Navigator.of(context).push(
            MaterialPageRoute(
            builder: (BuildContext context) {
                return ProductEditPage(
                //直接把product_edit.dart的內容推到route裡面
                product: products[index],
                updateProduct: updateProduct,
                productIndex: index,
                );
            },
            ),
        );
        },
    );
    }

    @override
    Widget build(BuildContext context) {
    return ListView.builder(
        itemBuilder: (BuildContext context, int index) {
        return Dismissible(
            //整個list的項目都是可以拉掉的
            key: Key(products[index]['title']),
            onDismissed: (DismissDirection direction) {
            if (direction == DismissDirection.endToStart) {
                //從右到左的方向
                deleteProduct(index);
            }
            },
            background: Container(color: Colors.red),
            //底下的背景是紅色比較像刪除
            child: Column(
            children: <Widget>[
                ListTile(
                //左圖片右敘述加小標的排列
                leading: CircleAvatar(
                    backgroundImage: AssetImage(products[index]['image']),
                    //圓形的商品圖片
                ),
                title: Text(products[index]['title']),
                subtitle: Text('$${products[index]['price'].toString()}'),
                //小標放入價格
                trailing: _buildEditButton(context, index),
                //右邊的東西
                ),
                Divider()
                //與下一個list item的分隔線
            ],
            ),
        );
        },
        itemCount: products.length,
    );
    }
}


上一篇
登入與新增商品的驗證,橫向時確認input可視
下一篇
管理員可以在商品清單的後台,編輯與刪除商品
系列文
使用flutter建構Android和iOs APP25

尚未有邦友留言

立即登入留言