Container(
height: 56,
width: 240,
color: Colors.indigo,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: ...,
)
위 코드를 실행하면, 다음과 같은 컴파일 에러를 마주한다.
예외가 발생했습니다.
_AssertionError ('package:flutter/src/widgets/container.dart': Failed assertion: line 270 pos 15: 'color == null || decoration == null': Cannot provide both a color and a decoration To provide both, use "decoration: BoxDecoration(color: color)".)
이 경고창은 container.dart
문서에 assert 문으로 선언된 내용이 호출된 것이다.
직역 내옹은 다음과 같습니다. 고마워 Bard
색상과 장식 모두 제공할 수 없습니다. 둘 다 제공하려면 "decoration: BoxDecoration(color: color)"를 사용하세요.
번역투로 작성된 장식이 Decoration 이다. 그냥 지금 현상 그 자체에 대해서 설명해주지, "왜" 사용하지 못하는 지는 알 수 없다.
Container
initialzer method 를 보자Cotainer
객체의 초기화 메서드 영역을 가보면 다음과 같은 주석이 포함되어 있다.
/// The `color` and `decoration` arguments cannot both be supplied, since
/// it would potentially result in the decoration drawing over the background
/// color.
내용은 간단하다. color
파라미터와 decoration
파라미터를 같이 쓰게될 경우, color 값이 추가되었음에도 decoration
에서 다시 그려버릴 수 있다는 것이다. 이렇게 되면, 개발자 입장에서 color
값을 추가했음에도 추가되지 않은 것처럼 보일 것이다. 실제로는 두 번 그리게 된 것이지만.
그래서 그런 동작을 막기 위해서 assert
문을 통해서 통제하고 있다. 덤으로 이걸 막게되면 쓸데없이 랜더링을 두번하는 것을 막을 수도 있으니 성능에도 효과가 있을 것이다.
결론은 같은 Color 객체를 파라미터로 요구하고 있다.
먼저 color
파라미터에서 받고 있는 타입은 Color
이다. 해당 타입은 아래 경로에 위치해 있다.
...>flutter>bin>cache>pkg>sky_engine>lib>ui>painting.dart>Color
이 경로를 보다보면, sky_engine
이라는 것이 있어서, 내가 모르는 새로운 엔진인줄 알았다. 해당 README.md
를 살펴보니, Flutter Engine 과 Dart 의 인터페이스라고 한다.
위 그림은 많이 봤을 것이다. SkyEngine 의 위치는 제일 위에 있는 Framework Dart
에 위치한다.
이 프레임 워크에서는 Flutter 에서 우리가 작성한 코드가 들어간다고 생각하면 간단하다. sky_engine
에서는 i/o, async. dart:ui
및 일반적인 ui 내용이 들어가 있는 인터페이스다.
Flutter Engine
==============
This package describes the dart:ui library, which is the interface between
Dart and the Flutter Engine. This package also contains a number of Flutter
shell binaries that let you run code that uses the dart:ui library on various
platforms.
본론으로 돌아와서, 그러면 Decoration
에서는 어떤 Color
타입을 받고 있을지 찾아보자.
만약 직접 찾아보려고 시도했다면, 당황할 것이다. 왜냐하면 Decoration
은 구현 객체가 아닌 추상객체이댜. 즉, 인터페이스다. 아래 코드 일부분이다.
abstract class Decoration with Diagnosticable { ... }
그러면 "구현" 객체는 어디있을까? 바로 BoxDecoration
이다. 실제로 구현할 떄, 쓰는 객체가 구현 객체다.당연한말의 반복
class BoxDecoration extends Decoration { ... }
여기서 Color 를 쫓아가면 똑같은 경로를 마주한다.
결론은, 첫 문장에서도 말했다시피 같은 Color 타입을 바라보고 있다.
...>flutter>bin>cache>pkg>sky_engine>lib>ui>painting.dart>Color
Container
에서 color
파라미터와 decoration
파라미터를 동시에 사용하지 못하도록 하는 이유는 배경색이라는 하나의 속성을 두 개의 파라미터에서 접근하려고 하기에, 동시 접근을 막아둔 것 같다.
프레임워크 설계 시, 사용자가 잘못 사용될 우려를 assert
문을 통해 확실히 전달하는게 중요하다는 걸 느꼈다. 이것은 단순히 프레임워크 설계뿐만 아니라, 나의 코드를 다른 사람이 사용할 때도 이런식으로 전달해두면, 좋을 것 같다는 생각을 했다.
마지막으로 Container
의 초기화 메서드 부분을 공유한다.
/// <-------아부분임---------->
으로 표시해두었다.
class Container extends StatelessWidget {
/// Creates a widget that combines common painting, positioning, and sizing widgets.
///
/// The `height` and `width` values include the padding.
/// <-------아부분임---------->
/// The `color` and `decoration` arguments cannot both be supplied, since
/// it would potentially result in the decoration drawing over the background
/// color. To supply a decoration with a color, use `decoration:
/// BoxDecoration(color: color)`.
/// <-------아부분임---------->
Container({
super.key,
this.alignment,
this.padding,
this.color,
this.decoration,
this.foregroundDecoration,
double? width,
double? height,
BoxConstraints? constraints,
this.margin,
this.transform,
this.transformAlignment,
this.child,
this.clipBehavior = Clip.none,
}) : assert(margin == null || margin.isNonNegative),
assert(padding == null || padding.isNonNegative),
assert(decoration == null || decoration.debugAssertIsValid()),
assert(constraints == null || constraints.debugAssertIsValid()),
assert(decoration != null || clipBehavior == Clip.none),
/// <-------아부분임---------->
assert(color == null || decoration == null,
'Cannot provide both a color and a decoration\n'
'To provide both, use "decoration: BoxDecoration(color: color)".',
),
/// <-------아부분임---------->
constraints = (width != null || height != null) ? constraints?.tighten(width: width, height: height)
?? BoxConstraints.tightFor(width: width, height: height)
: constraints;
...
} // Container