我正在尝试创建附加布局。它有两个容器。 - 首先是一个水平滚动的固定尺寸的盒子 - 第二张卡片占用剩余空间,其中包含列表视图。
如何实现此布局?
如您所见,两个容器的滚动方向不同。 代码工作到标签视图(第一个框)但是一旦我添加第二个盒子,即卡片,它没有显示任何内容并在控制台上收到错误,如下所示..
I/flutter ( 9412): AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#85877 ink renderer] ←
I/flutter ( 9412): NotificationListener<LayoutChangedNotification> ← ⋯
I/flutter ( 9412): parentData: offset=Offset(0.0, 0.0); flex=null; fit=null (can use size)
I/flutter ( 9412): constraints: BoxConstraints(0.0<=w<=340.0, 0.0<=h<=Infinity)
I/flutter ( 9412): size: MISSING
I/flutter ( 9412): additionalConstraints: BoxConstraints(biggest)
I/flutter ( 9412): This RenderObject had the following descendants (showing up to depth 5):
I/flutter ( 9412): RenderFlex#93e12 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412): RenderRepaintBoundary#977a7 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412): RenderCustomPaint#b6be8 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412): RenderRepaintBoundary#e449b NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412): _RenderExcludableScrollSemantics#293fd NEEDS-LAYOUT NEEDS-PAINT
class _KanbanState extends State<Kanban> {
@override
Widget build(BuildContext context) {
Widget tagList =
new SizedBox(
height: 100.0,
child:
new Column(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new ActionChip(
backgroundColor: Colors.yellow,
label: new Text('Tag1'),
onPressed: () {
// update board with selection
}),
new ActionChip(
//backgroundColor: Colors.transparent,
label: new Text('Tag2'),
onPressed: () {
// update board with selection
}),
new ActionChip(
label: new Text('Tag3'),
onPressed: () {
// update board with selection
}),
new ActionChip(
label: new Text('Tag4'),
onPressed: () {
// update board with selection
}),
],
)
],
),);
Widget boardView = new Flexible(
// margin: new EdgeInsets.symmetric(vertical: 15.0),
child: new Column(
children: <Widget>[
new ListView.builder(
scrollDirection: Axis.vertical,
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
return new ListTile(
onTap: () {
},
title: new Row(
children: <Widget>[
new Expanded(child: new Text("This is item name")),
new Text("12 Dec 18"),
],
),
);
},
),
],
),
);
// int _value=0;
return new Container(
child: new Scaffold(
appBar: new AppBar(
elevation: 1.0,
title: new Text("Test title"),
),
body: new Container(
margin: new EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
tagList,
boardView,
],
)),
));
}
}
答案 0 :(得分:3)
使用此技巧:
Row
包裹在SingleChildScrollView
中。scrollDirection: Axis.horizontal
中使用SingleChildScrollView
。ListView
中包装SingleChildScrollView。答案 1 :(得分:1)
tl; dr:以下代码执行您想要的操作= D
import 'package:flutter/material.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'stack overflow',
theme: ThemeData(
primarySwatch: Colors.pink,
),
routes: {},
home: KanbanState(),
);
}
}
class KanbanState extends StatefulWidget {
@override
KanbanStateState createState() {
return KanbanStateState();
}
}
class KanbanStateState extends State<KanbanState> {
@override
Widget build(BuildContext context) {
Widget tagList = Container(
color: Colors.green,
height: 100.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Row(
children: <Widget>[
ActionChip(
backgroundColor: Colors.yellow,
label: Text('Tag1'),
onPressed: () {
// update board with selection
}),
ActionChip(
//backgroundColor: Colors.transparent,
label: Text('Tag2'),
onPressed: () {
// update board with selection
}),
ActionChip(
label: Text('Tag3'),
onPressed: () {
// update board with selection
}),
ActionChip(
label: Text('Tag4'),
onPressed: () {
// update board with selection
}),
ActionChip(
backgroundColor: Colors.yellow,
label: Text('Tag1'),
onPressed: () {
// update board with selection
}),
ActionChip(
//backgroundColor: Colors.transparent,
label: Text('Tag2'),
onPressed: () {
// update board with selection
}),
ActionChip(
label: Text('Tag3'),
onPressed: () {
// update board with selection
}),
ActionChip(
label: Text('Tag4'),
onPressed: () {
// update board with selection
}),
],
)
],
),
);
Widget boardView = Container(
color: Colors.blue,
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: 15,
itemBuilder: (BuildContext context, int index) {
return ListTile(
onTap: () {},
title: Row(
children: <Widget>[
Expanded(child: Text("This is item name")),
Text("12 Dec 18"),
],
),
);
},
),
);
// int _value=0;
return Scaffold(
appBar: AppBar(
elevation: 1.0,
title: Text("Test title"),
),
body: Container(
color: Colors.amber,
child: new Column(
children: <Widget>[
tagList,
Expanded(
child: boardView,
)
],
),
margin: EdgeInsets.all(10.0),
));
}
}
继承思想过程: 我开始清理每个小部件并确保它们正确显示。在taglist小部件中,请注意您有一行作为列中的唯一小部件。在boardView中,LisView也是列中唯一的元素;
然后我添加了更多项目以确保两个卷轴都能正常工作。在tagList中添加scrollDirection: Axis.horizontal
确保了这一点。
最后,时间将它们放在一起并显示两个元素。删除顶部容器Scaffold就足够了。然后就是将boardView放在Expanded小部件中。
这是一项有趣的练习。 = d
答案 2 :(得分:0)
将CustomScrollView与SliverListview结合使用,则可以通过垂直滚动和水平滚动来实现任何类型的视图。
CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: new SliverChildBuilderDelegate(
(context, index) {
return Container(
child: Row(
children: <Widget>[
buildTitle(),
Expanded(
child: _buildList(),
),
],
),
);
},
childCount: array.length,
),
);,
],
);
答案 3 :(得分:0)
100% 定制
import 'package:flutter/material.dart';
import 'dart:math';
class NestedScrolls extends StatefulWidget {
static const listHeader = ['Pakistan', 'China','Iran','Turkey'];
@override
_NestedScrollsState createState() => _NestedScrollsState();
}
class _NestedScrollsState extends State<NestedScrolls> {
var position=0;
var topHeader;
Widget? applyWidget() {
switch(position){
case 0:
setState(() {
topHeader = NestedScrolls.listHeader[0];
});
// return widget if user click over pakistan in tab bar
return grid();
case 1:
setState(() {
topHeader = NestedScrolls.listHeader[1];
});
return list();
case 2:
setState(() {
topHeader = NestedScrolls.listHeader[2];
});
return Container(color: Colors.blue,
child: Center(child: Text(topHeader),),);
case 3:
setState(() {
topHeader = NestedScrolls.listHeader[3];
});
return Container(color: Colors.orange,
child: Center(child: Text(topHeader),),);
}
}
@override
void initState() {
// TODO: implement initState
super.initState();
//initial header name when activity start first time
topHeader = NestedScrolls.listHeader[0];
}
@override
Widget build(BuildContext context) {
topHeader = topHeader;
return Scaffold(
// Persistent AppBar that never scrolls
appBar: AppBar(
title: Text('AppBar'),
elevation: 0.0,
),
body:
Column(
children: <Widget>[
///header
Container(
alignment: Alignment.center,
color: Colors.blueGrey,
height: 90,
child: Text(NestedScrolls.listHeader[position]),
),
/// tabBar
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: NestedScrolls.listHeader.length,
itemBuilder: (con, index) {
return GestureDetector(
onTap: () => setState(() {
position=index;
topHeader = NestedScrolls.listHeader[index];
}),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 2.0, horizontal: 10),
child: Container(alignment: Alignment.center,
width: 100,
color: topHeader==NestedScrolls.listHeader[index]?Colors.black26:Colors.transparent,
child: Text(NestedScrolls.listHeader[index])),
),
);
}),
),
///Widget
Expanded(
child: GestureDetector(
// onHorizontalDragStart: (left){
// print('left : ${left.localPosition.direction}');
// // left.globalPosition.dx
//
// },
onHorizontalDragEnd: (start){
print('start : ${start.velocity.pixelsPerSecond.dx}');
if((start.velocity.pixelsPerSecond.dx)<-700){
if(position<NestedScrolls.listHeader.length-1 && position>=0)
setState(() {
position=position+1;
});
}else{}
if((start.velocity.pixelsPerSecond.dx)>900){
if(position<=NestedScrolls.listHeader.length-1 && position>0)
setState(() {
position=position-1;
});
}
print(position);
},
child: applyWidget()),
),
],
),
);
}
list() {
return SingleChildScrollView(scrollDirection: Axis.vertical,
child: Container(
child: Column(children: [
for(var color in Colors.primaries)
Container(color: color, height: 100.0)
],),
),
);
}
grid() {
return GridView.count(
padding: EdgeInsets.zero,
crossAxisCount: 3,
children: Colors.primaries.map((color) {
return Container(color: color, height: 100.0);
}).toList(),
);
}
}