Flutter 颤振出现方法&x27;FindEnderObject';被调用为空
我最近有一个需要,我需要测量小条和顶部中的子元素之间的距离,但总是提示findrendereobject为空 我甚至无法尝试widgetsbinding.instance.addpostframecallback 控制台错误:Flutter 颤振出现方法&x27;FindEnderObject';被调用为空,flutter,dart,Flutter,Dart,我最近有一个需要,我需要测量小条和顶部中的子元素之间的距离,但总是提示findrendereobject为空 我甚至无法尝试widgetsbinding.instance.addpostframecallback 控制台错误: ════════ 调度程序库捕获到异常═════════════════════════════════════════════════════ 计划程序回调期间引发了以下NoSuchMethodError: 对null调用了方法“FindEnderObject”。 收件
════════ 调度程序库捕获到异常═════════════════════════════════════════════════════
计划程序回调期间引发了以下NoSuchMethodError:
对null调用了方法“FindEnderObject”。
收件人:空
已尝试调用:FindEnderObject()
请大家看看发生了什么事,为什么不能测量高度~非常感谢!!!
我的代码:
class GoodsDetailPage扩展StatefulWidget{
最终指数;
GoodsDetailPage(this.bean);
@凌驾
_GoodsDetailPageState createState()=>_GoodsDetailPageState();
}
类_GoodsDetailPageState使用SingleTickerProviderStateMixin扩展状态{
int-productId;
内部区域ID;
字符串服务时间;
ProductInfoBean ProductInfoBean;
字符串_选择名称;
规范;
双屏宽;
bool_isShow=false;
TabController\u TabController;
列表小报;
ScrollController_ScrollController=ScrollController();
var globalKeyOne=GlobalKey();
var globalkeytow2=GlobalKey();
var globalkeytree=GlobalKey();
var oneY=0.0;
var twoY=0.0;
var threeY=0.0;
ProductModel=ProductModel();
GoodsSpecModel _specModel=GoodsSpecModel();
@凌驾
void initState(){
productId=widget.bean.productId;
areaId=widget.bean.areaId;
serviceTime=widget.bean.serviceTimeBegin;
小报作者=[
"商品",
"评价",
"详情",
];
_tabController=tabController(
长度:tabList.length,
vsync:这个,,
);
_scrollController.addListener((){
变量=_scrollController.offset;
设置状态(){
_isShow=of>=屏幕宽度-50;
});
如果(of>threeY-oneY){
_tabController.animateTo(2);
}否则如果(of>twoY-oneY){
_tabController.animateTo(1);
}否则{
_tabController.animateTo(0);
}
打印(“滚动了$of one=${twoY-oneY}=two=${threeY-oneY}”);
});
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
//等待界面渲染完成
无效u后布局(u){
oneY=getY(globalKeyOne.currentContext);
twoY=getY(globalKeyTwo.currentContext);
threeY=getY(globalkeytree.currentContext);
}
静态双getY(BuildContext BuildContext){
final RenderBox=buildContext.FindEnderObject();
//最终尺寸=盒子尺寸;
最终topLeftPosition=box.localToGlobal(偏移量为0);
返回topLeftPosition.dy;
}
Future\u request()异步{
model.requestGoodsDetail(productId:productId,areaId:areaId,serviceTime:serviceTime);
}
@凌驾
小部件构建(构建上下文){
screenWidth=MediaQuery.of(context).size.width;
返回脚手架(
主体:容器(
宽度:double.infinity,
高度:双无限,
子:ProviderWidget(
模型:模型,
onModelReady:(model)=>model.requestGoodsDetail(productId:productId,areaId:areaId,serviceTime:serviceTime),
生成器:(上下文、模型、子对象){
如果(型号忙){
返回ViewStateBusyWidget();
}
if(模型错误){
返回ViewStateErrorWidget(错误:model.viewStateError,onPressed:\u请求);
}
返回列(
儿童:[
已展开(子项:_body()),
_底部()
],
);
}
),
)
);
}
Widget_body(){
var _normalBack=Image.asset(ImagePath.normalBack,高度:dp40,宽度:dp40);
var_detailBack=Image.asset(ImagePath.detailBack,高度:dp60,宽度:dp60);
var _normalShare=Image.asset(ImagePath.detailsharesall,高度:dp40,宽度:dp60);
var\u detailShare=Image.asset(ImagePath.detailShare,高度:dp60,宽度:dp140);
var _normalDot=Image.asset(ImagePath.threeDot,高度:dp40,宽度:dp40);
var\u detailDot=Image.asset(ImagePath.detailDot,高度:dp60,宽度:dp60);
返回自定义滚动视图(
控制器:\ u滚动控制器,
条子:[
滑杆(
钥匙:环球通,
标题:_isShow?_topTabTitle():容器(),
标题:对,
扩展高度:屏幕宽度,
浮动:假,
对,,
快照:错,
标高:0.5,
领先:IconButton(
图标:_isShow?_normalBack:_detailBack,
按下时:()=>pop(),
),
行动:[
手势检测器(
子项:_isShow?_normalShare:_detailShare,
onTap:(){
打印(“分享");
},
),
尺寸框(宽度:dp24),
手势检测器(
孩子:_isShow?_normalDot:_detailDot,
onTap:_showPopup,
),
尺寸框(宽度:dp30),
],
flexibleSpace:FlexibleSpaceBar(
背景:GoodsDetailBannerWidget(型号),
),
),
银表(
委托:SliverChildListDelegate([
_activityImage(),
GoodsDetailInfo小部件(型号),
gap20,
GoodsDetailOtherWidget(型号、服务时间),
GoodsDetailCategoryWidget(单击:\单击规格,名称:\选择名称),
gap20,
纵队(
关键词:环球二号,
儿童:[
GoodsDetailCommentWidget(模型),
gap20,
],
),
容器(
钥匙:环球三号,
孩子:好的
class GoodsDetailPage extends StatefulWidget {
final IndexVOS bean;
GoodsDetailPage(this.bean);
@override
_GoodsDetailPageState createState() => _GoodsDetailPageState();
}
class _GoodsDetailPageState extends State<GoodsDetailPage> with SingleTickerProviderStateMixin{
int productId;
int areaId;
String serviceTime;
ProductInfoBean productInfoBean;
String _selectName;
Norms norms;
double screenWidth;
bool _isShow = false;
TabController _tabController;
List<String> tabList;
ScrollController _scrollController = ScrollController();
var globalKeyOne = GlobalKey();
var globalKeyTwo = GlobalKey();
var globalKeyThree = GlobalKey();
var oneY = 0.0;
var twoY = 0.0;
var threeY = 0.0;
ProductModel model = ProductModel();
GoodsSpecModel _specModel = GoodsSpecModel();
@override
void initState() {
productId = widget.bean.productId;
areaId = widget.bean.areaId;
serviceTime = widget.bean.serviceTimeBegin;
tabList = [
"商品",
"评价",
"详情",
];
_tabController = TabController(
length: tabList.length,
vsync: this,
);
_scrollController.addListener(() {
var of = _scrollController.offset;
setState(() {
_isShow = of >= screenWidth-50;
});
if (of > threeY - oneY) {
_tabController.animateTo(2);
}else if (of > twoY - oneY) {
_tabController.animateTo(1);
} else {
_tabController.animateTo(0);
}
print("滚动了$of one=${twoY - oneY}=two=${threeY - oneY}");
});
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
//等待界面渲染完成
void _afterLayout(_){
oneY = getY(globalKeyOne.currentContext);
twoY = getY(globalKeyTwo.currentContext);
threeY = getY(globalKeyThree.currentContext);
}
static double getY(BuildContext buildContext) {
final RenderBox box = buildContext.findRenderObject();
//final size = box.size;
final topLeftPosition = box.localToGlobal(Offset.zero);
return topLeftPosition.dy;
}
Future _request() async{
model.requestGoodsDetail(productId: productId,areaId: areaId,serviceTime: serviceTime);
}
@override
Widget build(BuildContext context) {
screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
child: ProviderWidget<ProductModel>(
model: model,
onModelReady: (model) => model.requestGoodsDetail(productId: productId,areaId: areaId,serviceTime: serviceTime),
builder: (context, model, child) {
if (model.busy) {
return ViewStateBusyWidget();
}
if (model.error) {
return ViewStateErrorWidget(error: model.viewStateError, onPressed: _request);
}
return Column(
children: <Widget>[
Expanded(child: _body()),
_bottom()
],
);
}
),
)
);
}
Widget _body(){
var _normalBack = Image.asset(ImagePath.normalBack,height: dp40,width: dp40);
var _detailBack = Image.asset(ImagePath.detailBack,height: dp60,width: dp60);
var _normalShare = Image.asset(ImagePath.detailShareSmall,height: dp40,width: dp60);
var _detailShare = Image.asset(ImagePath.detailShare,height: dp60,width: dp140);
var _normalDot = Image.asset(ImagePath.threeDot,height: dp40,width: dp40);
var _detailDot = Image.asset(ImagePath.detailDot,height: dp60,width: dp60);
return CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
key: globalKeyOne,
title: _isShow?_topTabTitle():Container(),
centerTitle: true,
expandedHeight: screenWidth,
floating: false,
pinned: true,
snap: false,
elevation: 0.5,
leading: IconButton(
icon: _isShow?_normalBack:_detailBack,
onPressed: () => pop(),
),
actions: <Widget>[
GestureDetector(
child: _isShow?_normalShare:_detailShare,
onTap: (){
print("分享");
},
),
SizedBox(width: dp24),
GestureDetector(
child: _isShow?_normalDot:_detailDot,
onTap: _showPopup,
),
SizedBox(width: dp30),
],
flexibleSpace: FlexibleSpaceBar(
background: GoodsDetailBannerWidget(model),
),
),
SliverList(
delegate: SliverChildListDelegate([
_activityImage(),
GoodsDetailInfoWidget(model),
gap20,
GoodsDetailOtherWidget(model,serviceTime),
GoodsDetailCategoryWidget(click: _clickSpec,name: _selectName),
gap20,
Column(
key: globalKeyTwo,
children: <Widget>[
GoodsDetailCommentWidget(model),
gap20,
],
),
Container(
key: globalKeyThree,
child: GoodsDetailDescWidget(model),
)
]),
),
],
);
}
Widget _bottom(){
return GoodsDetailBottomWidget(
clickBuy: (){
if(_selectName == null){
_clickSpec();
return;
}
routePush(ConfirmOrderPage(productInfoBean: model.productInfoBean,norms: norms,count: _specModel.countNumber));
},
);
}
Widget _activityImage(){
return Container(
width: double.infinity,
height: dp80,
child: Image.asset(ImagePath.goodsActivity),
);
}
Widget _topTabTitle(){
return Container(
height: dp60,
child: TabBar(
controller: _tabController,
labelColor: ColorConfig.themeGreen,
unselectedLabelColor: ColorConfig.C09,
labelStyle: StyleConfig.green_36Style,
unselectedLabelStyle: StyleConfig.normalTitle36Style,
indicatorColor: ColorConfig.themeGreen,
indicatorSize: TabBarIndicatorSize.label,
indicatorWeight: 2,
isScrollable: true,
labelPadding: EdgeInsets.symmetric(horizontal: dp20),
tabs: tabList.map((item) {
return Tab(
text: item,
);
}).toList(),
onTap: (index){
switch(index){
case 0:
_scrollController.jumpTo(0);
_tabController.animateTo(0);
break;
case 1:
_scrollController.jumpTo(twoY - oneY);
_tabController.animateTo(1);
break;
case 2:
_scrollController.jumpTo(threeY - oneY);
_tabController.animateTo(2);
break;
}
},
),
);
}
void _showPopup(){
showPopupWindow(
context,
gravity: KumiPopupGravity.rightTop,
underStatusBar: true,
underAppBar: true,
offsetX: -dp30,
offsetY: -dp20,
childFun: (pop){
return Container(
key: GlobalKey(),
child: GoodsDetailPopupMenuWidget(),
);
}
);
}
void _clickSpec(){
_specModel.initData(model.normInfoBean.norms);
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (BuildContext context) {
return GoodsSpecSelectDialog(
model: _specModel,
onSelected: (bean, count) {
norms = bean;
setState(() {
_selectName = "已选:"+bean.normName + ",数量:" + count.toString();
});
},
);
},
);
}
@override
void dispose() {
_specModel.dispose();
_scrollController.dispose();
_tabController.dispose();
super.dispose();
}
}