Last active
October 22, 2023 12:34
-
-
Save manelfera/a9bc181f090689f603244a76f83f0f39 to your computer and use it in GitHub Desktop.
Flutter circle container for lists (vertical & horizontal)
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 'package:flutter/material.dart'; | |
void main() { | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
debugShowCheckedModeBanner: false, | |
home: Scaffold( | |
body: Center( | |
child: MyWidget(), | |
), | |
), | |
); | |
} | |
} | |
class MyWidget extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
padding: const EdgeInsets.all(20), | |
child: Column(children: [ | |
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ | |
const Text( | |
'Sample horizontal bullets', | |
style: TextStyle( | |
color: Colors.black, | |
fontWeight: FontWeight.w800, | |
fontFamily: 'Roboto', | |
letterSpacing: 0.5, | |
fontSize: 20, | |
), | |
) | |
]), | |
const SizedBox(height: 20), | |
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ | |
const CircleBottomText( | |
innerText: 'Hello', | |
bottomText: 'World', | |
size: 60, | |
borderColor: Colors.orange, | |
fillColor: Colors.orange, | |
), | |
const CircleBottomText( | |
innerText: 'Hello', | |
bottomText: 'World', | |
size: 60, | |
borderColor: Colors.orange, | |
fillColor: Colors.orange, | |
), | |
const CircleBottomText( | |
innerText: 'Hello', | |
bottomText: 'World', | |
size: 60, | |
borderColor: Colors.orange, | |
fillColor: Colors.orange, | |
), | |
]), | |
const SizedBox(height: 20), | |
Separator(thickness: 2), | |
const SizedBox(height: 20), | |
Row(mainAxisAlignment: MainAxisAlignment.start, children: [ | |
const Text( | |
'Sample vertical bulleted list', | |
style: TextStyle( | |
color: Colors.black, | |
fontWeight: FontWeight.w800, | |
fontFamily: 'Roboto', | |
letterSpacing: 0.5, | |
fontSize: 20, | |
), | |
) | |
]), | |
const SizedBox(height: 20), | |
const NumberedListItem( | |
number: '1', color: Colors.orange, child: text1), | |
const SizedBox(height: 20), | |
const NumberedListItem( | |
number: '2', color: Colors.orange, child: text2), | |
const SizedBox(height: 20), | |
const NumberedListItem( | |
number: '3', color: Colors.orange, child: text3), | |
])); | |
} | |
} | |
const text1 = Text.rich( | |
TextSpan(text: 'Lorem ipsum dolor sit amet, ', children: <TextSpan>[ | |
TextSpan( | |
text: 'consectetur adipiscing elit.', | |
style: TextStyle(fontWeight: FontWeight.bold)) | |
]), | |
overflow: TextOverflow.ellipsis, | |
maxLines: 5, | |
); | |
const text2 = Text.rich( | |
TextSpan(text: 'Curabitur vehicula dictum cursus.'), | |
overflow: TextOverflow.ellipsis, | |
maxLines: 5, | |
); | |
const text3 = Text.rich( | |
TextSpan( | |
// with no TextStyle it will have default text style | |
text: 'Lorem ipsum dolor sit amet, ', | |
children: <TextSpan>[ | |
TextSpan( | |
text: 'consectetur adipiscing elit. ', | |
style: TextStyle(fontWeight: FontWeight.bold)), | |
TextSpan( | |
text: | |
'Curabitur vehicula dictum cursus. Aliquam posuere tortor quam, sed laoreet enim ultrices at.'), | |
], | |
), | |
overflow: TextOverflow.ellipsis, | |
maxLines: 5, | |
); | |
class CircleBottomText extends StatelessWidget { | |
final String innerText; | |
final String? bottomText; | |
final Color borderColor; | |
final Color? fillColor; | |
final double size; | |
final TextStyle? innerTextStyle; | |
const CircleBottomText({ | |
Key? key, | |
required this.innerText, | |
required this.borderColor, | |
required this.size, | |
this.bottomText, | |
this.fillColor, | |
this.innerTextStyle, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Column( | |
children: <Widget>[ | |
Container( | |
width: size, | |
height: size, | |
decoration: BoxDecoration( | |
color: borderColor, // border color | |
shape: BoxShape.circle, | |
), | |
child: Padding( | |
padding: const EdgeInsets.all(5), // border width | |
child: Container( | |
// or ClipRRect if you need to clip the content | |
decoration: BoxDecoration( | |
shape: BoxShape.circle, | |
color: fillColor ?? borderColor, // inner circle color | |
), | |
child: Center( | |
child: Text( | |
innerText, | |
style: innerTextStyle ?? | |
Theme.of(context).textTheme.bodyLarge, // inner content | |
), | |
), | |
), | |
), | |
), | |
if (bottomText != null) ...[ | |
const SizedBox(height: 8), | |
Text(bottomText!), | |
] | |
], | |
); | |
} | |
} | |
class NumberedListItem extends StatelessWidget { | |
final String number; | |
final Color color; | |
// final String text; | |
final Widget child; | |
const NumberedListItem({ | |
Key? key, | |
required this.number, | |
required this.color, | |
required this.child, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Row(children: [ | |
CircleBottomText( | |
innerText: number, | |
size: 60, | |
borderColor: color, | |
fillColor: Colors.white, | |
innerTextStyle: const TextStyle( | |
color: Colors.black, | |
fontWeight: FontWeight.w800, | |
fontFamily: 'Roboto', | |
letterSpacing: 0.5, | |
fontSize: 20, | |
), | |
), | |
const SizedBox(width: 20), | |
Expanded(child: child | |
) | |
]); | |
} | |
} | |
class Separator extends StatelessWidget { | |
final Color? color; | |
final double thickness; | |
const Separator({this.color, this.thickness = 1, Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
height: thickness, color: color ?? Theme.of(context).dividerColor); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Beautify your flutter bulleted lists
See it live at dartpad