我有一个带点指示器的旋转木马滑块,如图所示
滑块的每个页面都是一个Card小部件,其中ListView作为子部件。
如果Card不在Carousel小部件内,则它会随着Listview内元素的增加而展开。
我想对滑块的每一页都保持这种行为,但当我把卡片放在滑块内时,它们不再根据内容调整大小,而是似乎有一个预定义的高度(即使我没有指定任何高度!(。
如何动态更新滑块内卡片的高度?
这是我的代码:
main.dart文件
import 'package:flutter/material.dart';
import 'carousel.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Slider App',
home: MyHomePage(),
);
}
}
class GeneralEvent {
final String title;
final String desc;
GeneralEvent(this.title, this.desc);
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
final List<GeneralEvent> userEvents = [
GeneralEvent(
"List Item 1",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 2",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 3",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 4",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 5",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
];
class _MyHomePageState extends State<MyHomePage> {
final List<Card> cards = [
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Card 1',
style: TextStyle(fontSize: 24),
),
),
Container(
height: 1,
width: double.infinity,
color: Color.fromRGBO(0, 0, 0, 0.12),
),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (ctx, index) {
return ListTile(
title: Text(
userEvents.sublist(0, 3)[index].title,
),
subtitle: Text(userEvents.sublist(0, 3)[index].desc),
);
},
itemCount: userEvents.sublist(0, 3).length,
),
],
),
),
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Card 2',
style: TextStyle(fontSize: 24),
),
),
Container(
height: 1,
width: double.infinity,
color: Color.fromRGBO(0, 0, 0, 0.12),
),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (ctx, index) {
return ListTile(
title: Text(
userEvents.sublist(3)[index].title,
),
subtitle: Text(userEvents.sublist(3)[index].desc),
);
},
itemCount: userEvents.sublist(3).length,
),
],
),
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(235, 235, 235, 1),
appBar: AppBar(title: Text('iWantASliderAPP')),
body: Padding(
padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
child: LayoutBuilder(
builder: (context, constraints) {
return ListView(
children: <Widget>[
CarouselWithIndicator(cards),
Padding(
padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
child: Text(
"if the Card is not in the slider it resize properly:",
),
),
cards[0]
],
);
},
),
),
);
}
}
和转盘。dart
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
class CarouselWithIndicator extends StatefulWidget {
final List cards;
CarouselWithIndicator(this.cards);
@override
_CarouselWithIndicatorState createState() => _CarouselWithIndicatorState();
}
class _CarouselWithIndicatorState extends State<CarouselWithIndicator> {
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
int _current = 0;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
CarouselSlider(
// height: // NO HEIGHT SPECIFIED!
viewportFraction: 1.0,
enlargeCenterPage: true,
enableInfiniteScroll: false,
onPageChanged: (index) {
setState(() {
_current = index;
});
},
items: widget.cards.map((card) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
child: card,
);
},
);
}).toList(),
),
SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: map<Widget>(widget.cards, (index, card) {
return Container(
width: 10.0,
height: 10.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 3.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index ? Colors.grey : Color.fromRGBO(200, 200, 200, 1),
),
);
}),
),
],
);
}
}
我认识到对于不同的内容大小使用CarouselSlider是很困难的。
我使用了此程序包:https://pub.dev/packages/expandable_page_view
int current = 0;
Container(
width: MediaQuery.of(context).size.width,
child: ExpandablePageView.builder(
onPageChanged: (index) {
setState(() {
current = index;
});
},
itemCount: itemList.length,
itemBuilder: (context, index) {
return GalleryItemThumbnail(
galleryItemModel: GalleryItemModel(id: itemList[index]),
onTap: () {
_open(context, index);
},
);
},
),
),
在运行时高度确定的帮助下,我终于找到了解决方案。链接到运行时大小确定问题:如何获得小工具的高度?
只需定义一个高度变量,并在Measure-size的onChanged函数中更新它。
MeasureSizeRenderObject.dart
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
typedef void OnWidgetSizeChange(Size size);
class MeasureSizeRenderObject extends RenderProxyBox {
Size oldSize;
final OnWidgetSizeChange onChange;
MeasureSizeRenderObject(this.onChange);
@override
void performLayout() {
super.performLayout();
Size newSize = child.size;
if (oldSize == newSize) return;
oldSize = newSize;
WidgetsBinding.instance.addPostFrameCallback((_) {
onChange(newSize);
});
}
}
class MeasureSize extends SingleChildRenderObjectWidget {
final OnWidgetSizeChange onChange;
const MeasureSize({
Key key,
@required this.onChange,
@required Widget child,
}) : super(key: key, child: child);
@override
RenderObject createRenderObject(BuildContext context) {
return MeasureSizeRenderObject(onChange);
}
}
导入上面的飞镖文件,你就可以开始了。
在我的情况下,我有一个日期列表和一个Map<字符串,列表>每天运行小时数。因此,当添加一个新的操作小时时,ListView的长度就会增加。
List_days=[周一、周二、周三、周四、周五、周六、周日];
映射<字符串,列表>_operationalHours={};
我在Firebase Cloud Firestore中填充操作时间。
转盘滑块代码:
CarouselSlider.builder(
itemCount: days.length,
itemBuilder: (BuildContext context, int index, int realIdx) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Color(0xff3b3b3b),
child: Container(
width: displayWidth(context),
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Text(
days[index],
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20),
),
SizedBox(
height: 15,
),
Column(
children: [
MeasureSize(
onChange: (size) {
height = size.height;
print("log" + height.toString());
setState(() {});
},
child: ListView.builder(
shrinkWrap: true,
itemCount: operationalHours[days[index]]
.length,
itemBuilder: (context, i) {
return getTimeSlot(
operationalHours[days[index]][i]);
}),
)
],
)
],
),
),
);
},
options: new CarouselOptions(
autoPlay: false,
viewportFraction: 1.0,
height: 100 + height,
enlargeCenterPage: false,
enableInfiniteScroll: false,
onPageChanged: (index, reason) {
setState(() {
_current = index;
});
}),
),
如果我在将代码从IDE复制到StackOverflow时犯了任何拼写错误或错误,请告诉我。我会更新答案。
这是库中已知的问题。这是库Currently there is no way to define a dynamic height for each carousel item. But I think it can be done by creating a dynamic height container in the carousel item.
创建者的答案
对于整个对话,请查看以下问题:https://github.com/serenader2014/flutter_carousel_slider/issues/106
这是库的一个开放问题,但您仍然可以通过以下代码部分实现
转盘。dart
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
class CarouselWithIndicator extends StatefulWidget {
final List cards;
CarouselWithIndicator(this.cards);
@override
_CarouselWithIndicatorState createState() => _CarouselWithIndicatorState();
}
class _CarouselWithIndicatorState extends State<CarouselWithIndicator> {
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
int _current = 0;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Wrap(
children: <Widget>[
CarouselSlider(
height: double.maxFinite,
viewportFraction: 1.0,
enlargeCenterPage: true,
enableInfiniteScroll: false,
onPageChanged: (index) {
setState(() {
_current = index;
});
},
items: widget.cards.map((card) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
child: card,
);
},
);
}).toList(),
),
],
),
SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: map<Widget>(widget.cards, (index, card) {
return Container(
width: 10.0,
height: 10.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 3.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index
? Colors.grey
: Color.fromRGBO(200, 200, 200, 1),
),
);
}),
),
],
);
}
}
main.dart文件
import 'package:flutter/material.dart';
import 'carousel.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Slider App',
home: MyHomePage(),
);
}
}
class GeneralEvent {
final String title;
final String desc;
GeneralEvent(this.title, this.desc);
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
final List<GeneralEvent> userEvents = [
GeneralEvent(
"List Item 1",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 2",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 3",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 4",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
GeneralEvent(
"List Item 5",
"Lorem ipsum dolor sit amet, consectetur adipisci elit.",
),
];
class _MyHomePageState extends State<MyHomePage> {
List<Widget> cards = [
Wrap(
children: <Widget>[
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Card 1',
style: TextStyle(fontSize: 24),
),
),
Container(
height: 1,
width: double.infinity,
color: Color.fromRGBO(0, 0, 0, 0.12),
),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (ctx, index) {
return ListTile(
title: Text(
userEvents.sublist(0, 3)[index].title,
),
subtitle: Text(userEvents.sublist(0, 3)[index].desc),
);
},
itemCount: userEvents.sublist(0, 3).length,
),
],
),
),
],
),
Wrap(
children: <Widget>[
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Card 2',
style: TextStyle(fontSize: 24),
),
),
Container(
height: 1,
width: double.infinity,
color: Color.fromRGBO(0, 0, 0, 0.12),
),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (ctx, index) {
return ListTile(
title: Text(
userEvents.sublist(3)[index].title,
),
subtitle: Text(userEvents.sublist(3)[index].desc),
);
},
itemCount: userEvents.sublist(3).length,
),
],
),
),
],
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(235, 235, 235, 1),
appBar: AppBar(title: Text('iWantASliderAPP')),
body: Padding(
padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
child: LayoutBuilder(
builder: (context, constraints) {
return ListView(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CarouselWithIndicator(cards),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
child: Text(
"if the Card is not in the slider it resize properly:",
),
),
cards[0]
],
);
},
),
),
);
}
}
我希望这对你有所帮助