为啥 Flutter IconButton 动画显示在行下

Posted

技术标签:

【中文标题】为啥 Flutter IconButton 动画显示在行下【英文标题】:Why Flutter IconButton Animation Shows Under the Row为什么 Flutter IconButton 动画显示在行下 【发布时间】:2019-10-07 10:29:10 【问题描述】:

在我的应用程序中,我设置了一个 IconButton 来渲染具有彩色背景的 Row。不幸的是,按下按钮时的波纹动画呈现在 Row 下(如截屏视频所示)。如何在 Row 上显示波纹?

class Card extends StatelessWidget 
final Issue issue;
Color _bgColor;

Card(this.issue) 
  _bgColor = colorSwatch[issue.hashCode % colorSwatch.length];


@override
Widget build(BuildContext context) 
  return Container(
    margin: EdgeInsets.only(top: 12, left: 18, right: 18),
    padding: EdgeInsets.only(top: 8, bottom: 8),
    decoration: new BoxDecoration(
      color: _bgColor,
      border: new Border.all(color: _bgColor),
      borderRadius: BorderRadius.all(
          Radius.circular(10.0) 
          ),
    ),
    child: Row(children: [
      IconButton(
        padding: EdgeInsets.only(right: 16),
        icon: Icon(Icons.play_arrow, color: Colors.white, size: 48),
        tooltip: 'Start $issue.issueName',
        onPressed: () ,
      ),
      Expanded(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              padding: const EdgeInsets.only(bottom: 8),
              child: Text(
                issue.title,
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
                softWrap: true,
              ),
            ),
            Text(
              issue.issueName,
              style: TextStyle(
                color: Colors.white,
              ),
            ),
          ],
        ),
      ),
    ]));
  

【问题讨论】:

【参考方案1】:

波纹是Material 效果的一部分。用Material 包裹你的IconButton

Material(
  color: _bgColor,
  child: IconButton(
    padding: EdgeInsets.only(right: 16),
    icon: Icon(Icons.play_arrow, color: Colors.white, size: 48),
    tooltip: 'Start $issue.issueName',
    onPressed: () ,
  ),
),

更新

为了更具体地实现您的目标,您可以将Container 替换为Material

return Material(
  color: _bgColor,
  borderRadius: BorderRadius.all(Radius.circular(10.0)),
  child: Container(
     margin: EdgeInsets.only(top: 12, left: 18, right: 18),
     padding: EdgeInsets.only(top: 8, bottom: 8),
     backgroundBlendMode: BlendMode.multiply,
     child: Row(
     ...
  ),
);

【讨论】:

这可行,但材质没有边距或填充。啊,让我试试吧 所以我所做的就是用材料包裹最上面的容器,它可以工作。将您的答案更新为可以编译的内容,我会接受作为答案:-) 对不起朋友...看起来这个解决方案不完整。根据@alexendar kwint(和github.com/flutter/flutter/issues/31541),它还需要一个带有backgroundBlendMode: BlendMode.multiply 的容器【参考方案2】:

这看起来像是 Flutter 框架中的一个错误。 这只发生在 IconButton 上,FlatButton 没有问题。

可能的解决方法是将 BlendMode 设置为乘法 BlendMode.multiply。 试试这个:

Container(
          decoration: BoxDecoration(
              color: Colors.greenAccent[400],
              backgroundBlendMode: BlendMode.multiply),
          child: ListTile(
            leading: IconButton(icon: Icon(Icons.play_arrow), onPressed: () ),
            title: Text("issue title"),
            subtitle: Text("description"),
          ),
        ),

更新 问题github

【讨论】:

很高兴听到这是一个错误,但以上内容对我不起作用。请注意,在我的代码中,我有一个 Row 而不是 ListTile...我将 blendmode 应用于最顶层的容器 啊,看起来它也需要一个 Material 祖先。【参考方案3】:

您可以将Row 包裹在InkWell 中,这会给您带来触摸涟漪。

我已删除容器的背景颜色,显示波纹时出现问题,并将文本颜色更改为黑色。

    @override
  Widget build(BuildContext context) 
    return Container(
        height: 100,
        margin: EdgeInsets.only(top: 12, left: 18, right: 18),
        padding: EdgeInsets.only(top: 8, bottom: 8),
        decoration: new BoxDecoration(
          color: Colors.transparent,
          border: new Border.all(color: Colors.orange),
          borderRadius: BorderRadius.all(Radius.circular(10.0)),
        ),
        child: InkWell(
          // added here
          onTap: () ,
          child: Row(children: [
            IconButton(
              padding: EdgeInsets.only(right: 16),
              icon: Icon(Icons.play_arrow, color: Colors.black, size: 48),
              tooltip: 'Start issue',
              onPressed: () ,
            ),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Container(
                    padding: const EdgeInsets.only(bottom: 8),
                    child: Text(
                      'issue.title',
                      style: TextStyle(
                        color: Colors.black,
                        fontWeight: FontWeight.bold,
                      ),
                      softWrap: true,
                    ),
                  ),
                  Text(
                    'issue.issueName',
                    style: TextStyle(
                      color: Colors.black,
                    ),
                  ),
                ],
              ),
            ),
          ]),
        ));
  

参考文献

Add ripples

【讨论】:

【参考方案4】:

Ripple 始终位于材质小部件之上。因此,如果材质小部件顶部有任何东西,您将在小部件下方看到涟漪。

只需将您的 IconButton 包装为 Material 小部件,并将材质设置为使用“透明”类型,它应该可以工作。

您可以使用以下通用小部件为小部件添加波纹。

class AddRipple extends StatelessWidget 
  final Widget child;
  final Function onTap;

  AddRipple(@required this.child, @required this.onTap);

 @override
 Widget build(BuildContext context) 
 return Stack(
     children: <Widget>[
     child,
      Positioned.fill(
        child: new Material(
            color: Colors.transparent,
            child: new InkWell(
              onTap: onTap,
            ))),
      ],
    );
  

您还可以在 InkWell 小部件的构造函数和用户“splashColor”属性中获取颜色以设置启动颜色。

【讨论】:

以上是关于为啥 Flutter IconButton 动画显示在行下的主要内容,如果未能解决你的问题,请参考以下文章

Flutter - 如何为 IconButton 赋予颜色?

Flutter中常用的按钮组件-IconButton(可点击的Icon)

Flutter中常用的按钮组件-IconButton(可点击的Icon)

Flutter:IconButton onPressed 在控制台中响应但在显示中没有响应

Flutter基础Widget之按钮(RaisedButton、FlatButton、OutlineButton,IconButton)

谁能告诉我为啥在尝试实现动画时在 Flutter 中出现此错误