获取 CustomScrollView 中小部件的位置
当小部件位于 CustomScrollView 中时如何获取小部件位置 > SliverToBoxAdapter。我的小部件 ZoomItem 通过创建带有覆盖层的新小部件进行缩放,但是当我向上或向下滚动,或者当我更改窗口大小时,覆盖层会出现在一边。为什么“最终 Offset offset = renderBox.localToGlobal(Offset.zero);”仍然返回相同的位置?有没有办法更新渲染框?为什么我的代码中没有更新偏移量?
ZoomItem:
class ZoomItem extends ConsumerStatefulWidget {
final Widget child;
const ZoomItem({Key? key, required this.child}) : super(key: key);
@override
_ZoomItemState createState() => _ZoomItemState();
}
class _ZoomItemState extends ConsumerState<ZoomItem>
with SingleTickerProviderStateMixin {
OverlayEntry? overlayEntry;
late bool hasReachedTop;
late double height, width, xPosition, yPosition;
late AnimationController _animationController;
late Animation<double> animTween;
@override
void initState() {
super.initState();
hasReachedTop = true;
_animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 400));
_animationController.addListener(() {
if (_animationController.isDismissed) {
closeDropDown();
}
});
animTween = Tween<double>(begin: 1.0, end: 2.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
final scrollController = ref.read(scrollControllerProvider);
scrollController.addListener(() {
if (scrollController.position.atEdge) {
if (scrollController.position.pixels == 0) {
hasReachedTop = true;
} else {
hasReachedTop = false;
}
}
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (onEnter) {
insertOverlay(context);
},
onExit: (onExit) {
if (!_animationController.isAnimating) {
closeDropDown();
}
},
child: widget.child);
}
void insertOverlay(BuildContext context) {
closeDropDown();
findDropdownData(context);
overlayEntry = _createOverlay();
Overlay.of(context)!.insert(overlayEntry!);
}
OverlayEntry _createOverlay() {
return OverlayEntry(builder: (context) {
return Stack(
alignment: Alignment.center,
children: [
Positioned(
top: yPosition,
left: xPosition,
height: height,
width: width,
child: MouseRegion(
onEnter: (onEnter) {
_animationController.forward();
},
onExit: (onExit) {
_animationController.reverse();
},
child:
ScaleTransition(scale: animTween, child: widget.child))),
],
);
});
}
void findDropdownData(BuildContext context) {
final RenderBox renderBox = context.findRenderObject()! as RenderBox;
height = renderBox.size.height;
width = renderBox.size.width;
final Offset offset = renderBox.localToGlobal(Offset.zero);
xPosition = offset.dx - kPaddingHorizontal;
final top = hasReachedTop ? kSliverTop : 0;
yPosition = offset.dy - top;
}
void closeDropDown() {
if (overlayEntry != null) {
overlayEntry!.remove();
overlayEntry = null;
}
}
}
GridView交错:
class GridViewStaggered extends StatelessWidget {
final ResponsiveLayoutSize currentSize;
final List<Item> listItem;
const GridViewStaggered({Key? key, required this.currentSize, required this.listItem}) : super(key: key);
@override
Widget build(BuildContext context) {
return StaggeredGrid.count(
children: [
for(int i = 0 ; i < listItem.length; i++)
StaggeredGridTile.count(
crossAxisCellCount: i % 2 == 0 ? 2:1,
mainAxisCellCount: i % 2 == 0 ? 2:1,
child: i.isEven? ItemCard(
item: listItem[i],
):ZoomItem(
child: ItemCard(
item: listItem[i],
),
),
)
],
crossAxisCount: 4);
}
}
How to get the widget position when it is in a CustomScrollView > SliverToBoxAdapter. My widget ZoomItem zoom by creating a new widget with overlay, but when I scroll up or down, or when I change the size of the window the overlay appear aside. Why "final Offset offset = renderBox.localToGlobal(Offset.zero);" still return the same position? Is there a way to update the renderBox? Why there is no update of the offset in my code?
ZoomItem:
class ZoomItem extends ConsumerStatefulWidget {
final Widget child;
const ZoomItem({Key? key, required this.child}) : super(key: key);
@override
_ZoomItemState createState() => _ZoomItemState();
}
class _ZoomItemState extends ConsumerState<ZoomItem>
with SingleTickerProviderStateMixin {
OverlayEntry? overlayEntry;
late bool hasReachedTop;
late double height, width, xPosition, yPosition;
late AnimationController _animationController;
late Animation<double> animTween;
@override
void initState() {
super.initState();
hasReachedTop = true;
_animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 400));
_animationController.addListener(() {
if (_animationController.isDismissed) {
closeDropDown();
}
});
animTween = Tween<double>(begin: 1.0, end: 2.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
final scrollController = ref.read(scrollControllerProvider);
scrollController.addListener(() {
if (scrollController.position.atEdge) {
if (scrollController.position.pixels == 0) {
hasReachedTop = true;
} else {
hasReachedTop = false;
}
}
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (onEnter) {
insertOverlay(context);
},
onExit: (onExit) {
if (!_animationController.isAnimating) {
closeDropDown();
}
},
child: widget.child);
}
void insertOverlay(BuildContext context) {
closeDropDown();
findDropdownData(context);
overlayEntry = _createOverlay();
Overlay.of(context)!.insert(overlayEntry!);
}
OverlayEntry _createOverlay() {
return OverlayEntry(builder: (context) {
return Stack(
alignment: Alignment.center,
children: [
Positioned(
top: yPosition,
left: xPosition,
height: height,
width: width,
child: MouseRegion(
onEnter: (onEnter) {
_animationController.forward();
},
onExit: (onExit) {
_animationController.reverse();
},
child:
ScaleTransition(scale: animTween, child: widget.child))),
],
);
});
}
void findDropdownData(BuildContext context) {
final RenderBox renderBox = context.findRenderObject()! as RenderBox;
height = renderBox.size.height;
width = renderBox.size.width;
final Offset offset = renderBox.localToGlobal(Offset.zero);
xPosition = offset.dx - kPaddingHorizontal;
final top = hasReachedTop ? kSliverTop : 0;
yPosition = offset.dy - top;
}
void closeDropDown() {
if (overlayEntry != null) {
overlayEntry!.remove();
overlayEntry = null;
}
}
}
GridViewStaggered:
class GridViewStaggered extends StatelessWidget {
final ResponsiveLayoutSize currentSize;
final List<Item> listItem;
const GridViewStaggered({Key? key, required this.currentSize, required this.listItem}) : super(key: key);
@override
Widget build(BuildContext context) {
return StaggeredGrid.count(
children: [
for(int i = 0 ; i < listItem.length; i++)
StaggeredGridTile.count(
crossAxisCellCount: i % 2 == 0 ? 2:1,
mainAxisCellCount: i % 2 == 0 ? 2:1,
child: i.isEven? ItemCard(
item: listItem[i],
):ZoomItem(
child: ItemCard(
item: listItem[i],
),
),
)
],
crossAxisCount: 4);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论