Flutter, Container 에서 Decoration 과 Color 파라미터를 동시에 사용할 수 없는 이유에 관하여

Uno·2023년 10월 4일
0

flutter

목록 보기
9/15

문제 & 상황

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 파라미터에서 받고 있는 타입은 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 내용이 들어가 있는 인터페이스다.

  • README.md 내용
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

참고자료

profile
iOS & Flutter

0개의 댓글