iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 19
0
自我挑戰組

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

整理檔案架構:把組件跟公版拆出來

檔案結構:

pages/
    auth.dart //登入頁
    product_create.dart //管理者的新增商品頁
    product_list.dart //管理者的商品列表
    product.dart //商品細節
    product_admin.dart //管理者頁面(有tab那頁)
    products.dart //用戶的商品列表

widgets/
    products/
    address_tag.dart //地址標籤
    price_tag.dart  //價格標籤
    product_card.dart //商品卡
    products.dart //如果商品陣列大於零,就呼叫ListView.builder的那個列表
    ui_elements/
    title_default.dart //字體為Oswald的text
  1. main.dart
...
routes: {
    '/': (BuildContext context) => AuthPage(),
    '/products': (BuildContext context) => ProductsPage(_products),
    '/admin': (BuildContext context) =>
    ProductsAdminPage(_addProduct, _deleteProduct),
},
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) => ProductPage(
        _products[index]['title'],
        _products[index]['image'],
        _products[index]['price'],
        _products[index]['description']),
    );
    }
    return null;
    },
onUnknownRoute: (RouteSettings settings) {
    return MaterialPageRoute(
    builder: (BuildContext context) => ProductsPage(_products));
},
...
  1. pages/auth.dart
    //把組建拆成function
    Widget _buildEmailTextField() {
    return TextField(
        decoration: InputDecoration(
            labelText: 'E-Mail', filled: true, fillColor: Colors.white),
        keyboardType: TextInputType.emailAddress,
        onChanged: (String value) {
        setState(() {
            _emailValue = value;
        });
        },
    );
    }

build的時候看起來就比較簡潔

    Widget build(BuildContext context) {
    return Scaffold(
        ...
        body: Container(
        ...
        child: Center(
            child: SingleChildScrollView(
            child: Column(
                children: <Widget>[
                _buildEmailTextField(),
                ...
                _buildPasswordTextField(),
                _buildAcceptSwitch(),
                ...
                ],
            ),
            ),
        ),
        ),
    );
    }
  1. pages/products.dart
    把收合式選單拆出去
    Widget _buildSideDrawer(BuildContext context) {
    return Drawer(...);
    }
    @override
    Widget build(BuildContext context) {
    return Scaffold(
        drawer: _buildSideDrawer(context),
  1. widget/products/products.dart
    Widget _buildProductList() {
    Widget productCards;
    if (products.length > 0) {
        productCards = ListView.builder(
        itemBuilder: (BuildContext context, int index) =>
            ProductCard(products[index], index),
        itemCount: products.length,
        );
    } else {
        productCards = Container();
    }
    return productCards;
    }
  1. widget/products/product_card.dart
...

class ProductCard extends StatelessWidget {
    final Map<String, dynamic> product;
    final int productIndex;

    ProductCard(this.product, this.productIndex);

    Widget _buildTitlePriceRow() {
    return Container(
        ...
        child: Row(
        ...
        children: <Widget>[
            TitleDefault(product['title']),
            ...
            PriceTag(product['price'].toString())
        ],
        ),
    );
    }

    Widget _buildActionButtons(BuildContext context) {
    return ButtonBar(
        ...
        children: <Widget>[
        IconButton(...),
        IconButton(...)
        ],
    );
    }

    @override
    Widget build(BuildContext context) {
    return Card(
        child: Column(
        children: <Widget>[
            Image.asset(product['image']),
            _buildTitlePriceRow(),
            AddressTag('Union Square, San Francisco'),
            _buildActionButtons(context)
        ],
        ),
    );
    ;
    }
}

  1. widget/ui-element/title_default.dart

    Widget build(BuildContext context) {
    return Text(
        title,
        style: TextStyle(
            fontSize: 26.0, fontWeight: FontWeight.bold, fontFamily: 'Oswald'),
    );
    }
  1. widget/products/price_tag.dart
    Widget build(BuildContext context) {
    return Container(
        padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.5),
        decoration: BoxDecoration(...),
        child: Text(
        '$$price',
        style: TextStyle(color: Colors.white),
        ),
    );
    }
  1. widget/products/address_tag.dart
    Widget build(BuildContext context) {
    return Container(
        padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.5),
        decoration: BoxDecoration(...),
        child: Text(address),
    );
    }
  1. pages/products_admin.dart
    一樣把收合式選單拆出去,function叫_buildSideDrawer

  2. pages/products_create.dart
    幾乎要寫function,有行為的,都拆出去,讓build裡面盡量簡潔


class _ProductCreatePageState extends State<ProductCreatePage> {
...
    Widget _buildTitleTextField() {
    return TextField(
        decoration: InputDecoration(labelText: 'Product Title'),
        onChanged: (String value) {
        setState(() {
            _titleValue = value;
        });
        },
    );
    }

    Widget _buildDescriptionTextField() {
    return TextField(
        maxLines: 4,
        decoration: InputDecoration(labelText: 'Product Description'),
        onChanged: (String value) {
        setState(() {
            _descriptionValue = value;
        });
        },
    );
    }

    Widget _buildPriceTextField() {
    return TextField(
        keyboardType: TextInputType.number,
        decoration: InputDecoration(labelText: 'Product Price'),
        onChanged: (String value) {
        setState(() {
            _priceValue = double.parse(value);
        });
        },
    );
    }

    void _submitForm() {
    final Map<String, dynamic> product = {
        'title': _titleValue,
        'description': _descriptionValue,
        'price': _priceValue,
        'image': 'assets/food.jpg'
    };
    widget.addProduct(product);
    Navigator.pushReplacementNamed(context, '/products');
    }

    @override
    Widget build(BuildContext context) {
    return Container(
        margin: EdgeInsets.all(10.0),
        child: ListView(
        children: <Widget>[
            _buildTitleTextField(),
            _buildDescriptionTextField(),
            _buildPriceTextField(),
            SizedBox(
            height: 10.0,
            ),
            RaisedButton(
            child: Text('Save'),
            color: Theme.of(context).accentColor,
            textColor: Colors.white,
            onPressed: _submitForm,
            )
        ],
        ),
    );
    }
}

上一篇
背景圖片,上透明度,增加icon按鈕
下一篇
橫向手機時的樣式,使用者手勢監聽器
系列文
使用flutter建構Android和iOs APP25
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言