Flutter 控件高度动态变化(Container)
2020-08-06 本文已影响0人
fordG
-
先说说我的需求, 有一个组件有个固定的高度, 页面加载完成后,点击某个按钮把这个组件里面的内容全部展示出来带动画效果, 这么一个需求
image.png
image.png -
实现的原理 因为我需要动态获取组件的高度所以我用container的时候, 不能设置高度
@override
Widget build(BuildContext context) {
print("HeightReporterBuild");
Widget tmp = new GestureDetector(
child: child,
onTap: () {
print('Height is ${context.size.height}');
},
);
Future.delayed(Duration(milliseconds: 200)).then((e) {
_height = context.size.height;
debugPrint('Height is ${context.size.height}');
});
return tmp;
}
通过上面的代码测试发现,如果外层组件设置了高度, 那么获取的组件的高度就是外层设置的高度, 因为我们需要动态的高度,如果没有设置高度就可以准确的获取到组件的高度, 但是我的需求里面一开始必须是一个固定的高度, 如果按照这个来做的话, 一开始就完全展开然后缩回去变成固定高度, 不太那个
所以我变化了一下思路, 我们在container里面放了一个SingleChildScrollView把组件放到了滚动组件里面, 然后不让SingleChildScrollView滚动, 主要的问题在这里, 在SingleChildScrollView里面外层的组件设置了高度,SingleChildScrollView也可以获取到你想要的组件的高度,这就解决了一开始固定高度, 还可以获取到你想要展示的组件的高度, 然后通过点击事件取改变animation来改变container的高度,达到上面的效果
- 直接上代码
import 'package:flutter/material.dart';
import 'package:CutDown/height_reporter.dart';
GlobalKey<_CutDownWidgetState> cutDownWidgetKey = GlobalKey();
// ignore: must_be_immutable
class CutDownWidget extends StatefulWidget{
double defaultHeight;
Widget child;
CutDownWidget({Key key, this.defaultHeight, this.child}) : super(key: key);
@override
_CutDownWidgetState createState() => _CutDownWidgetState();
}
class _CutDownWidgetState extends State<CutDownWidget> with SingleTickerProviderStateMixin{
AnimationController animationController;
Animation animation;
Animation curve;
ScrollController scrollController;
double reallyHeight;
HeightReporter childCopy;
@override
void initState() {
// TODO: implement initState
super.initState();
scrollController = ScrollController();
animationController = AnimationController(
duration: const Duration(milliseconds: 300), vsync: this);
curve = new CurvedAnimation(parent: animationController, curve: Curves.easeInOut);
animation = new Tween(begin: widget.defaultHeight, end: reallyHeight).animate(curve);
}
widgetCutDown(){
if(reallyHeight == null){
print(childCopy.getHeight().toString());
reallyHeight = childCopy.getHeight();
animation = new Tween(begin: widget.defaultHeight, end: reallyHeight).animate(curve)..addListener(() {
setState(()=>{});
});
}
if(animation.value == widget.defaultHeight){
animationController.forward();
}else{
animationController.reverse();
}
/*if(animation.value == widget.defaultHeight){
}else{
animationController.reverse();
}*/
}
@override
Widget build(BuildContext context) {
if(childCopy == null){
childCopy = HeightReporter(child: widget.child);
}
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
height: animation.value,
child: SingleChildScrollView(
child: childCopy,
physics: NeverScrollableScrollPhysics(),
controller: scrollController,
),
),
);
}
}
import 'package:flutter/material.dart';
class HeightReporter extends StatelessWidget {
final Widget child;
HeightReporter({this.child});
double _height;
double getHeight() {
return _height;
}
@override
Widget build(BuildContext context) {
print("HeightReporterBuild");
Widget tmp = new GestureDetector(
child: child,
onTap: () {
print('Height is ${context.size.height}');
},
);
Future.delayed(Duration(milliseconds: 200)).then((e) {
_height = context.size.height;
debugPrint('Height is ${context.size.height}');
});
return tmp;
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String leadText = "展开";
CutDownWidget cutDownWidget;
double defaultHeight = 80.0;
@override
Widget build(BuildContext context) {
if (cutDownWidget == null) {
cutDownWidget = _cutDown();
}
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
GestureDetector(
onTap: () {
cutDownWidgetKey.currentState.widgetCutDown();
},
child: Container(
alignment: Alignment.center,
height: 44,
width: 44,
child: Text(leadText),
),
)
],
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
margin: EdgeInsets.all(15),
child: cutDownWidget,
),
Container(
height: 1000,
)
],
),
));
}
Widget _cutDown(){
return CutDownWidget(
key: cutDownWidgetKey,
defaultHeight: defaultHeight,
child: Container(
child: Column(
children: [
Container(
color: Colors.red,
child: Padding(
padding: EdgeInsets.all(30),
child: Text("CutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidgetCutDownWidget"),
),
)
],
),
),
);
}
}