Last active
October 2, 2023 22:00
-
-
Save aloisdeniel/9d584ba79cbf5454009b139f21926ae6 to your computer and use it in GitHub Desktop.
Flutter custom layout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math' as math; | |
import 'package:flutter/material.dart'; | |
const darkBlue = Color.fromARGB(255, 18, 32, 47); | |
const barBackground = Color(0xFFE9EAF6); | |
const barForeground = Color(0xFF0B0B10); | |
void main() { | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: ThemeData.dark().copyWith( | |
scaffoldBackgroundColor: darkBlue, | |
), | |
debugShowCheckedModeBanner: false, | |
home: Scaffold( | |
body: Center( | |
child: Container( | |
width: 420, | |
height: 48, | |
color: barBackground, | |
child: const TitleBar( | |
title: Text( | |
'Title', | |
maxLines: 1, | |
overflow: TextOverflow.ellipsis, | |
style: TextStyle( | |
fontSize: 20, | |
color: barForeground, | |
), | |
), | |
leading: TitleAction(Icons.menu), | |
trailing: Row( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
TitleAction(Icons.share), | |
TitleAction(Icons.search), | |
TitleAction(Icons.notifications_none), | |
], | |
), | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
enum _LayoutId { | |
leading, | |
title, | |
trailing, | |
} | |
class TitleBar extends StatelessWidget { | |
const TitleBar({ | |
super.key, | |
required this.title, | |
required this.leading, | |
required this.trailing, | |
}); | |
final Widget title; | |
final Widget leading; | |
final Widget trailing; | |
@override | |
Widget build(BuildContext context) { | |
return CustomMultiChildLayout( | |
delegate: _LayoutDelegate(), | |
children: [ | |
LayoutId( | |
id: _LayoutId.trailing, | |
child: trailing, | |
), | |
LayoutId( | |
id: _LayoutId.title, | |
child: title, | |
), | |
LayoutId( | |
id: _LayoutId.leading, | |
child: leading, | |
), | |
], | |
); | |
} | |
} | |
class _LayoutDelegate extends MultiChildLayoutDelegate { | |
_LayoutDelegate(); | |
@override | |
void performLayout(Size size) { | |
final leadingSize = layoutChild( | |
_LayoutId.leading, | |
BoxConstraints( | |
maxHeight: size.height, | |
maxWidth: size.width, | |
), | |
); | |
final trailingSize = layoutChild( | |
_LayoutId.trailing, | |
BoxConstraints( | |
maxHeight: size.height, | |
maxWidth: size.width - leadingSize.width, | |
), | |
); | |
final titleSize = layoutChild( | |
_LayoutId.title, | |
BoxConstraints( | |
maxHeight: size.height, | |
maxWidth: size.width - leadingSize.width - trailingSize.width, | |
), | |
); | |
final center = size.center(Offset.zero); | |
positionChild( | |
_LayoutId.leading, | |
Offset( | |
0, | |
center.dy - leadingSize.height / 2, | |
), | |
); | |
positionChild( | |
_LayoutId.trailing, | |
Offset( | |
size.width - trailingSize.width, | |
center.dy - trailingSize.height / 2, | |
), | |
); | |
final leadingOverlapping = leadingSize.width // leading end | |
- | |
(center.dx - titleSize.width / 2); // title start | |
final trailingOverlapping = | |
(size.width - trailingSize.width) // trailing start | |
- | |
(center.dx + titleSize.width / 2); // title end | |
positionChild( | |
_LayoutId.title, | |
Offset( | |
math.max(0, leadingOverlapping) + | |
math.min(0, trailingOverlapping) + | |
center.dx - | |
titleSize.width / 2, | |
center.dy - titleSize.height / 2, | |
), | |
); | |
} | |
@override | |
bool shouldRelayout(covariant _LayoutDelegate oldDelegate) { | |
return false; | |
} | |
} | |
class TitleAction extends StatelessWidget { | |
const TitleAction( | |
this.icon, { | |
super.key, | |
}); | |
final IconData icon; | |
@override | |
Widget build(BuildContext context) { | |
return SizedBox( | |
width: 42, | |
height: 48, | |
child: Center( | |
child: Icon( | |
icon, | |
color: barForeground, | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment