我正在尝试实现可滚动的背景图像(视差)。 就像在主屏幕启动器中一样。
一个例子: 在Evie启动器中: this video
我曾尝试使用像这样的文档中提到的here中的AnimatedBuilder
。
我正在使用ValueNotifier<double>
作为AnimatedBuilder小部件的动画的侦听器。
完整的代码是这里
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PageView Scrolling',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>{
ValueNotifier<double> _notifier;
double _prevnotifier;
double getOffset(){
if (_notifier.value == 0 && _prevnotifier != null){
return _prevnotifier;
}
return _notifier.value;
}
@override
void dispose() {
_notifier?.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_notifier = ValueNotifier<double>(0);
_prevnotifier = _notifier.value;
_notifier.addListener(
(){
print('object ${_notifier.value}');
if (_notifier.value != 0)
_prevnotifier = _notifier.value;
}
);
}
@override
Widget build(BuildContext context) {
print("Size is ${MediaQuery.of(context).size}");
return Scaffold(
body: Stack(
children: <Widget>[
AnimatedBuilder(
animation: _notifier,
builder: (context, _) {
return Transform.translate(
offset: Offset(-getOffset() * 60, 0),
child: Image.asset(
"assets/wallhaven-r276qj.png",
height: MediaQuery.of(context).size.height,
fit: BoxFit.fitHeight
),
);
},
),
NotifyingPageView(
notifier: _notifier,
),
],
),
);
}
}
class NotifyingPageView extends StatefulWidget {
final ValueNotifier<double> notifier;
const NotifyingPageView({Key key, this.notifier}) : super(key: key);
@override
_NotifyingPageViewState createState() => _NotifyingPageViewState();
}
class _NotifyingPageViewState extends State<NotifyingPageView> {
int _previousPage;
PageController _pageController;
void _onScroll() {
// Consider the page changed when the end of the scroll is reached
// Using onPageChanged callback from PageView causes the page to change when
// the half of the next card hits the center of the viewport, which is not
// what I want
if (_pageController.page.toInt() == _pageController.page) {
_previousPage = _pageController.page.toInt();
}
widget.notifier?.value = _pageController.page - _previousPage;
}
@override
void initState() {
_pageController = PageController(
initialPage: 0,
viewportFraction: 0.9,
)..addListener(_onScroll);
_previousPage = _pageController.initialPage;
super.initState();
}
List<Widget> _pages = List.generate(
10,
(index) {
return Container(
height: 10,
alignment: Alignment.center,
color: Colors.transparent,
child: Text(
"Card number $index",
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
);
},
);
@override
Widget build(BuildContext context) {
return PageView(
children: _pages,
controller: _pageController,
);
}
}
可以找到图像here
现在我有两个问题:
fit: BoxFit.fitHeight
时,图像没有像this那样完全溢出我尝试在_notifier.value
变为零之前存储值,并在它返回零时使用它,但这导致了上面视频中向您展示的怪异转换。
您认为可以做些什么来使像可滚动墙纸一样飘动?
类似这样的东西
答案 0 :(得分:0)
这不像我想象的那么简单。
TLDR ; Github阅读评论。
我使用了如上所述的ValueNotifier<double>
来控制滚动。
然后,我使用OverflowBox
的Transform.translate
属性代替了alignment
。该值是根据渲染前的notifier.value
计算出来的。
并以全屏模式显示图像:
我将AspectRatio
与孩子DecoratedBox
一起使用,孩子decoration
是BoxDecoration
,其image
为ImageProvider
。
所有代码都可以在github上找到here。 (阅读评论)
在GitHub上的this issue上有一些详细的信息,而Antonello Galipò的替代实现则不太复杂