Unhandled Exception: Cannot hit test a render box with no size

使用列表时,如果直接使用listView,flutter不能命中没有大小的渲染框。

比如下面这个例子,错误的做法

import 'package:flutter/material.dart';
import 'package:flutter_practice/practice-advanced/router/event-bus-ex.dart';
import 'package:flutter_practice/practice-advanced/router/gesture-detector-ex.dart';
import 'package:flutter_practice/practice-advanced/router/pointer-event-ex.dart';
import 'package:flutter_practice/practice-advanced/router/notification-ex.dart';
import 'my-route.dart';
import 'my-expansion-panel.dart';

class MyRouteGroup {
  MyRouteGroup(
      {@required this.groupName,
      @required this.icon,
      @required this.routes,
      this.isExpanded});

  final String groupName;
  final Widget icon;
  final List<MyRoute> routes;
  bool isExpanded = false;
}

List<MyRouteGroup> myAppAdvancedRoutes = [
  MyRouteGroup(
      groupName: '事件处理与通知',
      icon: Icon(Icons.drag_handle),
      routes: <MyRoute>[
        MyRoute(
          child: PointerEventExample(),
          title: '原始指针事件处理',
        ),
        MyRoute(
          child: GestureDetectorExample(),
          title: '手势识别',
        ),
        MyRoute(
          child: EventBusExample(),
          title: '全局事件总线',
        ),
        MyRoute(
          child: NotificationExample(),
          title: '通知(Notification)',
        ),
      ]),
  MyRouteGroup(groupName: '动画', icon: Icon(Icons.animation), routes: <MyRoute>[
    MyRoute(
      child: PointerEventExample(),
      title: '动画结构',
    ),
    MyRoute(
      child: GestureDetectorExample(),
      title: '自定义路由过渡动画',
    ),
    MyRoute(
      child: EventBusExample(),
      title: 'hero动画',
    ),
    MyRoute(
      child: NotificationExample(),
      title: '交织动画',
    ),
    MyRoute(
      child: NotificationExample(),
      title: '动画过渡组件',
    ),
  ]),
];

class PracticeAdvancedPage extends StatefulWidget {
  PracticeAdvancedPageState createState() => PracticeAdvancedPageState();
}

class PracticeAdvancedPageState extends State {
  Widget build(BuildContext context) {
    // const demos = [
    //   {'key': 'counter', 'component': CounterDemo},
    //   {'key': 'use_package', 'component': CounterDemo},
    //   {'key': 'tapbox_state', 'component': CounterDemo},
    // ];
    return Container(
      padding: EdgeInsets.all(16.0),
      child: ExpansionPanelList(
        expansionCallback: (int panelIndex, bool isExpanded) {},
        children: myAppAdvancedRoutes.map((group) {
          return ExpansionPanel(
            headerBuilder: (BuildContext context, bool isExpanded) {
              return ListTile(title: Text(group.groupName));
            },
            body: ListView(
              padding: EdgeInsets.all(8),
              children: group.routes
                  .map((er) => ListTile(title: Text(er.title)))
                  .toList(),
            ),
            isExpanded: false,
          );
        }).toList(),
      ),
    );
  }
}

这是正确的做法:

import 'package:flutter/material.dart';
import 'package:flutter_practice/practice-advanced/router/event-bus-ex.dart';
import 'package:flutter_practice/practice-advanced/router/gesture-detector-ex.dart';
import 'package:flutter_practice/practice-advanced/router/pointer-event-ex.dart';
import 'package:flutter_practice/practice-advanced/router/notification-ex.dart';
import 'my-route.dart';

class MyRouteGroup {
  MyRouteGroup(
      {@required this.groupName,
      @required this.icon,
      @required this.routes,
      this.isExpanded});

  final String groupName;
  final Widget icon;
  final List<MyRoute> routes;
  bool isExpanded = false;
}

List<MyRouteGroup> myAppAdvancedRoutes = [
  MyRouteGroup(
      groupName: '事件处理与通知',
      icon: Icon(Icons.drag_handle),
      isExpanded: false,
      routes: <MyRoute>[
        MyRoute(
          child: PointerEventExample(),
          title: '原始指针事件处理',
        ),
        MyRoute(
          child: GestureDetectorExample(),
          title: '手势识别',
        ),
        MyRoute(
          child: EventBusExample(),
          title: '全局事件总线',
        ),
        MyRoute(
          child: NotificationExample(),
          title: '通知(Notification)',
        ),
      ]),
  MyRouteGroup(
      groupName: '动画',
      icon: Icon(Icons.animation),
      isExpanded: false,
      routes: <MyRoute>[
        MyRoute(
          child: PointerEventExample(),
          title: '动画结构',
        ),
        MyRoute(
          child: GestureDetectorExample(),
          title: '自定义路由过渡动画',
        ),
        MyRoute(
          child: EventBusExample(),
          title: 'hero动画',
        ),
        MyRoute(
          child: NotificationExample(),
          title: '交织动画',
        ),
        MyRoute(
          child: NotificationExample(),
          title: '动画过渡组件',
        ),
      ]),
];

class PracticeAdvancedPage extends StatefulWidget {
  PracticeAdvancedPageState createState() => PracticeAdvancedPageState();
}

class PracticeAdvancedPageState extends State {
  Widget build(BuildContext context) {
    return SingleChildScrollView(
        child: Container(
      child: ExpansionPanelList(
        expansionCallback: (int panelIndex, bool isExpanded) {
          print(panelIndex);
          print(isExpanded);
          setState(() {
            myAppAdvancedRoutes[panelIndex].isExpanded = !isExpanded;
          });
        },
        children: myAppAdvancedRoutes.map((group) {
          return ExpansionPanel(
            headerBuilder: (BuildContext context, bool isExpanded) {
              return ListTile(title: Text(group.groupName));
            },
            body: Container(
              height: (group.routes.length * 50)
                  .toDouble(), // 这里必须告诉flutter高度, 否则不渲染
              child: ListView(
                padding: EdgeInsets.all(8),
                children: group.routes
                    .map((er) => ListTile(title: Text(er.title)))
                    .toList(),
              ),
            ),
            isExpanded: group.isExpanded,
          );
        }).toList(),
      ),
    ));
  }
}

SingleChildScrollView 包起会滚动的组件, List渲染时,设置好height。

全部代码访问: flutter实战

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值