I am trying to add swiper dots below as shown in the figure
while in the code I tried parallax effect on image and text, now I am trying to add dots below, swiper dots will help to understand which page we are in.
here is the present code:
import 'package:ecommerce_int2/models/product.dart';
import 'package:flutter/material.dart';
import 'package:transformer_page_view/transformer_page_view.dart';
import 'package:flutter/cupertino.dart';
class ParallaxMain extends StatefulWidget {
ParallaxMain({Key key, this.title}) : super(key: key);
final String title;
#override
_ParallaxMainState createState() => new _ParallaxMainState();
}
class ParallaxSlide extends StatelessWidget {
final List<Product> product;
ParallaxSlide({Key key, this.product}) : super(key: key);
#override
Widget build(BuildContext context) {
return new TransformerPageView(
loop: true,
viewportFraction: 0.8,
transformer: new PageTransformerBuilder(
builder: (Widget child, TransformInfo info) {
return new Padding(
padding: new EdgeInsets.all(10.0),
child: new Material(
elevation: 4.0,
textStyle: new TextStyle(color: Colors.white),
borderRadius: new BorderRadius.circular(10.0),
child: new Stack(
fit: StackFit.expand,
children: <Widget>[
new ParallaxImage.asset(
//images[info.index],
product[info.index].image[0],
position: info.position,
),
new DecoratedBox(
decoration: new BoxDecoration(
gradient: new LinearGradient(
begin: FractionalOffset.bottomCenter,
end: FractionalOffset.topCenter,
colors: [
const Color(0xFF000000),
const Color(0x33FFC0CB),
],
),
),
),
new Positioned(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new ParallaxContainer(
child: new Text(
product[info.index].name,
style: new TextStyle(fontSize: 15.0),
),
position: info.position,
translationFactor: 300.0,
),
new SizedBox(
height: 8.0,
),
new ParallaxContainer(
child: new Text("₹ "+product[info.index].price.toString(),
style: new TextStyle(fontSize: 18.0)),
position: info.position,
translationFactor: 200.0,
),
],
),
left: 10.0,
right: 10.0,
bottom: 10.0,
)
],
),
),
);
}),
itemCount: product.length,
);
}
}
class _ParallaxMainState extends State<ParallaxMain> {
#override
Widget build(BuildContext context) {
return new SizedBox(
height: 400,
child: new ParallaxSlide()
);
}
}
Is there any way to add swiper dots to this code?
Try this:
move your TransformerPageView inside a stack and add a DotIndicator
Stack(children:[
TransformerPageView(controller: _controller),
DotsIndicator(controller: _controller)
])
Make sure you add the same _controller for both of them. Then position the dot indicator as you like.
PageController: A controller for PageView.
A page controller lets you manipulate which page is visible in a PageView.
You can read the complete information in the link provided.
Hints taken from here.
Personally, I use smooth_page_indicator because it provides awesome transition effects. Just follow the docs and it's so easy to implement.
Yes we can do it by using carousel_slider
Please check the example of Image carousel slider with a custom indicator.
Related
I have implement several no of expanded items using expansion widget.
These are the steps
All the widgets are collapsed at the beginning
First widget was expanded
Second widget also expanded without collapse first one
I want to automatically collapse first one when expanding second one
import 'package:expansion_widget/expansion_widget.dart';
import 'package:flutter/material.dart';
class CustomExpansionTile extends StatefulWidget {
final Widget HeaderBody;
final Widget ExpandedBody;
final Color HeaderColor;
final Color ExpandedBodyColor;
final double Padding;
const CustomExpansionTile({
Key? key,
required this.HeaderBody,
required this.ExpandedBody,
required this.HeaderColor,
required this.ExpandedBodyColor,
required this.Padding,
}) : super(key: key);
#override
_CustomExpansionTileState createState() => _CustomExpansionTileState();
}
class _CustomExpansionTileState extends State<CustomExpansionTile> {
#override
Widget build(BuildContext context) {
return Column(
children: [
Card(
elevation: 0,
child: ExpansionWidget(
initiallyExpanded: false,
titleBuilder:
(double animationValue, _, bool isExpaned, toogleFunction) {
return Container(
decoration: BoxDecoration(
color: widget.HeaderColor,
borderRadius: BorderRadius.circular(6)),
height: 59,
child: InkWell(
onTap: () {
toogleFunction(animated: true);
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: widget.Padding),
child: Row(
children: [
widget.HeaderBody,
const Spacer(),
Transform.rotate(
angle: 0,
child: Icon(
isExpaned
? Icons.keyboard_arrow_down_rounded
: Icons.keyboard_arrow_right,
size: 40),
alignment: Alignment.centerRight,
)
],
),
)),
);
},
content: Container(
color: widget.ExpandedBodyColor,
width: double.infinity,
padding: const EdgeInsets.all(20),
child: Column(
children: [widget.ExpandedBody],
),
),
),
),
],
);
}
}
This is my Code for calling custom widget
CustomExpansionTile(
HeaderBody: Row(
children: [
Text('Hellooo'),
Text('Hellooo'),
],
),
ExpandedBody: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text('Hellooo'),
Text('Hellooo'),
],
),
HeaderColor: Colors.white,
ExpandedBodyColor: Colors.white,
Padding: 0,
),
To achieve that you can do one of the following:
1- [O(n): O(1)] create a new property called currentSelectedItem its type is as your data model type and onTap method change its value to your tapped item and do not forget to add the check to the expansion property of the expanded card as -> expanded: currentSelectedItem == itemModel,
2- [O(n): O(n)] add a new boolean property to your model item called "isExpanded" and config on tap action to loop throw all models list changing items' isExpanded to false and update current tapped item's isExpanded to true
I'm developing a parallax-style header/background block in my flutter application, which scrolls upwards at around 1/3 the speed of the foreground content. All parts in the foreground are within the same customScrollView and the background header is in a positioned container at the top of the stack.
I'm using a listener on the customscrollview to update a y-offset integer, and then using that integer to update the top position on the element inside my stack.
While this works as expected, the issue I'm facing is a large amount of repainting takes place on scroll, which in the future may impact performance. I'm sure there may be a more efficient way to achieve this - such as placing the entire background in a separate child widget and passing the controller down to it from the parent widget - however I am struggling to find any information on doing so, or if this is the correct approach.
Can someone point me in the right direction for refactoring this in such a way as to disconnect the scrolling background from the foreground, so that the foreground doesn't repaint constantly?
class ScrollingWidgetList extends StatefulWidget {
ScrollingWidgetList();
#override
State<StatefulWidget> createState() {
return _ScrollingWidgetList();
}
}
class _ScrollingWidgetList extends State<ScrollingWidgetList> {
ScrollController _controller;
double _offsetY = 0.0;
_scrollListener() {
setState(() {
_offsetY = _controller.offset;
});
}
#override
void initState() {
_controller = ScrollController();
_controller.addListener(_scrollListener);
super.initState();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Positioned(
top: -(_offsetY / 3),
child: ConstrainedBox(
constraints: new BoxConstraints(
maxHeight: 300.0,
minHeight: MediaQuery.of(context).size.width * 0.35),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Theme.of(context).primaryColorDark,
Colors.blueGrey[900].withOpacity(0.8)
],
)),
height: MediaQuery.of(context).size.width * 0.35)),
width: MediaQuery.of(context).size.width,
),
CustomScrollView(controller: _controller, slivers: [
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
child: ListTile(
title: Padding(
padding: const EdgeInsets.only(top: 6.0),
child: Text('Header text',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Colors.white)),
),
subtitle: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text('Subtitle text',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white)),
),
))
])),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return FakeItem(
executing: false,
delay: index.isOdd,
complete: false,
cancelled: false);
},
childCount: 30,
)),
])
],
);
}
}
A great solution was added by #pskink in the comments, however they seemed to have removed it. For anyone searching for an elegant solution, this is the basics of what was settled on.
You can see in the below code there is two layouts that are being handled by CustomMultiChildLayout. Hopefully this helps anyone searching for a similar solution
class ScrollList extends StatelessWidget {
final ScrollController _controller = ScrollController();
#override
Widget build(BuildContext context) {
return CustomMultiChildLayout(
delegate: ScrollingChildComponentDelegate(_controller),
children: <Widget>[
// background element layout
LayoutId(
id: 'background',
child: DecoratedBox(
decoration: BoxDecoration(
// box decoration
),
),
),
// foreground element layout
LayoutId(
id: 'scrollview',
child: CustomScrollView(
controller: _controller,
physics: AlwaysScrollableScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: ListTile(
title: Text('TitleText'),
),
subtitle: Text('SubtitleText'),
)),
),
SliverList(
delegate: SliverChildBuilderDelegate(itemBuilder,
childCount: 100),
),
],
)),
],
);
}
}
// itembuilder for child components
Widget itemBuilder(BuildContext context, int index) {
return Card(
margin: EdgeInsets.all(6),
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10))),
child: Container(
// child element content
)));
}
// controller for the animation
class ScrollingChildComponentDelegate extends MultiChildLayoutDelegate {
final ScrollController _controller;
ScrollingChildComponentDelegate(this._controller) : super(relayout: _controller);
#override
void performLayout(Size size) {
positionChild('background', Offset(0, -_controller.offset / 3));
layoutChild('background',
BoxConstraints.tightFor(width: size.width, height: size.height * 0.2));
positionChild('scrollview', Offset.zero);
layoutChild('scrollview', BoxConstraints.tight(size));
}
#override
bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => true;
}
How can I make a scrolling view in Flutter in which a left and bottom portion of the screen is fixed (axes), then the rest of the screen can be scrolled horizontally to the right, or vertically upward. (imagine scrolling a graph with two axes .. see image)
Very interesting question. After looking through the docs I couldn't find a widget that would fit this scenario. So I decided to search a bit on pub.dev for a plugin that could make this happen.
Found it: https://pub.dev/packages/bidirectional_scroll_view
The plugin does a fairly good job of scrolling content on both axis, but to get what you are looking for ("fixed portion of on left and bottom") you are gonna have to structure your page accordingly. I decided to go with Stack and Align widgets, here is what it looks like:
See the full code on a working DartPad: https://dartpad.dev/10573c0e9bfa7f1f8212326b795d8628
Or take a look at the code bellow (don't forget to include bidirectional_scroll_view in your project):
void main() {
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
BidirectionalScrollViewPlugin _plugin;
double fixedAxisSpace = 100.0;
double biDirectContentWidth = 4096.0;
double biDirectContentHeight = 4096.0;
#override
void initState() {
super.initState();
_plugin = new BidirectionalScrollViewPlugin(
child: _buildWidgets(),
velocityFactor: 0.0,
);
}
void _snapToZeroZero(BuildContext context){
double yOffset = biDirectContentHeight + fixedAxisSpace - context.size.height;
_plugin.offset = new Offset(0, yOffset);
}
#override
Widget build(BuildContext context) {
final btnSnapToZeroZero = Padding(
padding: EdgeInsets.all(10.0),
child:FlatButton(
color: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(12.0),
),
onPressed: () { _snapToZeroZero(context); },
child: Text(
"Snap to 0.0",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
)
);
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
body: Stack(
children: <Widget>[
_plugin, // BidirectionalScrollViewPlugin, goes 1st because we want it to sit on the bottom layer
Align( // Y Axis goes over _plugin, it is aligned to topLeft
alignment: Alignment.topLeft,
child: Column(
children: <Widget> [
Expanded(
child: Container(
width: fixedAxisSpace,
decoration: BoxDecoration(
color: Colors.white, // change to Colors.white70 too se what is going on "behind the scene"
border: Border(
right: BorderSide(width: 1.0, color: Colors.black),
),
),
child: Center(child: VerticalTextWidget("FIXED _ Y AXIS", 22))
),
),
SizedBox(height: fixedAxisSpace),
]
),
),
Align( // X Axis goes over _plugin and Y Axis, it is aligned to bottomLeft
alignment: Alignment.bottomLeft,
child: Row(
children: <Widget> [
SizedBox(width: fixedAxisSpace),
Expanded(
child: Container(
height: fixedAxisSpace,
decoration: BoxDecoration(
color: Colors.white, // change to Colors.white70 too se what is going on "behind the scene"
border: Border(
top: BorderSide(width: 1.0, color: Colors.black),
),
),
child: Center(child: Text("FIXED | X AXIS", style: TextStyle(fontSize: 22)))
),
),
]
),
),
Align( // this little square is optional, I use it to put a handy little button over everything else at the bottom left corner.
alignment: Alignment.bottomLeft,
child: Container(
color: Colors.white, // change to Colors.white70 too se what is going on "behind the scene"
height: fixedAxisSpace,
width: fixedAxisSpace,
child: btnSnapToZeroZero
),
),
],
)
)
);
}
// put your large bidirectional content here
Widget _buildWidgets() {
return new Padding(
padding: EdgeInsets.fromLTRB(100, 0, 0, 100),
child: SizedBox(
width: biDirectContentWidth,
height: biDirectContentHeight,
child: Image.network(
'https://i.stack.imgur.com/j1ItQ.png?s=328&g=1',
repeat: ImageRepeat.repeat,
alignment: Alignment.bottomLeft
),
)
);
}
}
VerticalTextWidget:
class VerticalTextWidget extends StatelessWidget {
final String text;
final double size;
const VerticalTextWidget(this.text, this.size);
#override
Widget build(BuildContext context) {
return Wrap(
direction: Axis.vertical,
alignment: WrapAlignment.center,
children: text.split("").map((string) => Text(string, style: TextStyle(fontSize: size))).toList(),
);
}
}
I am new in Flutter.
Today I created splash screen and login screen. Then I want to animate my logo from splash screen -> login screen.
But when I run code, the animation not working
here is my code:
Splash Screen
class SplashScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
home: new SplashScreenPage(),
routes: <String, WidgetBuilder>{
'/LoginPage': (BuildContext context) => new LoginPage()
},
);
}
}
class SplashScreenPage extends StatefulWidget{
SplashScreenPage({Key key, this.title}) : super(key: key);
final String title;
#override
State<StatefulWidget> createState() {
return new SplashScreenState();
}
}
class SplashScreenState extends State<SplashScreenPage>{
startTime() async {
var _duration = new Duration(seconds: 2);
return new Timer(_duration, navigationPage);
}
void navigationPage() {
Navigator.of(context).pushNamed('/LoginPage');
}
#override
void initState() {
startTime();
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new SizedBox(
child: new Hero(
tag: 'hero-tag-llama',
child: new Image.asset(
'images/logo_futurisx.png',
fit: BoxFit.cover,
height: 150.0,
)
),
)
],
)
),
);
}
Login screen
class LoginState extends State<LoginPage>{
final userNameController = new TextEditingController();
final passwordController = new TextEditingController();
#override
Widget build(BuildContext context) {
var _imageBox = new SizedBox(
child: new Hero(
tag: 'hero-tag-llama',
child: new Image.asset(
'images/logo_futurisx.png',
fit: BoxFit.cover,
height: 100.0,
)
),
);
var _loginForm = new Container(
padding: new EdgeInsets.all(32.0),
child: new Column(
children: <Widget>[
new TextField(
maxLines: 1,
controller: userNameController,
decoration: new InputDecoration(
border: new UnderlineInputBorder(),
fillColor: Colors.green,
hintText: "Username"
),
),
new Container(
padding: new EdgeInsets.only(bottom: 20.0),
),
new TextField(
maxLines: 1,
controller: passwordController,
decoration: new InputDecoration(
border: new UnderlineInputBorder(),
fillColor: Colors.green,
hintText: "Password"
),
),
new Container(
padding: new EdgeInsets.only(bottom: 30.0),
),
new RaisedButton(
padding: new EdgeInsets.fromLTRB(30.0, 10.0, 30.0, 10.0),
child: new Text("Login", style: new TextStyle(color: Colors.white)),
elevation: 4.0,
color: Colors.teal,
onPressed: (){
login(userNameController.text, passwordController.text);
}
),
])
);
return new Scaffold(
key: _scaffoldKey,
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_imageBox,
_loginForm
],
)
)
);
}
The video I uploaded here:
https://vimeo.com/271938052
When I comment the _loginForm layout in Login Screen,
children: <Widget>[
_imageBox,
//_loginForm
],
animation work normally. Can anyone help me know why animation not running as expect?
UPDATE -----------
After a lots of searching and fixing, i found that Timer may be block thread(or something similar,..) removed timer let button click action to change page, animation work normally.
Did someone meet this problem?
What happens here is that the Timer finishes before even starting the Hero animation. A workaround here is to increase the duration set on the Timer.
I have a list and I want to add a bullet to each item (I'm using new Column because I don't want to implement scrolling). How would I create a bulleted list?
I'm thinking maybe an icon but possibly there is a way with the decoration class used in the text style.
To make it as simple as possible, you can use UTF-code.
This's going to be a bullet
String bullet = "\u2022 "
Following widget will create a filled circle shape, So you can call this widget for every item in your column.
class MyBullet extends StatelessWidget{
#override
Widget build(BuildContext context) {
return new Container(
decoration: new BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
);
}
}
Hope this is what you want !
EDIT :
class MyList extends StatelessWidget{
#override
Widget build(BuildContext context) {
return new Column(
children: <Widget>[
new ListTile(
leading: new MyBullet(),
title: new Text('My first line'),
),
new ListTile(
leading: new MyBullet(),
title: new Text('My second line'),
)
],
);
}
}
class MyBullet extends StatelessWidget{
#override
Widget build(BuildContext context) {
return new Container(
height: 20.0,
width: 20.0,
decoration: new BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
);
}
}
Simple Answer
If you looking for just a symbol, then use Text('\u2022 Bullet Text')
Detailed Answer
I have created a custom widget for Bullet List of Strings. I am sharing the code so that anyone would find it helpful.
Output:
Code For BulletList Widget
(You can paste this in a separate file like 'bullet_widget.dart' and later import to your screen.)
import 'package:flutter/material.dart';
class BulletList extends StatelessWidget {
final List<String> strings;
BulletList(this.strings);
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.fromLTRB(16, 15, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: strings.map((str) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'\u2022',
style: TextStyle(
fontSize: 16,
height: 1.55,
),
),
SizedBox(
width: 5,
),
Expanded(
child: Container(
child: Text(
str,
textAlign: TextAlign.left,
softWrap: true,
style: TextStyle(
fontSize: 16,
color: Colors.black.withOpacity(0.6),
height: 1.55,
),
),
),
),
],
);
}).toList(),
),
);
}
}
This will Take List of Strings and Output with Bullets. Like This example.
Container(
height: 327,
decoration: BoxDecoration(
color: Constants.agreementBG,
borderRadius: BorderRadius.circular(14)),
child: SingleChildScrollView(
child: BulletList([
'Text 1',
'Text 2',
'Text 3',
]),
),
),
I used the ascii character E.G.
...your widget hierarchy
Text(String.fromCharCode(0x2022)),
...
You can just add an icon.
class MyList extends StatelessWidget{
#override
Widget build(BuildContext context) {
return new Column(
children: <Widget>[
new ListTile(
leading: Icon(Icons.fiber_manual_record),
title: new Text('My first line'),
),
new ListTile(
leading: Icon(Icons.fiber_manual_record),
title: new Text('My second line'),
)
],
);
}
}
I might be late to answer this question, but it might be of help to someone who is looking for how to use bullet in a text. It can be done using RichText.
RichText(
text: TextSpan(
text: '• ',
style: TextStyle(color: Colors.lightBlue, fontSize: 18),
children: <TextSpan>[
TextSpan(text: 'Software Developer',style:
GoogleFonts.ptSansNarrow(textStyle: TextStyle(fontSize: 18))),
],
),
)
So, in this case, the color of the bullet can also be changed as you wish!
Here you have the class for bullet text
import 'package:flutter/cupertino.dart';
class BulletText extends StatelessWidget {
late String txt;
BulletText(String t){
txt = t;
}
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('\u2022'),
SizedBox(width: 5),
Expanded(
child: Text(txt)
)
],
);
}
}
You can use CircleAvatar something like below
ListTile(
leading: CircleAvatar(
radius: 6.0,
backgroundColor: Colors.black,
),
title : Text("Timestamp: C0238 - Wheel Speed Mismatch")
),
I got the idea from Tushar Pol. In case you want to display a number on the bullet then you can refer to my code.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class AppBullet extends StatelessWidget {
AppBullet({
#required this.width,
#required this.height,
this.order,
}) : assert(width != null),
assert(height != null);
final double width;
final double height;
final int order;
#override
Widget build(BuildContext context) {
return order == null
? _buildBullet(context)
: _buildBulletWithOrder(context);
}
Widget _buildBullet(BuildContext context) {
return new Container(
height: height,
width: width,
decoration: new BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
);
}
Widget _buildBulletWithOrder(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
_buildBullet(context),
Text(
'$order',
style: GoogleFonts.lato(fontSize: 12.0, color: Colors.white),
),
],
);
}
}
Entypo.dot_single from Flutter vector Icons library
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
class MyList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
MyListItem(title: 'First Item'),
MyListItem(title: 'Second Item'),
],
);
}
}
class MyListItem extends StatelessWidget {
final String title;
MyListItem({this.title});
#override
Widget build(BuildContext context) {
return Row(
children: [
Icon(Entypo.dot_single),
Text(title),
],
);
}
}
Screenshot
May be this does not answer this question. I think, this answer can be helpful to other developers.
I use this code to draw a circle of solid color:
CircleAvatar(
radius: 5.0,
backgroundColor: Colors.black,
)
to add extra padding at top, I use Container:
Container(
padding: EdgeInsets.only(top: 3),
child: CircleAvatar(
radius: 5.0,
backgroundColor: Colors.black,
)
)
Also you can use other backgroundColor in CircleAvatar.
Thanks to: #NBM
The solution using flutter widget is to either use the Icon Icon(Icons.circle) or Container or CirleAvatar. There are different solutions. but the one with Icons is easier I think.
You can create a separate class to generate the bullet item that you can further easily modify as per your design. i.e you can use different bullet styles like instead of circle rectangle, triangle, any other icon.
I have just added the option to add the custom padding.
Code:
class MyBulletList extends StatelessWidget {
final String text;
final double vpad;
final double hpad;
MyBulletList({
required this.text,
this.hpad = 24.0,
this.vpad = 8.0,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: hpad, vertical: vpad),
child: Row(
children: [
Icon(
Icons.circle,
size: 6,
color: Colors.grey,
),
SizedBox(
width: 5,
),
Text(
text,
)
],
),
);
}
}
class UL extends StatelessWidget {
final String text;
const UL(this.text, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 14),
child: Icon(
Icons.circle,
size: Theme.of(context).textTheme.bodyText1?.fontSize,
),
),
Text(text, style: Theme.of(context).textTheme.bodyText1),
],
),
);
// return ListTile(
// contentPadding: EdgeInsets.zero,
// minVerticalPadding: 0,
// dense: true,
// visualDensity: VisualDensity(vertical: -4, horizontal: 0),
// leading: Container(
// height: double.infinity,
// child: Icon(
// Icons.circle,
// size: Theme.of(context).textTheme.bodyText1?.fontSize,
// ),
// ),
// title: Text(text, style: Theme.of(context).textTheme.bodyText1),
// );
}
}
You can also pass in padding as an optional parameter to this widget if needed to customize padding