Skip to content

Instantly share code, notes, and snippets.

@densa
Created July 29, 2025 09:07
Show Gist options
  • Save densa/50ff7bb0b194aa4240b298f156cc3089 to your computer and use it in GitHub Desktop.
Save densa/50ff7bb0b194aa4240b298f156cc3089 to your computer and use it in GitHub Desktop.
// Method 3: Smart auto-layout widget with configuration
class ButtonConfig {
final String text;
final VoidCallback? onPressed;
final ButtonStyle? style;
ButtonConfig({
required this.text,
this.onPressed,
this.style,
});
}
class SmartButtonLayout extends StatelessWidget {
final List<ButtonConfig> buttons;
final double spacing;
final double minButtonWidth;
final TextStyle? textStyle;
const SmartButtonLayout({
Key? key,
required this.buttons,
this.spacing = 8,
this.minButtonWidth = 100,
this.textStyle,
}) : super(key: key);
Size _measureText(String text, TextStyle style) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: 1,
textDirection: TextDirection.ltr,
);
textPainter.layout();
return textPainter.size;
}
@override
Widget build(BuildContext context) {
if (buttons.length != 2) {
throw ArgumentError('SmartButtonLayout currently supports exactly 2 buttons');
}
return LayoutBuilder(
builder: (context, constraints) {
final effectiveTextStyle = textStyle ??
Theme.of(context).elevatedButtonTheme.style?.textStyle?.resolve({}) ??
TextStyle(fontSize: 16, fontWeight: FontWeight.w500);
// Calculate required widths for each button
final buttonWidths = buttons.map((button) {
final textSize = _measureText(button.text, effectiveTextStyle);
// Add padding and button internal spacing
return Math.max(minButtonWidth, textSize.width + 48); // 48 for padding + margins
}).toList();
final totalRequiredWidth = buttonWidths.reduce((a, b) => a + b) +
spacing * (buttons.length - 1);
final canFitInRow = totalRequiredWidth <= constraints.maxWidth;
if (canFitInRow) {
// Use Row with proportional widths
final totalWidth = buttonWidths.reduce((a, b) => a + b);
return Row(
children: buttons.asMap().entries.map((entry) {
final index = entry.key;
final button = entry.value;
final proportion = buttonWidths[index] / totalWidth;
return [
if (index > 0) SizedBox(width: spacing),
Expanded(
flex: (proportion * 100).round(),
child: ElevatedButton(
onPressed: button.onPressed,
style: button.style,
child: Text(
button.text,
style: textStyle,
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
];
}).expand((widgets) => widgets).toList(),
);
} else {
// Use Column
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: buttons.asMap().entries.map((entry) {
final index = entry.key;
final button = entry.value;
return [
if (index > 0) SizedBox(height: spacing),
ElevatedButton(
onPressed: button.onPressed,
style: button.style,
child: Text(
button.text,
style: textStyle,
textAlign: TextAlign.center,
),
),
];
}).expand((widgets) => widgets).toList(),
);
}
},
);
}
}
// Helper class for math operations
class Math {
static double max(double a, double b) => a > b ? a : b;
static double min(double a, double b) => a < b ? a : b;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment