0

我想将 a 添加BackdropFilter()SliverAppbar().

我希望它看起来像 iOS App Library App Bar:https ://cln.sh/eP8wfY 。

标题条不浮动在 NestedScrollView 中的列表上,但只浮动到标题,我希望titleactions在背景模糊时可见。

谢谢!

编辑

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

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

4

2 回答 2

2

注意:即使花费了数小时的时间,也很难在颜色上。

  • 你需要改变颜色
  • 你们中的一些人发现了一些可能是由于 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")),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

于 2021-08-19T00:15:37.687 回答
0

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


我意识到我不需要 aSilverAppBar()因为它只会保留floatingpinned。这让我的生活变得轻松多了,因为我可以AppBar()在. 这样我就不必制作自定义条子小部件,因为我不熟悉制作它们。extendBodyBehindAppBartrueScaffold()

我的解决方案是自定义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);
}

于 2021-08-19T19:34:24.167 回答