以编程方式在Flutter中扩展ExpansionTile

时间:2018-08-05 20:12:35

标签: dart flutter flutter-layout

我只是想在Flutter中使用ExpansionTile,根据我经过修改的示例,使其变得像这样:

enter image description here

我想隐藏箭头并使用Switch来扩展图块,这可能吗?还是我需要自定义小部件以编程方式呈现子级?基本上,我只需要显示/隐藏孩子

这是我的代码:

import 'package:flutter/material.dart';

void main() {
  runApp(ExpansionTileSample());
}
class ExpansionTileSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('ExpansionTile'),
        ),
        body: ListView.builder(
          itemBuilder: (BuildContext context, int index) =>
              EntryItem(data[index]),
          itemCount: data.length,
        ),
      ),
    );
  }
}

// One entry in the multilevel list displayed by this app.
class Entry {
  Entry(this.title,[this.question='',this.children = const <Entry>[]]);

  final String title;
  final String question;
  final List<Entry> children;
}

// The entire multilevel list displayed by this app.
final List<Entry> data = <Entry>[
  Entry(
    'Chapter A',
    '',
    <Entry>[
      Entry(
        'Section A0',
        '',
        <Entry>[
          Entry('Item A0.1'),
          Entry('Item A0.2'),
          Entry('Item A0.3'),
        ],
      ),
      Entry('Section A1','text'),
      Entry('Section A2'),
    ],
  ),
  Entry(
    'Chapter B',
    '',
    <Entry>[
      Entry('Section B0'),
      Entry('Section B1'),
    ],
  ),
  Entry(
    'Chapter C',
    '',
    <Entry>[
      Entry('Section C0'),
      Entry('Section C1')
    ],
  ),
];

// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class EntryItem extends StatelessWidget {
  const EntryItem(this.entry);

  final Entry entry;

  Widget _buildTiles(Entry root) {
    if (root.children.isEmpty) return  Container(
        child:Padding(
          padding: const EdgeInsets.symmetric(
            vertical: 8.0,
            horizontal: 32.0,
          ),
          child:Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children:[
                  Text(root.title),
                  Divider(height: 10.0,),
                  root.question=='text'?Container(
                      width: 100.0,
                      child:TextField(
                        decoration: const InputDecoration(helperText: "question")
                      ),
                  ):Divider()
              ]
          )
        )
    );
    return ExpansionTile(
      //key: PageStorageKey<Entry>(root),
      title: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children:[
          Text(root.title),
          Switch(
            value:false,
            onChanged: (_){},
          )
        ]
      ),
      children: root.children.map(_buildTiles).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return _buildTiles(entry);
  }
}

2 个答案:

答案 0 :(得分:1)

@diegoveloper的答案几乎可以,一个没有被掩盖的小问题是:它不会推动// calculate the max of a vector after omitting one element double max_except(NumericVector vec, int ele) { if (vec.length() == 1) stop("vec too short"); if (ele < 0 | ele > vec.length()-1) stop("ele out of range"); double temp = vec[ele]; int idx = (ele > 0) ? ele-1 : ele+1; vec[ele] = vec[idx]; double res = max(vec); vec[ele] = temp; return res; } 上的adapter.notifyDataSetChanged();的点击,因此,如果您单击外部开关,它将在单击时扩展public class GetOrdersModel implements GetOrdersPre { private Context _context; private GetOrdersView _view; private List<Orders> list = new ArrayList<>(); public GetOrdersModel(Context context,GetOrdersView view){this._context = context;this._view = view;} @Override public void Get_Orders(String usercode) { RequestQueue queue = Volley.newRequestQueue(_context); queue.getCache().clear(); StringRequest request = new StringRequest( Request.Method.GET, DirectionU.BASE_URL_USERS + "getorders/" + usercode + "/", new Response.Listener<String>() { @Override public void onResponse(String response) { if(!response.toString().equals("{\"success\":0}")) { GsonBuilder builder = new GsonBuilder(); Gson gson = builder.create(); list.clear(); list = Arrays.asList(gson.fromJson(response, Orders[].class)); _view.Successfuly_getorders(list); }else{ _view.Failed_getorders(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.d("orders","error is " + error.getMessage()); } }){ @Override public String getBodyContentType() { return "application/json; charset=utf-8"; } }; request.setRetryPolicy(new DefaultRetryPolicy( 10000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); request.setShouldCache(false); queue.add(request); } } 上的操作无效。用Switch括起来,并在扩展事件中设置switch的值。逻辑有些倒退,但是效果很好。

ExpansionTile

答案 1 :(得分:0)

是的,有可能,我对您的代码做了一些修改:

        class EntryItem extends StatefulWidget {
          const EntryItem(this.entry);
          final Entry entry;

          @override
          EntryItemState createState() {
            return new EntryItemState();
          }
        }

        class EntryItemState extends State<EntryItem> {
          var isExpanded = false;

          _onExpansionChanged(bool val) {
            setState(() {
              isExpanded = val;
            });
          }

          Widget _buildTiles(Entry root) {
            if (root.children.isEmpty)
              return Container(
                  child: Padding(
                      padding: const EdgeInsets.symmetric(
                        vertical: 8.0,
                        horizontal: 32.0,
                      ),
                      child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Text(root.title),
                            Divider(
                              height: 10.0,
                            ),
                            root.question == 'text'
                                ? Container(
                                    width: 100.0,
                                    child: TextField(
                                        decoration: const InputDecoration(
                                            helperText: "question")),
                                  )
                                : Divider()
                          ])));
            return ExpansionTile(
              onExpansionChanged: _onExpansionChanged,
              trailing: Switch(
                value: isExpanded,
                onChanged: (_) {},
              ),
              //key: PageStorageKey<Entry>(root),
              title: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
                Text(root.title),
              ]),
              children: root.children.map((entry) => EntryItem(entry)).toList(),
            );
          }

          @override
          Widget build(BuildContext context) {
            return _buildTiles(widget.entry);
          }
        }

基本上,我从无状态更改为有状态,因为您需要处理Switch小部件的状态。

trailing中有一个ExpansionTile属性,我将“开关”默认删除了arrow小部件。

收听onExpansionChanged: _onExpansionChanged,,以更改交换机的状态。

最后将子代构建为新的小部件:

children: root.children.map((entry) => EntryItem(entry)).toList(),