일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Flutter #Stream
- 도약연계
- 희망적금연계
- 안드로이드 #코틀린 #코루틴 #콜백 #채널
- 조립 후 재부팅
- 플러터 #안드로이드 #플레이콘솔 #앱내리기
- 청년도약계좌환승
- 도약전환
- flutter #dart #stream
- Flutter #Stream #dart
- 희망적금전환
- 도약계좌전환
- Today
- Total
Flutter 개발 상자
[Fluter] AlertDialog의 content에 ListView를 넣었을때 발생하는 'hasSize' 에러 본문
[Fluter] AlertDialog의 content에 ListView를 넣었을때 발생하는 'hasSize' 에러
망고상자 2024. 6. 27. 15:19위험한 에러
The following assertion was thrown during performLayout():
RenderBox was not laid out: RenderCustomPaint#392a8 relayoutBoundary=up3 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2165 pos 12: 'hasSize'
이 에러는 위험합니다.
하지만 에러를 만났다면 다행입니다(?)
플러터 위젯 에러를 좀 겪어보신분들은 hasSize 에러를 보고 대충 감이 올겁니다.
ListView를 넣었는데 저 에러가 뜬다? 그렇다는건 ListView는 무한히 늘어나는데 부모의 사이즈는 정의가 안되어 있어서 그러는구나! 라는 걸 먼저 떠올리게 되죠
AlerDialog 분석
보통 사람들은 shinkwrap = true 이걸 추가하거나 부모의 높이사이즈를 지정해주는걸 생각합니다.
보통의 리스트는 세로 리스트이고, 세로로 무한히 확장하는 리스트의 사이즈를 정해주거나, 부모에 사이즈를 정해서 제약을 넣어주면 위젯의 세로 길이를 플러터에서 정확히 파악할 수 있으니까요.
근데 저걸 넣어줘도 문제는 해결되지 않습니다.
사실 세로길이때문에 에러가 난게 아니였기에 발생한 문제죠.
AlertDialog는 content 항목을 Flexible위젯으로 감싼뒤 Column에 넣어서 IntrinsicWidth 라는 위젯으로 묶어주고 있습니다.
} else {
columnChildren = <Widget>[
if (icon != null) iconWidget!,
if (title != null) titleWidget!,
if (content != null) Flexible(child: contentWidget!),
if (actions != null) actionsWidget!,
];
}
Widget dialogChild = IntrinsicWidth(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: columnChildren,
),
);
코드의 핵심 내용입니다.
1. Flexible 위젯 : 자식위젯이 부모위젯의 남은 공간을 이용하되, 필요한 너비만 사용합니다.
2. MainAxisSize.min : Column이 최소한의 필요한 공간만 사용합니다.
3. CrossAxisAlignment.stretch : 교차축의 정렬을 stretch, 쭉 늘려서 정렬합니다. 보통 IntrinsicWidth와 같이 쓰일때는 자식위젯들의 교차축의 길이가 가변적일때 가장 넓은 길이로 통일시켜주는 역할을 합니다.
4. InstrinsicWidth : 이 위젯은 Width를 자식 위젯의 너비를 '본질적인 너비' 에 맞추도록 강제합니다. '본질적인 너비' 란 위젯이 필요한 최소한의 너비를 뜻합니다. 본래라면 CrossAxisAlignment.stretch 속성에 의해서 Column의 chilren 위젯들은 교차축이 최대로 확정되어야 하지만 InstrinsicWidth의 제약 사항으로 인해서 '본질적인 너비'에 맞춰집니다.
이 과정에 따라 레이아웃이 그려질때 가장 먼저 확인되는것이 InstrinsicWidth에 의한 자식의 고유 넓이 측정입니다. 자식 위젯들을 하나씩 그려보고 본질적인 넓이가 확인되면 그걸 자신의 너비로 만들고 그 이후에 다시 자식위젯들을 Column 속성에 맞추어 재배치합니다.
그런데, Column의 자식으로 ListView가 들어와버린다면 InstrinsicWidth의 '자식의 고유 넓이 측정' 이 과정에서 충돌이 발생합니다. ListView는 기본적으로 지연 생성(Lazy rendering) 이기 때문입니다.
(builder 뿐만 아니라 일반 ListView도 지연생성임 !!)
그렇기 때문에 InstrinsicWidth가 계속해서 ListView한테 너비를 물어보지만 ListView는 지금 렌더링할 생각 없는데? 하면서 뻗어있으니 충돌이 발생하게 됩니다.
해결법
1. AlertDialog를 Dialog로 변환
=> Dialog는 InstrinsicWidth가 업슴 !
2. ListView를 SingleChildScrollView로 변환
=> SingleChildScrollView는 지연생성이 아님
3. ListView를 SizedBox로 감싼 후 width에 double.maxFinite 주기
=> ListView의 width를 강제로 부여하여 지연생성이 되더라도 InstrinsicWidth가 자식 너비를 측정할 수 있도록 도와줌
4. 밑부분 내용 중요하니까 읽어보세요
이게 위험한 에러인 이유
이 포스팅을 쓰게 된 계기...
그건 바로 위의 에러가 일부 기종에서는 정상작동 해버린다는 것입니다!...
즉 AlertDialog에 ListView를 바로 박아도 일부 기종에서는 잘되고 일부 기종에서는 에러가 터지는것...
아까 초입에서 에러를 만났다면 다행이라고 쓴 이유도 개발 단계에서 정상작동하는 폰으로 테스트를 해버렸다면 크게 문제가 터질 수 있었지만 다행히 오류를 만나서 문제를 수정할 수 있기 때문입니다.
이렇게 일부 기종에서는 정상작동하고 일부 기기에서만 에러가 발생할 경우 QA 테스트 단계에서 발견하지 못하고 상용서비스에 배포될 가능성이 있습니다. 그래서 상당히 위험하죠
- 갤럭시 S20, 안드로이드 버전 13
위의 폰에서 정상작동하는걸 확인 했는데 테스트 기기가 많지 않아서 정상작동하는 기기에 대한 규칙은 못찾았습니다. 다만 다른분들은 이런 현상을 겪는다면 일부 기기에서 정상작동하는것 뿐이고 에러가 발생하는게 맞으니 꼭 수정하시기 바랍니다.