Я пытаюсь реализовать прокручиваемое фоновое изображение (параллакс).
Как в домашней панели запуска.
Пример:
В эви лаунчере:
это видео
Я пытался использовать 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,
);
}
}
Изображение можно найти здесь
Теперь у меня есть две проблемы:
- Изображение при использовании
fit: BoxFit.fitHeight
не переполняется полностью, как this
- Поскольку после завершения анимации значение станет равным нулю, оно будет привязано так:
это видео
Я пытался сохранить значение непосредственно перед тем, как _notifier.value
станет равным нулю, и использовать его, когда он возвращает ноль, но это привело к странному переходу, который я показал вам в этом видео.
Что вы можете сделать, чтобы сделать нечто вроде прокручиваемых обоев в флаттере?
как то так
Дизайн