개요
Expanded는 Row, Column, Flex 내에서 자식 위젯이 주축(main axis) 방향의 사용 가능한 공간을 모두 차지하도록 확장하는 위젯입니다.
Expanded는 Flexible 위젯의 특별한 경우로, fit: FlexFit.tight
속성이 적용된 상태입니다. 즉, 자식 위젯이 할당된 공간을 반드시 모두 채우도록 강제합니다. 여러 Expanded 위젯이 있을 때는 flex 값에 따라 공간을 비율적으로 분배합니다.
참고: https://api.flutter.dev/flutter/widgets/Expanded-class.html
언제 사용하나요?
- Row/Column 내에서 남은 공간을 모두 차지하는 위젯이 필요할 때
- 여러 위젯 간에 공간을 비율적으로 분배할 때
- TextField나 다른 입력 위젯이 가능한 모든 가로 공간을 사용하게 할 때
- 반응형 레이아웃을 만들 때
- Spacer를 사용하여 위젯들을 밀어낼 때
기본 사용법
// Row에서 남은 공간 채우기
Row({
children: [
Container({ width: 100, height: 50, color: 'blue' }),
Expanded({
child: Container({ height: 50, color: 'red' })
}),
Container({ width: 100, height: 50, color: 'green' })
]
})
// Column에서 사용
Column({
children: [
Container({ height: 100, color: 'blue' }),
Expanded({
child: Container({ color: 'red' }) // 남은 세로 공간 모두 차지
}),
Container({ height: 100, color: 'green' })
]
})
Props
child (필수)
값: Widget
Expanded로 확장할 자식 위젯입니다.
Expanded({
child: Container({ color: 'blue' })
})
flex
값: number (기본값: 1)
다른 Expanded/Flexible 위젯과 비교하여 이 위젯이 차지할 공간의 비율을 정의합니다. 값이 클수록 더 많은 공간을 차지합니다.
- 0 이상의 정수여야 합니다 (음수 불가)
- 기본값은 1입니다
- 다른 flex 자식들과의 비율로 공간이 분배됩니다
Row({
children: [
Expanded({
flex: 2, // 전체의 2/3 차지
child: Container({ color: 'red' })
}),
Expanded({
flex: 1, // 전체의 1/3 차지
child: Container({ color: 'blue' })
})
]
})
고급 사용법
비율적 공간 분배
Row({
children: [
Expanded({
flex: 3, // 3/6 = 50%
child: Container({ height: 100, color: 'red' })
}),
Expanded({
flex: 2, // 2/6 = 33.33%
child: Container({ height: 100, color: 'green' })
}),
Expanded({
flex: 1, // 1/6 = 16.67%
child: Container({ height: 100, color: 'blue' })
})
]
})
고정 크기 위젯과 함께 사용
Row({
children: [
Icon({ icon: Icons.menu }), // 고정 크기
SizedBox({ width: 16 }), // 고정 간격
Expanded({
child: Text('제목이 길어도 가능한 공간 내에서 표시됩니다')
}),
IconButton({ // 고정 크기
icon: Icons.more_vert,
onPressed: () => {}
})
]
})
실제 사용 예제
예제 1: 검색 바
const searchBar = Container({
padding: EdgeInsets.all(16),
child: Row({
children: [
Expanded({
child: TextField({
decoration: InputDecoration({
hintText: '검색어를 입력하세요',
prefixIcon: Icon({ icon: Icons.search }),
border: OutlineInputBorder({
borderRadius: BorderRadius.circular(30)
})
})
})
}),
SizedBox({ width: 12 }),
IconButton({
icon: Icons.filter_list,
onPressed: () => console.log('필터 열기')
})
]
})
});
예제 2: 채팅 입력창
const chatInput = Container({
padding: EdgeInsets.all(8),
decoration: BoxDecoration({
color: 'white',
boxShadow: [
BoxShadow({
color: 'rgba(0, 0, 0, 0.1)',
blurRadius: 4,
offset: { x: 0, y: -2 }
})
]
}),
child: Row({
children: [
IconButton({
icon: Icons.attach_file,
onPressed: () => {}
}),
Expanded({
child: TextField({
decoration: InputDecoration({
hintText: '메시지 입력...',
border: InputBorder.none
}),
maxLines: 3
})
}),
IconButton({
icon: Icons.send,
onPressed: () => {}
})
]
})
});
예제 3: 반응형 버튼 그룹
const responsiveButtons = Container({
padding: EdgeInsets.all(16),
child: Row({
children: [
Expanded({
child: ElevatedButton({
onPressed: () => console.log('취소'),
style: ButtonStyle({
backgroundColor: 'gray'
}),
child: Text('취소')
})
}),
SizedBox({ width: 16 }),
Expanded({
flex: 2, // 확인 버튼이 더 넓음
child: ElevatedButton({
onPressed: () => console.log('확인'),
child: Text('확인')
})
})
]
})
});
예제 4: Spacer 활용
// Spacer는 내부적으로 Expanded를 사용합니다
const header = Container({
padding: EdgeInsets.all(16),
color: 'blue',
child: Row({
children: [
Text('로고', { style: TextStyle({ color: 'white', fontSize: 20 }) }),
Spacer(), // Expanded({ child: Container() })와 동일
IconButton({
icon: Icons.notifications,
color: 'white',
onPressed: () => {}
}),
IconButton({
icon: Icons.account_circle,
color: 'white',
onPressed: () => {}
})
]
})
});
Flexible와의 차이점
Expanded는 Flexible의 특수한 경우입니다:
// 이 두 코드는 동일합니다
Expanded({
flex: 2,
child: widget
})
Flexible({
flex: 2,
fit: FlexFit.tight, // 핵심 차이점
child: widget
})
- Expanded: 항상 할당된 공간을 모두 차지 (tight)
- Flexible: 기본적으로 필요한 만큼만 차지 (loose)
주의사항
- Expanded는 반드시 Row, Column, 또는 Flex의 직접적인 자식이어야 합니다.
- Expanded를 다른 Expanded나 Flexible 안에 직접 중첩할 수 없습니다.
- 부모 위젯이 주축 방향으로 무한한 크기를 가지면 오류가 발생합니다.
- flex 값은 0 이상이어야 하며, 음수를 사용하면 오류가 발생합니다.
- Column 안의 Column이나 Row 안의 Row에서 Expanded를 사용할 때는 내부 Column/Row를 Expanded로 감싸야 할 수 있습니다.
관련 위젯
- Flexible: Expanded의 기반이 되는 더 유연한 위젯
- Spacer: 빈 공간을 만들기 위한 Expanded의 특수한 사용
- Row: 가로 방향 레이아웃에서 Expanded 사용
- Column: 세로 방향 레이아웃에서 Expanded 사용
- Flex: Row와 Column의 기반 위젯