【问题标题】:Offset origin of tiled Image in FlutterFlutter中平铺图像的偏移原点
【发布时间】:2020-12-12 12:36:24
【问题描述】:

我正在尝试在 Flutter 应用程序中创建视差背景,构建它的最有效方法是使用 Stack 并将图像填充屏幕作为背景,然后将我的列表放在顶部。图像在 Y 轴上使用 ImageRepeat 平铺。然后计划将磁贴的原点与我用于列表的ScrollController 同步。然后我可以调整平铺图像的原点以创建视差效果。这应该很简单。这是上下文的一些代码:

Stack(
          children: [
            SizedBox.expand(
              child: Image(
                image: AssetImage('assets/images/tiled_background_leaf.jpg'),
                repeat: ImageRepeat.repeatY,
              ),
            ),
            CustomScrollView(
              controller: _controller,
              slivers: [ ...

我的问题是 Image 没有 offset 属性或 origin 位置。我需要一些关于最简单方法的建议。我已经看到有自定义画家、画布方法等,但是当 Image 小部件中应该有更优雅的解决方案时,它们似乎都过于复杂,或者可能在另一个小部件中可以给我相同的视差效果.

【问题讨论】:

  • 使用 Padding 作为 Image 的父级 - 文档说:“通过给定填充插入其子级的小部件。”
  • 不幸的是,这只是根据填充设置的边缘插图调整图像在其父项内的边界大小。我需要图像来填充屏幕,但将图块的起始原点设置为 0,0 以外的值。
  • 这将产生相同的结果。我需要在整个屏幕上平铺重复图像,但能够更改原点。例如,开始绘制从容器顶部向上 100 像素的图像,但仍会填充整个对象。
  • 我现在看到了,Imagealignment 属性 - 默认情况下它是“中心” - 用 FractionalOffset 更改它(两个轴范围都是 0..1)
  • 行得通!谢谢。你想写,还是我写?

标签: flutter flutter-image flutter-canvas


【解决方案1】:

感谢@pskink 对此的回答(参见上面的 cmets)。

这是仪表板的一些代码,该仪表板具有滚动的文章列表和视差滚动平铺图像作为背景...

class DashboardRoot extends StatefulWidget {
  DashboardRoot({Key key}) : super(key: key);

  @override
  _DashboardRootState createState() => _DashboardRootState();
}

class _DashboardRootState extends State<DashboardRoot> {
  int _currentIndex = 0;
  ScrollController _controller;

  double _offsetY = 0.0;

  _scrollListener() {
    setState(() {
      _offsetY = _controller.offset;
    });
  }

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      var state = Provider.of<ArticlesState>(context, listen: false);
      state.initArticleStream();
    });
    _controller = ScrollController();
    _controller.addListener(_scrollListener);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
        bottomNavigationBar: AppBottomNavigationBar(),
        body: Stack(
          children: [
            SizedBox.expand(
              child: Image(
                image: AssetImage('assets/images/tiled_background_leaf.jpg'),
                repeat: ImageRepeat.repeatY,
                alignment: FractionalOffset(0, (_offsetY / 1000) * -1),
              ),
            ),
            CustomScrollView(
              controller: _controller,
              slivers: [
                SliverAppBar(
                  elevation: 0.0,
                  floating: true,
                  expandedHeight: 120,
                  flexibleSpace: FlexibleSpaceBar(
                    title: Text(NavigationManager
                        .instance.menuItems[_currentIndex].title),
                  ),
                  actions: <Widget>[
                    IconButton(
                      icon: Icon(Icons.settings),
                      onPressed: () => {
                        locator<NavigationService>()
                            .navigateTo(SettingsNavigator.routeName)
                      },
                    ),
                    IconButton(
                      icon: Icon(Icons.menu),
                      onPressed: () => {RootScaffold.openDrawer(context)},
                    ),
                  ],
                ),
                Consumer<ArticlesState>(
                  builder: (context, state, child) {
                    final List<Article> list = state.articles;
                    if (list == null) {
                      return SliverToBoxAdapter(
                        child: Center(
                          child: CircularProgressIndicator(
                              backgroundColor: Colors.amber, strokeWidth: 1),
                        ),
                      );
                    } else if (list.length > 0) {
                      return SliverGrid(
                        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                          maxCrossAxisExtent: 200.0,
                          mainAxisSpacing: 10.0,
                          crossAxisSpacing: 10.0,
                          childAspectRatio: 1.0,
                        ),
                        delegate: SliverChildBuilderDelegate(
                          (BuildContext context, int index) {
                            Article article = list[index];
                            return ArticleCell(
                                article: article,
                                cellTapHandler: () {
                                  Navigator.pushNamed(
                                      context, ArticleDetail.routeName,
                                      arguments: new ArticleDetailArguments(
                                          article.docId, article.heading));
                                });
                          },
                          childCount: list.length,
                        ),
                      );
                    } else {
                      return Center(
                        child: Text("No Articles"),
                      );
                    }
                  },
                ),
              ],
            ),
          ],
        ));
  }
}

请注意,Stack 的背景图像位于展开的SizedBox 内,因此它会填满屏幕空间。上面的层是CustomScrollView,其中包含SliverGrid 和其他东西。

重要的是Image:

child: Image(
                image: AssetImage('assets/images/tiled_background_leaf.jpg'),
                repeat: ImageRepeat.repeatY,
                alignment: FractionalOffset(0, (_offsetY / 1000) * -1),
              ),

还有_offsetY 的属性ScrollController 监听器在用户滚动时设置:

double _offsetY = 0.0;

  _scrollListener() {
    setState(() {
      _offsetY = _controller.offset;
    });
  }

Image 对齐属性用于将对齐设置为顶部、中心、左侧等,但它也可以是任意偏移量。 FractionalOffset 值是一个范围0..1,但将其设置为大于或小于零的更大数字也绝对可以。因为图像也是使用ImageRepeat.repeatY 平铺的,所以平铺图像的原点使用对齐方式重新绘制,并且通过弄乱数字,您可以创建一个很好的视差滚动效果。

请注意FractionalOffset(0, (_offsetY / 1000) * -1) 的偏移值除以 1000(这是您的速度,值越高,背景的视差越慢(将其视为两层之间的距离)。将数字乘以-1 在正负数之间切换,并改变视差方向。

【讨论】:

  • 顺便说一句,而不是Stack,你可以使用DecoratedBox甚至普通的ContainerDecorationImage一起使用
  • 谢谢!我是新手,所以仍在发现所有这些不同的小部件。
  • 我还注意到平铺图像总是会缩小到其边界,因此如果图像需要比容器长,则必须使用 Transform.scale。透明PNG也根本无法平铺。
  • “我还注意到平铺图像总是会缩小到它的边界” - 所以我认为更好的选择是自定义 Decoration 类(用于 @987654341 @ 或Container)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多