实现像 Louis Vuitton 应用程序这样的项目列表视图的自定义水平滚动
Implementing custom horizontal scroll of listview of items like Louis Vuitton app
最近下载了Louis Vuitton App. I found a strange type of horizontal scroll of product items in listview. I tried card_swiper包,但是无法通过。我怎样才能实现下面gif中的滚动?
这里的技巧是使用堆栈并且:
- 使用页面视图显示除第一个元素之外的所有元素
- 使用左对齐
FractionallySizedBox
显示第一项并随着第一项偏移量增长
我尝试了几次,但结果非常令人满意,我会让你添加袋子,但这里你使用彩色盒子 ;) :
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: FunList()));
}
class FunList extends StatefulWidget {
@override
State<FunList> createState() => _FunListState();
}
class _FunListState extends State<FunList> {
/// The colors of the items in the list
final _itemsColors = List.generate(
100,
(index) => Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
);
/// The current page of the page view
double _page = 0;
/// The index of the leftmost element of the list to be displayed
int get _firstItemIndex => _page.toInt();
/// The offset of the leftmost element of the list to be displayed
double get _firstItemOffset => _controller.hasClients ? 1 - (_page % 1) : 1;
/// Controller to get the current position of the page view
final _controller = PageController(
viewportFraction: 0.25,
);
/// The width of a single item
late final _itemWidth = MediaQuery.of(context).size.width * _controller.viewportFraction;
@override
void initState() {
super.initState();
_controller.addListener(() => setState(() {
_page = _controller.page!;
}));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: Stack(
children: [
Positioned.fill(
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: _itemWidth,
child: FractionallySizedBox(
widthFactor: _firstItemOffset,
heightFactor: _firstItemOffset,
child: PageViewItem(color: _itemsColors[_firstItemIndex]),
),
),
),
),
SizedBox(
height: 200,
child: PageView.builder(
padEnds: false,
controller: _controller,
itemBuilder: (context, index) {
return Opacity(
opacity: index <= _firstItemIndex ? 0 : 1,
child: PageViewItem(color: _itemsColors[index]),
);
},
itemCount: _itemsColors.length,
),
),
],
),
);
}
}
class PageViewItem extends StatelessWidget {
final Color color;
const PageViewItem({
Key? key,
required this.color,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10),
color: color,
);
}
}
最近下载了Louis Vuitton App. I found a strange type of horizontal scroll of product items in listview. I tried card_swiper包,但是无法通过。我怎样才能实现下面gif中的滚动?
这里的技巧是使用堆栈并且:
- 使用页面视图显示除第一个元素之外的所有元素
- 使用左对齐
FractionallySizedBox
显示第一项并随着第一项偏移量增长
我尝试了几次,但结果非常令人满意,我会让你添加袋子,但这里你使用彩色盒子 ;) :
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: FunList()));
}
class FunList extends StatefulWidget {
@override
State<FunList> createState() => _FunListState();
}
class _FunListState extends State<FunList> {
/// The colors of the items in the list
final _itemsColors = List.generate(
100,
(index) => Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
);
/// The current page of the page view
double _page = 0;
/// The index of the leftmost element of the list to be displayed
int get _firstItemIndex => _page.toInt();
/// The offset of the leftmost element of the list to be displayed
double get _firstItemOffset => _controller.hasClients ? 1 - (_page % 1) : 1;
/// Controller to get the current position of the page view
final _controller = PageController(
viewportFraction: 0.25,
);
/// The width of a single item
late final _itemWidth = MediaQuery.of(context).size.width * _controller.viewportFraction;
@override
void initState() {
super.initState();
_controller.addListener(() => setState(() {
_page = _controller.page!;
}));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: Stack(
children: [
Positioned.fill(
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: _itemWidth,
child: FractionallySizedBox(
widthFactor: _firstItemOffset,
heightFactor: _firstItemOffset,
child: PageViewItem(color: _itemsColors[_firstItemIndex]),
),
),
),
),
SizedBox(
height: 200,
child: PageView.builder(
padEnds: false,
controller: _controller,
itemBuilder: (context, index) {
return Opacity(
opacity: index <= _firstItemIndex ? 0 : 1,
child: PageViewItem(color: _itemsColors[index]),
);
},
itemCount: _itemsColors.length,
),
),
],
),
);
}
}
class PageViewItem extends StatelessWidget {
final Color color;
const PageViewItem({
Key? key,
required this.color,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10),
color: color,
);
}
}