패키지 없이 Flutter에서 Neumorphic 디자인 구현하기

9231 단어
최근에는 뉴모픽 디자인 열풍과 유사한 방식으로 UI/UX 디자인 세계를 뒤흔든 개념이 거의 없습니다. Dribbblebehance에는 웹 또는 모바일 앱에서 이 디자인 패턴의 사용을 설명하는 디자인이 가득합니다. 최소한의 디자인이므로 튀고 외치는 색상이 모두 열광하는 디자인 환경에서 부드러움과 독특함으로 인해 눈에 매우 매력적입니다.
운 좋게도 우리는 Flutter 앱에서 이러한 훌륭한 디자인을 구현하고 군중(앱*)에서 눈에 띄게 만들 수 있습니다. 어둡고 밝은 뉴모픽 디자인을 모두 구현하겠습니다. 이 시연에서는 제가 만든 간단한 핀테크 앱 UI 샘플을 사용하겠습니다.
여기는 source code
먼저 라이트 버전부터 시작하겠습니다. 앱 전체에 적용되는 모든 전역 테마 속성을 보유하는 기본 테마 위젯을 구현합니다. Color.grey[300]의 스캐폴드 배경색을 사용하여 효과적으로 튀어나오는 뉴모픽 그림자를 적용할 수 있습니다.

ThemeData lightThemeData(BuildContext context) {
  return ThemeData.light().copyWith(
      scaffoldBackgroundColor: Colors.grey[300],
}


다음으로 앱 전체에서 사용할 상자 장식 변수를 생성하여 뉴모픽 디자인에 존재하는 팝핑 효과를 생성하는 라이트 박스 그림자를 생성합니다.

final BoxDecoration decorator = BoxDecoration(
      [
              BoxShadow(
                  color: Colors.grey.shade500,
                  offset: Offset(4, 4),
                  blurRadius: 15,
                  spreadRadius: 1),
              BoxShadow(
                spreadRadius: 1,
                color: Colors.white,
                offset: Offset(-4, -4),
                blurRadius: 15,
              )
            ]);


예를 들어 컨테이너와 같이 우리가 사용하는 위젯에 신경형 그림자를 추가하려면 장식 속성에 데코레이터 변수를 추가하기만 하면 됩니다.

 Container(
              height: size.height * 0.07,
              width: size.width * 0.4,
              decoration: decorator.copyWith(
                  borderRadius: BorderRadius.circular(30.0),
                  color: Colors.greenAccent),)


경우에 따라 아래 이미지와 같이 화면에 우울증의 환상을 만들기 위해 뉴모픽 디자인 언어에 우울증 효과를 추가할 수 있습니다. Flutter로도 만들 수 있습니다.
장식 및 박스 페인터 위젯을 만들고 오목한 장식 효과를 만드는 데 사용할 색상을 추가합니다.

class SecondDecoration extends Decoration {
  final ShapeBorder? shape;
  final double? depression;
  final List<Color>? colors;

  SecondDecoration({
    @required this.shape,
    @required this.depression,
    this.colors,
  })  : assert(shape != null),
        assert(depression! >= 0),
        assert(colors == null || colors.length == 2);

  @override
  BoxPainter createBoxPainter([void onChanged]) =>
      _SecondDecorationPainter(shape!, depression!, colors!);

  @override
  EdgeInsetsGeometry get padding => shape!.dimensions;
}

class _SecondDecorationPainter extends BoxPainter {
  ShapeBorder shape;
  double depression;
  List<Color> colors;

  _SecondDecorationPainter(this.shape, this.depression, this.colors) {
    colors = [
      // Colors.black,
      // Colors.grey.shade800,
        Colors.black87,
       Colors.white
    ];
  }

  @override
  void paint(
      ui.Canvas canvas, ui.Offset offset, ImageConfiguration configuration) {
    final rect = offset & configuration.size!;
    final shapePath = shape.getOuterPath(rect);

    final delta = 16 / rect.longestSide;
    final stops = [0.5 - delta, 0.5 + delta];

    final path = Path()
      ..fillType = PathFillType.evenOdd
      ..addRect(rect.inflate(depression * 2))
      ..addPath(shapePath, Offset.zero);
    canvas.save();
    canvas.clipPath(shapePath);

    final paint = Paint()
      ..maskFilter = MaskFilter.blur(BlurStyle.normal, depression);
    final clipSize = rect.size.aspectRatio > 1
        ? Size(rect.width, rect.height / 2)
        : Size(rect.width / 2, rect.height);
    for (final alignment in [Alignment.topLeft, Alignment.bottomRight]) {
      final shaderRect =
          alignment.inscribe(Size.square(rect.longestSide), rect);
      paint.shader = ui.Gradient.linear(
          shaderRect.topLeft, shaderRect.bottomRight, colors, stops);

      canvas.save();
      canvas.clipRect(alignment.inscribe(clipSize, rect));
      canvas.drawPath(path, paint);
      canvas.restore();
    }
    canvas.restore();
  }
}


그런 다음 이 장식 위젯을 컨테이너 위젯의 장식 속성에 대한 인수로 전달합니다. 그런 다음 컨테이너에서 오목한 장식 효과를 제공하는 한 쌍의 색상을 전달합니다.

Container(
                height: 60,
                decoration: SecondDecoration(
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(10)),
                        depression: 10,
                        colors: [
                            Color.fromRGBO(216, 213, 208, 1),
                            Colors.white
                          ]))


그리고 짜잔. 이제 Flutter 앱에서 가벼운 뉴모픽 그림자 및 우울증 효과를 만들 수 있습니다.
다음으로 어두운 모드에서 동일한 것을 복제합니다.
먼저 어두운 뉴모픽 디자인을 만들 수 있도록 어두운 스캐폴드 색상으로 전체 어두운 테마를 추가합니다.

ThemeData darkThemeData(BuildContext context) {
  return ThemeData.dark().copyWith(
      scaffoldBackgroundColor:Colors.grey[900],
      );
}


그런 다음 터지는 효과를 만드는 어두운 뉴모픽 그림자를 만듭니다. 이것은 필요한 상자 그림자가 있는 BoxDecoration 개체를 보유하는 데코레이터 변수를 생성하여 수행됩니다.

final BoxDecoration decorator = BoxDecoration(
      [
              BoxShadow(
                  color: Colors.black,
                  offset: Offset(5, 5),
                  blurRadius: 15,
                  spreadRadius: 5),
              BoxShadow(
                spreadRadius: 1,
                color: Colors.grey.shade800,
                offset: Offset(-4, -4),
                blurRadius: 15,
              )
            ]);


이제 위젯 트리 아래의 컨테이너 위젯 내에서 이 변수를 사용할 수 있습니다.

Container(
              height: size.height * 0.07,
              width: size.width * 0.4,
              decoration: decorator.copyWith(
                  borderRadius: BorderRadius.circular(30.0),
                  color: Colors.greenAccent),)


그런 다음 데코레이션 및 박스 페인터 위젯을 사용하여 어두운 오목 함몰 뉴모픽 효과를 생성합니다.

class ConcaveDecoration extends Decoration {
  final ShapeBorder? shape;
  final double? depression;
  final List<Color>? colors;

  ConcaveDecoration({
    @required this.shape,
    @required this.depression,
    this.colors,
  })  : assert(shape != null),
        assert(depression! >= 0),
        assert(colors == null || colors.length == 2);

  @override
  BoxPainter createBoxPainter([void onChanged]) =>
      _ConcaveDecorationPainter(shape!, depression!, colors!);

  @override
  EdgeInsetsGeometry get padding => shape!.dimensions;
}

class _ConcaveDecorationPainter extends BoxPainter {
  ShapeBorder shape;
  double depression;
  List<Color> colors;

  _ConcaveDecorationPainter(this.shape, this.depression, this.colors) {
    colors = [
      Colors.black,
      Colors.grey.shade800,
      //   Colors.black87,
      //  Colors.white
    ];
  }

  @override
  void paint(
      ui.Canvas canvas, ui.Offset offset, ImageConfiguration configuration) {
    final rect = offset & configuration.size!;
    final shapePath = shape.getOuterPath(rect);

    final delta = 16 / rect.longestSide;
    final stops = [0.5 - delta, 0.5 + delta];

    final path = Path()
      ..fillType = PathFillType.evenOdd
      ..addRect(rect.inflate(depression * 2))
      ..addPath(shapePath, Offset.zero);
    canvas.save();
    canvas.clipPath(shapePath);

    final paint = Paint()
      ..maskFilter = MaskFilter.blur(BlurStyle.normal, depression);
    final clipSize = rect.size.aspectRatio > 1
        ? Size(rect.width, rect.height / 2)
        : Size(rect.width / 2, rect.height);
    for (final alignment in [Alignment.topLeft, Alignment.bottomRight]) {
      final shaderRect =
          alignment.inscribe(Size.square(rect.longestSide), rect);
      paint.shader = ui.Gradient.linear(
          shaderRect.topLeft, shaderRect.bottomRight, colors, stops);

      canvas.save();
      canvas.clipRect(alignment.inscribe(clipSize, rect));
      canvas.drawPath(path, paint);
      canvas.restore();
    }
    canvas.restore();
  }
}


표시 방법은 다음과 같습니다.
이제 위젯 트리 내의 컨테이너 위젯에서 이 오목한 장식 효과를 사용할 수 있습니다.

Container(
                height: 60,
                decoration:ConcaveDecoration(
                        colors: [Colors.black, Colors.grey.shade800],
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(10)),
                        depression: 10))


그 결과 앱을 위한 멋진 다크 모드 뉴모픽 디자인이 탄생했습니다.
다음은 샘플 앱의 느낌과 모양을 보여주는 그림입니다.
앱에서 라이트 모드와 다크 모드를 전환할 수 있는 기능도 구현합니다. 해당 기능을 구현하는 방법에 대한 설명을 제공했습니다.
끝까지 읽어주셔서 감사하고 앞으로 더 많은 플러터 팁을 기대해 주세요.

좋은 웹페이지 즐겨찾기