在其他小部件上颤动阴影

Posted

技术标签:

【中文标题】在其他小部件上颤动阴影【英文标题】:Flutter shadow over other widgets 【发布时间】:2020-01-15 18:34:43 【问题描述】:

我的基本小部件是一个列。第一个元素是具有 BoxShadow 的 Container。第二个元素是一个 ListView,它根据上下文构建多个 Card。如果滚动为 0,则显示阴影。然而,当开始滚动时,卡片会“越过”阴影(较高的 z-index)并隐藏它。

未滚动

滚动

阴影应始终位于卡片上方。这是怎么做到的?

【问题讨论】:

你能分享一些代码吗?以及一些预期的用户界面?屏幕截图看起来很白,无法从细节中理解很多。对不起朋友! 【参考方案1】:

代码对解决这个问题很有帮助。但我知道您面临什么问题以及如何解决。

尝试使用Stack 而不是Column,因为Column 占据了整个屏幕空间。因此它与阴影重叠。 Stack 将帮助您在您的ListView 上方显示Container。也使用Positioned。您的ListView 需要从顶部ListItem 偏移,否则它将被Container 覆盖并且无法再触摸。

Stack(
  children: <Widget>[
    Padding(
      //padding
      child: //Listview (can also be wrapped in "Positioned")
    ),
    Positioned(
      top: 0.0, //Container at the top, ListView needs an additional offset from top, otherwise it will be covered by Container
      left: 0.0,
      right: 0.0,
      child: Container(
        decoration: BoxDecoration(
          color: //put some color
          boxShadow: [
            BoxShadow(
              color: //put some color
              offset: Offset(0, 10), //offset
              // also can do some blur etc.
          )]
        ),
        child: ListTile(
          title: //choose your title
        )
     ),
    ),
  ]
)

【讨论】:

【参考方案2】:

编辑

如果您不希望容器阴影在滚动时消失,请删除 ScrollNotificationNotificationListener

有一个小部件 ?

您可以将ScrollNotificationNotificationListener 一起使用。试试this;

编码愉快! ?

class TestPage extends StatefulWidget 
  const TestPage(Key key) : super(key: key);

  @override
  _TestPageState createState() => _TestPageState();


class _TestPageState extends State<TestPage> 
  double blurRadius = 10.0;
  double spreadRadius = 1.0;

  @override
  void initState() 
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blueGrey,
        title: Text('Title'),
      ),
      body: Container(
        width: Get.width,
        height: Get.height,
        child: Stack(
          children: [
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0).copyWith(
                top: 62.0,
              ),
              child: NotificationListener<ScrollNotification>(
                // ignore: missing_return
                onNotification: (scrollNotification) 
                  if (scrollNotification is ScrollStartNotification) 
                    setState(() 
                      blurRadius = 0.0;
                      spreadRadius = 0.0;
                    );
                   else if (scrollNotification is ScrollEndNotification) 
                    setState(() 
                      blurRadius = 10.0;
                      spreadRadius = 1.0;
                    );
                  
                ,
                child: ListView.builder(
                  // controller: _controller,
                  itemCount: 10,
                  itemBuilder: (context, index) 
                    return Card(
                      child: Container(
                          width: Get.width * .8,
                          height: 100.0,
                          child: Center(
                            child: Text('child @ index : $index'),
                          )),
                    );
                  ,
                ),
              ),
            ),
            Positioned(
              top: 0,
              left: 0,
              right: 0,
              child: Container(
                width: Get.width,
                height: 60.0,
                margin: EdgeInsets.only(),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.only(
                    bottomLeft: Radius.circular(20.0),
                    bottomRight: Radius.circular(20.0),
                  ),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.grey,
                      blurRadius: blurRadius,
                      spreadRadius: spreadRadius,
                    ),
                  ],
                ),
                child: Center(
                  child: Text('TOP CONTAINER'),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  

【讨论】:

【参考方案3】:

根据您的问题,这是这里出了什么问题的概念。

Column 的第一个孩子是 Container with shadowShadow 呈现超出定义的大小。如果您在此Container 之后不提供任何空格,我们将无法看到阴影。这个空间可以通过Container marginSizedBoxwrapping our list with Padding. But now our main question is how we get shadow while index=0. I believe it is coming from ListChildren`来完成。它们包含上部空格,这就是为什么我们只能看到第一次。

在 Ui 上渲染优先级从底部到顶部。

如何解决这个问题: 我们可以在容器底部提供空间或分配margin(不是填充),或者在container 之后使用SizedBox,提供与shadow 相同的高度。

    在容器上提供底部margin。 添加具有阴影高度的 SizedBox。 用Padding 包装我们的列表并提供top:

在这张图片中, 我们的shadow: whitebackground:amber

演示代码:

import 'package:flutter/material.dart';

class ColumnWithContainerShadow extends StatelessWidget 
  const ColumnWithContainerShadow(Key? key) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      backgroundColor: Colors.amber,
      body: Column(
        children: [
          Container(
            height: 50,
            width: double.infinity,
            ////* we dont need margin if we have padding on ListView
            // margin: EdgeInsets.only(bottom: 12),
            decoration: BoxDecoration(
              color: Colors.green,
              boxShadow: [
                BoxShadow(
                  offset: Offset(0, 12),
                  color: Colors.white,
                )
              ],
            ),
            child: Center(child: Text("Container A")),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.only(top: 12),
              child: ListView(
                children: [
                  ...List.generate(
                    333,
                    (index) => Container(
                      /// enable this margine and remove other spaces to see 1st child shadow.(shadow depend on children position)
                      // margin: EdgeInsets.only(top: 12),
                      height: 60,
                      color: Colors.deepPurple,
                      child: Text("$index"),
                    ),
                  )
                ],
              ),
            ),
          ),
          Container(
            height: 50,
            width: double.infinity,
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: Colors.green,
              boxShadow: [
                BoxShadow(
                  offset: Offset(0, 12),
                  color: Colors.white,
                )
              ],
            ),
            child: Text("Bottom Container"),
          ),
          // Comment to close shadow
          SizedBox(
            height: 20,
          )
        ],
      ),
    );
  


【讨论】:

【参考方案4】:

将上面的框包裹在Material 小部件中并提供一个高度。

【讨论】:

高程实际上不是 z-index material.io/design/environment/elevation.html 高程与 z-index 无关。它被称为高程,但只提供阴影

以上是关于在其他小部件上颤动阴影的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在不使用材料小部件的情况下提升小部件的颤动?

如何在颤动的屏幕上显示一个小部件?

如何在颤动中获取动态文本小部件的宽度?

如何将颤动文本与行中的其他小部件居中

setState 是不是会在颤动中为屏幕重建整个小部件树,以及它与其他状态管理相比如何

如何在颤动中制作音频修剪小部件