feat(zipcode): compact column widths for popup; ensure no horizontal scroll within dialog
Some checks failed
Flutter Test & Quality Check / Test on macos-latest (push) Has been cancelled
Flutter Test & Quality Check / Test on ubuntu-latest (push) Has been cancelled
Flutter Test & Quality Check / Build APK (push) Has been cancelled

- ZipcodeTable: dynamic widths; shrink columns when target width < standard
- Use computed widths for header and rows; actions width fixed
- Works with tableMaxWidthFraction from ZipcodeSearchScreen],
This commit is contained in:
JiWoong Sul
2025-09-09 23:11:59 +09:00
parent 2a27c1acb3
commit 32eee2bfe2

View File

@@ -35,15 +35,51 @@ class ZipcodeTable extends StatelessWidget {
child: LayoutBuilder(
builder: (context, constraints) {
// 고정폭 + 마지막 filler
const double minW = 160 + 180 + 180 + 320 + 140 + 24;
// Standard widths
const double zipStd = 160.0;
const double sidoStd = 180.0;
const double guStd = 180.0;
const double etcStd = 320.0;
const double actionsStd = 140.0;
const double fudge = 24.0; // internal paddings/margins
final double viewportW = constraints.maxWidth.isFinite
? constraints.maxWidth
: MediaQuery.sizeOf(context).width;
final double cappedW = maxWidthCap != null
final double targetW = maxWidthCap != null
? math.min(viewportW, maxWidthCap!)
: viewportW;
final double tableW = cappedW >= minW ? cappedW : minW;
const double etcW = 320.0;
final double stdMin = zipStd + sidoStd + guStd + etcStd + actionsStd + fudge;
final bool compact = targetW < stdMin;
// Effective widths
double zipW;
double sidoW;
double guW;
double etcW;
double actionsW;
bool includeFiller;
if (!compact) {
zipW = zipStd;
sidoW = sidoStd;
guW = guStd;
etcW = etcStd;
actionsW = actionsStd;
includeFiller = true; // use remaining width as filler column
} else {
// Compact widths to fit inside targetW without horizontal scroll
zipW = 110.0;
sidoW = 120.0;
guW = 120.0;
actionsW = 110.0;
final double remaining = targetW - fudge - (zipW + sidoW + guW + actionsW);
etcW = math.max(180.0, remaining);
includeFiller = false; // no filler in compact mode
}
final double tableW = targetW;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
@@ -53,17 +89,19 @@ class ZipcodeTable extends StatelessWidget {
columnSpanExtent: (index) {
switch (index) {
case 0:
return const FixedTableSpanExtent(160); // 우편번호
return FixedTableSpanExtent(zipW); // 우편번호
case 1:
return const FixedTableSpanExtent(180); // 시도
return FixedTableSpanExtent(sidoW); // 시도
case 2:
return const FixedTableSpanExtent(180); // 구/군
return FixedTableSpanExtent(guW); // 구/군
case 3:
return const FixedTableSpanExtent(etcW); // 상세주소
return FixedTableSpanExtent(etcW); // 상세주소
case 4:
return const FixedTableSpanExtent(140); // 작업
return FixedTableSpanExtent(actionsW); // 작업
case 5:
return const RemainingTableSpanExtent(); // filler
return includeFiller
? const RemainingTableSpanExtent()
: const FixedTableSpanExtent(0);
default:
return const FixedTableSpanExtent(100);
}
@@ -73,15 +111,15 @@ class ZipcodeTable extends StatelessWidget {
const ShadTableCell.header(child: Text('시도')),
const ShadTableCell.header(child: Text('구/군')),
ShadTableCell.header(child: SizedBox(width: etcW, child: const Text('상세주소'))),
const ShadTableCell.header(child: Text('작업')),
const ShadTableCell.header(child: SizedBox.shrink()),
ShadTableCell.header(child: SizedBox(width: actionsW, child: const Text('작업'))),
if (includeFiller) const ShadTableCell.header(child: SizedBox.shrink()),
],
children: zipcodes.map((zipcode) {
return [
// 우편번호 (오버플로우 방지)
ShadTableCell(
child: SizedBox(
width: 160,
width: zipW,
child: FittedBox(
alignment: Alignment.centerLeft,
fit: BoxFit.scaleDown,
@@ -138,13 +176,16 @@ class ZipcodeTable extends StatelessWidget {
),
// 작업
ShadTableCell(
child: SizedBox(
width: actionsW,
child: ShadButton(
onPressed: () => onSelect(zipcode),
size: ShadButtonSize.sm,
child: const Text('선택', style: TextStyle(fontSize: 11)),
),
),
const ShadTableCell(child: SizedBox.shrink()),
),
if (includeFiller) const ShadTableCell(child: SizedBox.shrink()),
];
}).toList(),
),