问题是这样描述的.
在web环境中,我必须建立一个图像的水平列表(如Netflix),当用户将鼠标光标放在这些图像上时,这些图像应该会增加元素的大小.为了实现这一点,我使用一个堆栈(clipBehavior
等于Clip.none
)来渲染列表中的每个项目,当我检测到鼠标悬停事件时,我添加一个新的容器(大于原始项目的大小)来绘制一个动画容器,其中将增长以填充它.
动画效果很好,但容器被定位到列表中的下一个右项,然而,我需要它位于该项之上.
代码如下:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
final double zoomTargetHeight = 320;
final double zoomTargetWidth = 500;
final double zoomOriginalHeight = 225;
final double zoomOriginalWidth = 400;
double _zoomHeight = 225;
double _zoomWidth = 400;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: Column(
children: [
Image.network("https://source.unsplash.com/random/1600x900?cars"),
Container(
color: Colors.black87,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 12,
),
const Text(
"List of items",
style: TextStyle(color: Colors.white),
),
const SizedBox(
height: 12,
),
SizedBox(
height: 235,
child: ListView.separated(
clipBehavior: Clip.none,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return buildCard(index);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 12,
);
},
itemCount: 10,
),
),
const SizedBox(
height: 200,
),
],
),
),
),
],
),
),
);
}
Map _showZoom = {};
Widget buildCard(int index) {
Stack stack = Stack(
clipBehavior: Clip.none,
children: [
MouseRegion(
onEnter: (event) {
setState(() {
_showZoom["$index"] = true;
});
},
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
Image.network(
"https://source.unsplash.com/random/400x225?sig=$index&cars"),
Container(
color: Colors.black.withAlpha(100),
height: zoomOriginalHeight,
width: zoomOriginalWidth,
),
],
),
),
),
if (_showZoom["$index"] != null && _showZoom["$index"]!)
Positioned(
left: (zoomOriginalWidth - zoomTargetWidth) / 2,
top: (zoomOriginalHeight - zoomTargetHeight) / 2,
child: MouseRegion(
onHover: (_) {
setState(() {
_zoomHeight = zoomTargetHeight;
_zoomWidth = zoomTargetWidth;
});
},
onExit: (event) {
setState(() {
_showZoom["$index"] = false;
_zoomHeight = zoomOriginalHeight;
_zoomWidth = zoomOriginalWidth;
});
},
child: SizedBox(
width: zoomTargetWidth,
height: zoomTargetHeight,
child: Center(
child: AnimatedContainer(
duration: const Duration(milliseconds: 400),
width: _zoomWidth,
height: _zoomHeight,
// color: Colors.green.withAlpha(100),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
image: DecorationImage(
image: NetworkImage(
"https://source.unsplash.com/random/400x225?sig=$index&cars"),
fit: BoxFit.cover,
),
),
),
),
),
),
),
],
);
return stack;
}
}
记住Flutter 配置--启用web