颤振中的内阴影效果

问题描述 投票:0回答:10

根据github问题,ShadowBox中还没有inset属性。是否有任何解决方法如何在颤动中立即模拟内部阴影。

我喜欢实现内阴影效果,如下图所示

enter image description here

enter image description here

flutter flutter-layout shadow
10个回答
68
投票
decoration: BoxDecoration(
        boxShadow: [
          const BoxShadow(
            color: your_shadow_color,
          ),
          const BoxShadow(
            color: your_bg_color,
            spreadRadius: -12.0,
            blurRadius: 12.0,
          ),
        ],
      ),

28
投票

这就是我所做的:

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class InnerShadow extends SingleChildRenderObjectWidget {
  const InnerShadow({
    Key key,
    this.blur = 10,
    this.color = Colors.black38,
    this.offset = const Offset(10, 10),
    Widget child,
  }) : super(key: key, child: child);

  final double blur;
  final Color color;
  final Offset offset;

  @override
  RenderObject createRenderObject(BuildContext context) {
    final _RenderInnerShadow renderObject = _RenderInnerShadow();
    updateRenderObject(context, renderObject);
    return renderObject;
  }

  @override
  void updateRenderObject(
      BuildContext context, _RenderInnerShadow renderObject) {
    renderObject
      ..color = color
      ..blur = blur
      ..dx = offset.dx
      ..dy = offset.dy;
  }
}

class _RenderInnerShadow extends RenderProxyBox {
  double blur;
  Color color;
  double dx;
  double dy;

  @override
  void paint(PaintingContext context, Offset offset) {
    if (child == null) return;

    final Rect rectOuter = offset & size;
    final Rect rectInner = Rect.fromLTWH(
      offset.dx,
      offset.dy,
      size.width - dx,
      size.height - dy,
    );
    final Canvas canvas = context.canvas..saveLayer(rectOuter, Paint());
    context.paintChild(child, offset);
    final Paint shadowPaint = Paint()
      ..blendMode = BlendMode.srcATop
      ..imageFilter = ImageFilter.blur(sigmaX: blur, sigmaY: blur)
      ..colorFilter = ColorFilter.mode(color, BlendMode.srcOut);

    canvas
      ..saveLayer(rectOuter, shadowPaint)
      ..saveLayer(rectInner, Paint())
      ..translate(dx, dy);
    context.paintChild(child, offset);
    context.canvas..restore()..restore()..restore();
  }
}

然后在某个地方使用它:

InnerShadow(
  blur: 5,
  color: const Color(0xFF477C70),
  offset: const Offset(5, 5),
  child: Container(
    decoration: const BoxDecoration(
      borderRadius: BorderRadius.all(Radius.circular(8)),
      color: Color(0xFFE9EFEC),
    ),
    height: 100,
  ),
)

结果: result


16
投票

我已经接受了@AlexandrPriezzhev的答案,并将其改进为使用标准

Shadow
类(包括其
offset
字段的语义),添加了对多个阴影的支持,并删除了
saveLayer()
调用,该调用应该使它更有效率一点:

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class InnerShadow extends SingleChildRenderObjectWidget {
  const InnerShadow({
    Key? key,
    this.shadows = const <Shadow>[],
    Widget? child,
  }) : super(key: key, child: child);

  final List<Shadow> shadows;

  @override
  RenderObject createRenderObject(BuildContext context) {
    final renderObject = _RenderInnerShadow();
    updateRenderObject(context, renderObject);
    return renderObject;
  }

  @override
  void updateRenderObject(
      BuildContext context, _RenderInnerShadow renderObject) {
    renderObject.shadows = shadows;
  }
}

class _RenderInnerShadow extends RenderProxyBox {
  late List<Shadow> shadows;

  @override
  void paint(PaintingContext context, Offset offset) {
    if (child == null) return;
    final bounds = offset & size;

    context.canvas.saveLayer(bounds, Paint());
    context.paintChild(child!, offset);

    for (final shadow in shadows) {
      final shadowRect = bounds.inflate(shadow.blurSigma);
      final shadowPaint = Paint()
        ..blendMode = BlendMode.srcATop
        ..colorFilter = ColorFilter.mode(shadow.color, BlendMode.srcOut)
        ..imageFilter = ImageFilter.blur(
            sigmaX: shadow.blurSigma, sigmaY: shadow.blurSigma);
      context.canvas
        ..saveLayer(shadowRect, shadowPaint)
        ..translate(shadow.offset.dx, shadow.offset.dy);
      context.paintChild(child!, offset);
      context.canvas.restore();
    }

    context.canvas.restore();
  }
}

6
投票

詹姆斯的答案在外部产生了一个阴影,使形状扭曲。穆罕默德的答案是渐变而不是正确的阴影,但亚历山大的解决方案非常适合我,只需一个小修复! rectInner 必须更新。

final Rect rectInner = Rect.fromLTWH(
    offset.dx,
    offset.dy,
    size.width,
    size.height,
);

4
投票

您可以使用多个 BoxShadow 来完成此操作,其中第一个(下面)较暗,顶部较亮,并在其顶部加上灰色边框以使容器弹出。

代码:

Container(
                        width: 100,
                        height: 100,
                        alignment: Alignment.center,
                        decoration: BoxDecoration(
                            border: Border.fromBorderSide(
                              BorderSide(color: Colors.black12),
                            ),
                            shape: BoxShape.circle,
                            boxShadow: [
                              BoxShadow(color: Colors.black, blurRadius: 1, spreadRadius: 0),
                              BoxShadow(color: Colors.white, blurRadius: 10, spreadRadius: 5),
                            ]),
                        child: Icon(Icons.pause, size: 70, color: Colors.black54),
                      ),

结果:


4
投票

或者,您可以通过使用普通的盒子阴影和两个容器来解决此问题 - 外部容器充当背景,内部容器提供阴影。

代码:

      Container(
          padding: EdgeInsets.only(top: 30, left: 10, right: 10),
          child: Container(
              padding: EdgeInsets.all(10),
              child: Container(
                  decoration: BoxDecoration(
                      color: Colors.grey,
                      borderRadius: BorderRadius.all(Radius.circular(12))),
                  padding: EdgeInsets.all(10),
                  child: Container(
                    padding: EdgeInsets.zero,
                    decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.all(Radius.circular(8)),
                        boxShadow: [
                          BoxShadow(
                              color: Colors.white,
                              blurRadius: 10,
                              spreadRadius: 10)
                        ]),
                    width: double.infinity,
                    height: 272,
                    child: Center(
                      child: Text("Content goes here"),
                    ),
                  )))),

生产: Screen shot


1
投票

詹姆斯的回答对我来说没有效果。

所以我只是通过在容器/图像上方放置一个内部Gradient层来实现它,因此,我有了我想要的内部阴影(仅从我的情况的底部)。

Stack(children: <Widget>[
      Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            fit: BoxFit.cover,
            image: AssetImage('images/bg.jpg') /*NetworkImage(imageUrl)*/,
          ),
        ),
        height: 350.0,
      ),
      Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: FractionalOffset.topCenter,
            end: FractionalOffset.bottomCenter,
            colors: [
              Colors.grey.withOpacity(0.0),
              Colors.black54,
            ],
            stops: [0.95, 1.0],
          ),
        ),
      )
    ],
  )

0
投票

如果您对只使用一个软件包感到满意,我发现这个软件包效果很好。

https://pub.dev/packages/sums_inner


0
投票

找到这个包:https://pub.dev/packages/inner_shadow_widget

非常适合我:

InnerShadow(
 blur: 3,
 offset: const Offset(2, 2),
 child: Image.asset('path'),
),

无内阴影

enter image description here

有内阴影

enter image description here


0
投票

更新:https://pub.dev/packages/flutter_inner_shadow

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: SizedBox(
        height: 100,
        width: 100,
        child: InnerShadow(
          shadows: [
            Shadow(
                color: Colors.black.withOpacity(0.25),
                blurRadius: 10,
                offset: Offset(2, 5))
          ],
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(10),
              color: Colors.red,
            ),
          ),
        ),
      ),
    ),
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.