【问题标题】:Flutter: How to add BackdropFilter to SliverAppBarFlutter:如何将 BackdropFilter 添加到 SliverAppBar
【发布时间】:2021-10-20 15:01:09
【问题描述】:

我想将BackdropFilter() 添加到SliverAppbar()

我希望它看起来像 iOS 应用程序库应用栏:https://cln.sh/eP8wfY

Header sliver not floating over the list in a NestedScrollView 会这样做,但仅限于标题,我希望 titleactions 在背景模糊时可见。

谢谢!

编辑

页面是什么样的:https://cln.sh/vcCY4j

Github Gist 和我的代码:https://gist.github.com/HadyMash/21e7bd2f7e202de02837505e1c7363e9

【问题讨论】:

    标签: flutter flutter-sliver flutter-sliverappbar


    【解决方案1】:

    注意:即使花费了数小时的时间,颜色也会变得很困难。

    • 你需要改变颜色
    • 你们中的一些人发现一些区域问题可能是由于 safeArea 或 CupertinoNavBar。
    • 您可以移除/更改阴影上的颜色,我在测试时给出的太多了。
    • 所有你必须玩的颜色和LinearGradient

    输出


    这是我的概念:

    Stack
        - backgroundImage
        - Container with white.3
             - CustomScrollView
                  - SliverToBoxAdapter 2x kToolbarHeight for extra height for GridList, 
                  - SliverGrid
         - LinearGradient 2xkToolbarHeight for fadeEffect on upper scroll
         - our widget TextField or anything
    

    演示

    
    class Body extends StatelessWidget {
      const Body({Key? key}) : super(key: key);
    
      Widget build(BuildContext context) {
        return Scaffold(
          body: LayoutBuilder(
            builder: (context, constraints) => Stack(
              children: [
                Container(
                  decoration: BoxDecoration(
                    // color: Colors.white.withOpacity(.3),
                    image: DecorationImage(
                      image: AssetImage("assets/me.jpg"),
                      fit: BoxFit.cover,
                    ),
                  ),
                  child: Container(),
                ),
                Container(
                  decoration: BoxDecoration(
                    color: Colors.white.withOpacity(.3),
                  ),
                  child: CustomScrollView(
                    slivers: [
                      SliverToBoxAdapter(
                        child: SizedBox(
                          height: kToolbarHeight * 2,
                        ),
                      ),
                      SliverPadding(
                        padding: EdgeInsets.all(20),
                        sliver: SliverGrid.count(
                          crossAxisCount: 2,
                          mainAxisSpacing: 20,
                          crossAxisSpacing: 20,
                          children: [
                            ...List.generate(
                                12,
                                (index) => Container(
                                      decoration: BoxDecoration(
                                        color: index % 3 == 0
                                            ? Colors.deepPurple
                                            : index % 3 == 1
                                                ? Colors.deepOrange
                                                : Colors.amberAccent,
                                        borderRadius: BorderRadius.circular(12),
                                      ),
                                    ))
                          ],
                        ),
                      )
                    ],
                  ),
                ),
                Align(
                  alignment: Alignment.topCenter,
                  child: Container(
                    height: kToolbarHeight * 2,
                    width: constraints.maxWidth,
                    decoration: BoxDecoration(
                      gradient: LinearGradient(
                        begin: Alignment.topCenter,
                        end: Alignment.bottomCenter,
                        colors: [
                          Colors.grey,
                          Colors.white.withOpacity(.7),
                        ],
                      ),
                    ),
                    child: Text(""),
                  ),
                ),
                Positioned(
                  top: kTextTabBarHeight * 1.122,
    
                  /// need to tweek
                  left: 20,
                  right: 20,
                  child: Container(
                    height: kToolbarHeight,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(12),
                      color: Colors.white70,
                      boxShadow: [
                        BoxShadow(
                            blurRadius: 12,
                            spreadRadius: 6,
                            color: Colors.black54,
                            offset: Offset(0, 12))
                      ],
                    ),
                    child: Row(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        GestureDetector(
                            onTap: () {
                              print("boosm");
                            },
                            child: Text("Tap")),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    

    【讨论】:

    • 您好,非常感谢您的帮助!有没有办法对SliverAppBar() 执行此操作?这是我的错,因为我应该早点包含这些信息。第一页有一个带有 Sliver 标题的 NestedScrollView(),然后我有一个包含一些条件逻辑和一个 ListView.builder() 的正文。第二页有一个NestedScrollView() 和一个SliverAppBar()。它们的外观如下:cln.sh/vcCY4j。这是代码的要点:gist.github.com/HadyMash/21e7bd2f7e202de02837505e1c7363e9.
    • github.com/flutter/flutter/issues/48212#issuecomment-750785885。这是我正在考虑的一种解决方法,但我不确定如何将BackdropFilter() 添加到SliverAppBar()。问题是我不知道如何将 BackdropFilters 添加到 SliverAppBar() 或如何将其包含在 Stack() 中。
    【解决方案2】:

    TL;DR 我使用普通的AppBar() 解决了这个问题,因为我不需要SliverAppBar()。我制作了一个自定义应用栏来解决问题(请参阅问题末尾的代码)。


    我意识到我不需要SilverAppBar(),因为它只会保留floatingpinned。这让我的生活变得轻松多了,因为我可以使用AppBar() 并在Scaffold() 中将extendBodyBehindAppBar 设置为true。这样我就不必制作自定义条子小部件,因为我不熟悉制作它们。

    我的解决方案是自定义AppBar()。我会有一个Stack() 然后把模糊效果和AppBar() 放在它上面。

    https://github.com/flutter/flutter/issues/48212 表明您不能将ShaderMasks()BackdropFilter()s 一起使用。为了解决这个问题,我用一堆BackdropFilter()s 制作了一个专栏。它们将具有递减的 sigma 值来创建我正在寻找的渐变效果。但是,这不是很高效,并且在较重的应用程序中无法正常工作。让每个块都具有单个逻辑像素的长度太重了,所以我将其设置为 2 个逻辑像素。

    它也可以很容易地扩展,例如,像我一样通过添加淡入淡出效果。

    这是结果的样子。

    这是解决方案的代码:

    import 'dart:math';
    import 'dart:ui';
    import 'package:flutter/material.dart';
    
    class BlurredAppBar extends StatelessWidget implements PreferredSizeWidget {
      final String title;
      final List<Widget>? actions;
    
      /// An `AppBar()` which has a blur effect behind it which fades in to hide it
      /// until content appears behind it. This has a similar effect to the iOS 14
      /// App Library app bar. It also has the possibility of having a fade effect to
      /// redude the opacity of widgets behind the `BlurredAppBar()` using a `LinearGradient()`.
      const BlurredAppBar({required this.title, this.actions, Key? key})
          : super(key: key);
    
      /// The height of the `AppBar()`
      final double height = 56;
    
      /// Returns a `List<Widget>` of `BackdropFilter()`s which have decreasing blur values.
      /// This will create the illusion of a gradient blur effect as if a `ShaderMask()` was used.
      List<Widget> _makeBlurGradient(double height, MediaQueryData mediaQuery) {
        List<Widget> widgets = [];
        double length = height + mediaQuery.padding.top;
    
        for (int i = 1; i <= (length / 2); i++) {
          widgets.add(
            ClipRRect(
              child: BackdropFilter(
                filter: ImageFilter.blur(
                  sigmaX: max(((length / 2) - i.toDouble()) / 2, 0),
                  sigmaY: min(5, max(((length / 2) - i.toDouble()) / 2, 0)),
                ),
                child: SizedBox(
                  height: 2,
                  width: mediaQuery.size.width,
                ),
              ),
            ),
          );
        }
    
        return widgets;
      }
    
      @override
      Widget build(BuildContext context) {
        final MediaQueryData mediaQuery = MediaQuery.of(context);
    
        return Stack(
          children: [
            // BackdropFilters
            SizedBox(
              height: height + mediaQuery.padding.top,
              child: Column(
                children: _makeBlurGradient(height, mediaQuery),
              ),
            ),
            // Fade effect.
            Container(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  stops: [0.5, 1],
                  colors: [
                    Colors.white.withOpacity(0.8),
                    Colors.white.withOpacity(0),
                  ],
                ),
              ),
            ),
    
            // AppBar
            AppBar(
              title: Text(
                title,
                style: Theme.of(context).textTheme.headline3,
              ),
              automaticallyImplyLeading: false,
              actions: actions,
            ),
          ],
        );
      }
    
      @override
      Size get preferredSize => Size.fromHeight(height);
    }
    
    

    【讨论】:

      猜你喜欢
      • 2018-12-19
      • 1970-01-01
      • 2020-06-26
      • 2020-05-04
      • 2020-02-25
      • 2019-06-20
      • 2019-05-27
      • 1970-01-01
      • 2020-05-06
      相关资源
      最近更新 更多