渲染时嵌套 ListView.Builder 失败 - Flutter
Nested ListView.Builder fails while rendering - Flutter
我正在尝试使用 flutter 应用程序来构建一个小游戏
我有一个 List<List<ColumnData>> gameBoard
,其中 ColumnData
是本地定义的 class。
该列表应该是三角形格式的二维列表
例如对于 3 级,列表将如下所示:
[00]
[10][11]
[20][21][22]
我的模拟代码是:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class ColumnData {
int _rowIdx;
int _colIdx;
String _data;
Widget _column;
ColumnData({String data, int row, int col}) {
_data = data;
_rowIdx = row;
_colIdx = col;
_column = new InkWell(
child: new Container(
margin: new EdgeInsets.all(10.0),
child: new SizedBox(width: 30.0, height: 30.0,
child: new Text(_data, textAlign: TextAlign.center),
),
decoration: new BoxDecoration(
border: new Border.all(color: Colors.indigoAccent, width: 2.0),
shape: BoxShape.rectangle,
),
),
);
}
set data(String value) => _data=value;
set colIdx(int value) => _colIdx=value;
set rowIdx(int value) => _rowIdx=value;
Widget get column => _column;
String get data => _data;
int get colIdx => _colIdx;
int get rowIdx => _rowIdx;
String toString(){
return ('Row: ${_rowIdx} Col: ${_colIdx} Data: $_data');
}
}
class _MyHomePageState extends State<MyHomePage> {
List<List<ColumnData>> gameBoard = new List(3);
@override
void initState() {
super.initState();
print('Lets build matrix');
initGame();
}
@override
Widget build(BuildContext context) {
return new Scaffold(body: _buildBody());
}
Widget _buildBody() {
return new ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: gameBoard.length,
shrinkWrap: true,
itemBuilder: (BuildContext ctx, int rowIdx){
return new ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: gameBoard[rowIdx].length,
itemBuilder: (BuildContext ctx, int colIdx){
return gameBoard[rowIdx][colIdx].column;
},
);
},
);
}
initGame(){
List<ColumnData> row1Data = [];
List<ColumnData> row2Data = [];
List<ColumnData> row3Data = [];
ColumnData colData00 = new ColumnData(row: 0, col: 0, data: '7');
row1Data.add(colData00);
gameBoard[0] =row1Data;
ColumnData colData10 = new ColumnData(row: 1, col: 0, data: '5');
ColumnData colData11 = new ColumnData(row: 1, col: 1, data: '2');
row2Data.add(colData10);
row2Data.add(colData11);
gameBoard[1]= row2Data;
ColumnData colData20 = new ColumnData(row: 2, col: 0, data: '3');
ColumnData colData21 = new ColumnData(row: 2, col: 1, data: '2');
ColumnData colData22 = new ColumnData(row: 2, col: 2, data: '0');
row3Data.add(colData20);
row3Data.add(colData21);
row3Data.add(colData22);
gameBoard[2] = row3Data;
print(gameBoard);
}
}
我收到的错误片段是:
I/flutter (21273): [[Row: 0 Col: 0 Data: 7], [Row: 1 Col: 0 Data: 5, Row: 1 Col: 1 Data: 2], [Row: 2 Col: 0 Data: 3, Row: 2 Col: 1 Data: 2, Row: 2 Col: 2 Data: 0]]
Restarted app in 9,341ms.
I/flutter (21273): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (21273): The following assertion was thrown during performLayout():
I/flutter (21273): 'package:flutter/src/rendering/viewport.dart': Failed assertion: line 1283 pos 16:
I/flutter (21273): 'constraints.hasBoundedWidth': is not true.
I/flutter (21273): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter (21273): more information in this error message to help you determine and fix the underlying cause.
I/flutter (21273): In either case, please report this assertion by filing a bug on GitHub:
I/flutter (21273): https://github.com/flutter/flutter/issues/new
I/flutter (21273): When the exception was thrown, this was the stack:
I/flutter (21273): #2 RenderShrinkWrappingViewport.performLayout (package:flutter/src/rendering/viewport.dart)
I/flutter (21273): #3 RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
......
我试过不使用收缩包装,也尝试过使用行和列
但没有成功
我到底做错了什么?
我可以探索的任何其他变化?
任何其他 work-around/idea 构建二维矩阵
欢迎指点
此致
ListView
inside ListView
是一个坏主意。
这是 CustomScrollView
的典型用例。您可以在其中将多个滚动视图组合成一个单元。并且仍然拥有平滑的 虚拟化渲染,其中只有可见的内容会在屏幕上渲染。
这会将您的 build
方法转换为以下内容:
@override
Widget build(BuildContext context) {
final slivers = new List<Widget>(gameBoard.length);
for (var i = 0; i < gameBoard.length; i++) {
slivers[i] = new SliverList(
delegate: new SliverChildBuilderDelegate((context, j) {
return gameBoard[i][j].column;
}, childCount: gameBoard[i].length),
);
}
return new Scaffold(
body: new CustomScrollView(
shrinkWrap: true,
slivers: slivers,
),
);
}
由于我的游戏区域的行数和列数有限(根据所选级别和其他一些参数设计),我可以通过以下方式实现我的布局:
Widget _buildBody() {
List<Widget> rows = new List<Widget>(gameBoard.length);
for (int i=0;i<gameBoard.length; i++){
List<Widget> cols = new List<Widget>(gameBoard[i].length);
for(int j=0; j<gameBoard[i].length; j++){
cols[j] = gameBoard[i][j].column;
}
rows[i] = new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: cols,
);
}
return new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: rows,
),
);
}
此后输出为
我正在尝试使用 flutter 应用程序来构建一个小游戏
我有一个 List<List<ColumnData>> gameBoard
,其中 ColumnData
是本地定义的 class。
该列表应该是三角形格式的二维列表
例如对于 3 级,列表将如下所示:
[00]
[10][11]
[20][21][22]
我的模拟代码是:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class ColumnData {
int _rowIdx;
int _colIdx;
String _data;
Widget _column;
ColumnData({String data, int row, int col}) {
_data = data;
_rowIdx = row;
_colIdx = col;
_column = new InkWell(
child: new Container(
margin: new EdgeInsets.all(10.0),
child: new SizedBox(width: 30.0, height: 30.0,
child: new Text(_data, textAlign: TextAlign.center),
),
decoration: new BoxDecoration(
border: new Border.all(color: Colors.indigoAccent, width: 2.0),
shape: BoxShape.rectangle,
),
),
);
}
set data(String value) => _data=value;
set colIdx(int value) => _colIdx=value;
set rowIdx(int value) => _rowIdx=value;
Widget get column => _column;
String get data => _data;
int get colIdx => _colIdx;
int get rowIdx => _rowIdx;
String toString(){
return ('Row: ${_rowIdx} Col: ${_colIdx} Data: $_data');
}
}
class _MyHomePageState extends State<MyHomePage> {
List<List<ColumnData>> gameBoard = new List(3);
@override
void initState() {
super.initState();
print('Lets build matrix');
initGame();
}
@override
Widget build(BuildContext context) {
return new Scaffold(body: _buildBody());
}
Widget _buildBody() {
return new ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: gameBoard.length,
shrinkWrap: true,
itemBuilder: (BuildContext ctx, int rowIdx){
return new ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: gameBoard[rowIdx].length,
itemBuilder: (BuildContext ctx, int colIdx){
return gameBoard[rowIdx][colIdx].column;
},
);
},
);
}
initGame(){
List<ColumnData> row1Data = [];
List<ColumnData> row2Data = [];
List<ColumnData> row3Data = [];
ColumnData colData00 = new ColumnData(row: 0, col: 0, data: '7');
row1Data.add(colData00);
gameBoard[0] =row1Data;
ColumnData colData10 = new ColumnData(row: 1, col: 0, data: '5');
ColumnData colData11 = new ColumnData(row: 1, col: 1, data: '2');
row2Data.add(colData10);
row2Data.add(colData11);
gameBoard[1]= row2Data;
ColumnData colData20 = new ColumnData(row: 2, col: 0, data: '3');
ColumnData colData21 = new ColumnData(row: 2, col: 1, data: '2');
ColumnData colData22 = new ColumnData(row: 2, col: 2, data: '0');
row3Data.add(colData20);
row3Data.add(colData21);
row3Data.add(colData22);
gameBoard[2] = row3Data;
print(gameBoard);
}
}
我收到的错误片段是:
I/flutter (21273): [[Row: 0 Col: 0 Data: 7], [Row: 1 Col: 0 Data: 5, Row: 1 Col: 1 Data: 2], [Row: 2 Col: 0 Data: 3, Row: 2 Col: 1 Data: 2, Row: 2 Col: 2 Data: 0]]
Restarted app in 9,341ms.
I/flutter (21273): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (21273): The following assertion was thrown during performLayout():
I/flutter (21273): 'package:flutter/src/rendering/viewport.dart': Failed assertion: line 1283 pos 16:
I/flutter (21273): 'constraints.hasBoundedWidth': is not true.
I/flutter (21273): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter (21273): more information in this error message to help you determine and fix the underlying cause.
I/flutter (21273): In either case, please report this assertion by filing a bug on GitHub:
I/flutter (21273): https://github.com/flutter/flutter/issues/new
I/flutter (21273): When the exception was thrown, this was the stack:
I/flutter (21273): #2 RenderShrinkWrappingViewport.performLayout (package:flutter/src/rendering/viewport.dart)
I/flutter (21273): #3 RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
......
我试过不使用收缩包装,也尝试过使用行和列 但没有成功
我到底做错了什么? 我可以探索的任何其他变化? 任何其他 work-around/idea 构建二维矩阵
欢迎指点
此致
ListView
inside ListView
是一个坏主意。
这是 CustomScrollView
的典型用例。您可以在其中将多个滚动视图组合成一个单元。并且仍然拥有平滑的 虚拟化渲染,其中只有可见的内容会在屏幕上渲染。
这会将您的 build
方法转换为以下内容:
@override
Widget build(BuildContext context) {
final slivers = new List<Widget>(gameBoard.length);
for (var i = 0; i < gameBoard.length; i++) {
slivers[i] = new SliverList(
delegate: new SliverChildBuilderDelegate((context, j) {
return gameBoard[i][j].column;
}, childCount: gameBoard[i].length),
);
}
return new Scaffold(
body: new CustomScrollView(
shrinkWrap: true,
slivers: slivers,
),
);
}
由于我的游戏区域的行数和列数有限(根据所选级别和其他一些参数设计),我可以通过以下方式实现我的布局:
Widget _buildBody() {
List<Widget> rows = new List<Widget>(gameBoard.length);
for (int i=0;i<gameBoard.length; i++){
List<Widget> cols = new List<Widget>(gameBoard[i].length);
for(int j=0; j<gameBoard[i].length; j++){
cols[j] = gameBoard[i][j].column;
}
rows[i] = new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: cols,
);
}
return new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: rows,
),
);
}
此后输出为