【问题标题】:parallax effect | scrollable background image in flutter视差效果|颤动中的可滚动背景图像
【发布时间】:2019-10-17 17:19:24
【问题描述】:

我正在尝试实现可滚动的背景图像(视差)。 就像在主屏幕启动器中一样。

一个例子: 在 Evie 启动器中: this video

我已经尝试使用 AnimatedBuilder 在像这样的文档中提到 here。

我使用ValueNotifier<double> 作为 AnimatedBuilder Widget 动画的监听器。

完整的代码是这样的

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.network(
                   "https://w.wallhaven.cc/full/r2/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
  • 因为动画完成后该值将变为零,所以它会像这样捕捉: this video

我尝试在 _notifier.value 变为零之前存储该值,并在它返回零时使用它,但它导致了我在上面的视频中向您展示的那种奇怪的过渡。

你建议可以做些什么来制作类似可滚动壁纸的东西?

类似的东西

Design

【问题讨论】:

标签: image flutter flutter-animation


【解决方案1】:

这并不像我想象的那么简单。

TLDR; Github 阅读 cmets。

我使用ValueNotifier&lt;double&gt; 来控制滚动。

然后,我使用了带有 alignment 属性的 OverflowBox 而不是 Transform.translate。这是在渲染前根据notifier.value 计算出来的。

并以全屏模式显示图像:

我将AspectRatio 与一个孩子DecoratedBox 一起使用,其decoration 是BoxDecoration,其image 是ImageProvider。

所有代码都可以在github上找到here。 (阅读 cmets)

而且 github 上的 this issue 有一些详细的信息和一个不太复杂的替代实现 Antonello Galipò

【讨论】:

  • 我知道不鼓励仅链接的答案,但代码很大。不能确定我的 github 帐户会在 10 年后保留。
  • 很好的解决方案,它有帮助。实际上,我用水平列表视图更改了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
相关资源
最近更新 更多