Home: samakan ukuran font label menu layanan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e273785268
commit
5a8b020256
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@@ -98,39 +100,83 @@ class HomeServiceSection extends StatelessWidget {
|
|||||||
context.router.push(route);
|
context.router.push(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const double _horizontalPadding = 16;
|
||||||
|
static const int _crossAxisCount = 4;
|
||||||
|
static const double _crossAxisSpacing = 8;
|
||||||
|
|
||||||
|
/// Semua label memakai ukuran font yang sama: kalau label terpanjang tidak
|
||||||
|
/// muat di lebar sel, semuanya diperkecil bersama supaya tidak ada yang
|
||||||
|
/// kecil sendiri.
|
||||||
|
TextStyle _labelStyle(BuildContext context, double maxWidth) {
|
||||||
|
final style = DefaultTextStyle.of(
|
||||||
|
context,
|
||||||
|
).style.merge(AppStyle.xs.copyWith(fontWeight: FontWeight.w600));
|
||||||
|
final textScaler = MediaQuery.textScalerOf(context);
|
||||||
|
final textDirection = Directionality.of(context);
|
||||||
|
|
||||||
|
final widest = _menus
|
||||||
|
.map((menu) {
|
||||||
|
final painter = TextPainter(
|
||||||
|
text: TextSpan(text: menu.label, style: style),
|
||||||
|
textDirection: textDirection,
|
||||||
|
textScaler: textScaler,
|
||||||
|
maxLines: 1,
|
||||||
|
)..layout();
|
||||||
|
final width = painter.width;
|
||||||
|
painter.dispose();
|
||||||
|
return width;
|
||||||
|
})
|
||||||
|
.reduce(math.max);
|
||||||
|
|
||||||
|
if (widest <= maxWidth) return style;
|
||||||
|
return style.copyWith(fontSize: style.fontSize! * maxWidth / widest);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GridView.builder(
|
return LayoutBuilder(
|
||||||
shrinkWrap: true,
|
builder: (context, constraints) {
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
final itemWidth =
|
||||||
padding: const EdgeInsets.fromLTRB(16, 32, 16, 16),
|
(constraints.maxWidth -
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
_horizontalPadding * 2 -
|
||||||
crossAxisCount: 4,
|
_crossAxisSpacing * (_crossAxisCount - 1)) /
|
||||||
mainAxisSpacing: 12,
|
_crossAxisCount;
|
||||||
crossAxisSpacing: 8,
|
final labelStyle = _labelStyle(context, itemWidth);
|
||||||
mainAxisExtent: 76,
|
|
||||||
),
|
return GridView.builder(
|
||||||
itemCount: _menus.length,
|
shrinkWrap: true,
|
||||||
itemBuilder: (context, index) {
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
final menu = _menus[index];
|
padding: const EdgeInsets.fromLTRB(
|
||||||
return InkWell(
|
_horizontalPadding,
|
||||||
borderRadius: BorderRadius.circular(AppValue.borderRadius),
|
32,
|
||||||
onTap: () => _open(context, menu),
|
_horizontalPadding,
|
||||||
child: Column(
|
16,
|
||||||
children: [
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
menu.icon.image(width: 44, height: 44, fit: BoxFit.contain),
|
|
||||||
const SizedBox(height: 6),
|
|
||||||
FittedBox(
|
|
||||||
fit: BoxFit.scaleDown,
|
|
||||||
child: Text(
|
|
||||||
menu.label,
|
|
||||||
maxLines: 1,
|
|
||||||
style: AppStyle.xs.copyWith(fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: _crossAxisCount,
|
||||||
|
mainAxisSpacing: 12,
|
||||||
|
crossAxisSpacing: _crossAxisSpacing,
|
||||||
|
mainAxisExtent: 76,
|
||||||
|
),
|
||||||
|
itemCount: _menus.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final menu = _menus[index];
|
||||||
|
return InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(AppValue.borderRadius),
|
||||||
|
onTap: () => _open(context, menu),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
menu.icon.image(width: 44, height: 44, fit: BoxFit.contain),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
FittedBox(
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
child: Text(menu.label, maxLines: 1, style: labelStyle),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user