Related
Today I have a question, not providing any code.
I would like to create a tiktok like experience for scrolling through my appfeed in flutter. However I don't want to scroll an entire page when I swipe, only to the next widget in the ListView/PageView. I am only able to swipe an entire page with pageview and I'm only able to scroll normally on Listview. Is there any solution for my request? I hope I clarified enough what I mean. Instagram offers such an experience on its Search. Is there any possibility how one could realize something like that?
Please help.
Use ListView.builder inside the Container with the 500px height and the ListView.builder will have the children posts thus you stay inside the same feed with the ability to swipe thru posts vertically or horizontally.
Check the following link for a tutorial : https://www.youtube.com/watch?v=baA_J5tUtEU
You can change the scrolling by setting scrollDirection: Axis.horizontal or Axis.vertical inside the ListView.buidler
Hope this answers your question.
So what you want to do is to use a Stack widget and then put the pageview, just as you would if you were creating an onboarding screen with flutter, something like this
import 'package:flutter/material.dart';
class OnBoarding extends StatefulWidget {
#override
_OnBoardingState createState() => _OnBoardingState();
}
class _OnBoardingState extends State<OnBoarding> {
PageController? controller;
int currentIndex = 0;
#override
void initState() {
controller = PageController();
super.initState();
}
#override
void dispose() {
controller!.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
PageView(
scrollDirection: Axis.vertical,
onPageChanged: onchahged,
controller: controller,
children: [
Container(
child: Image.network(
'https://picsum.photos/200/300',
fit: BoxFit.fill,
),
),
Container(
child: Image.network(
'https://picsum.photos/200/300',
fit: BoxFit.fill,
),
),
Container(
child: Image.network(
'https://picsum.photos/200/300',
fit: BoxFit.fill,
),
),
],
),
Positioned(
bottom: 30,
right: 10,
child: Column(
children: [
Icon(
Icons.ac_unit,
size: 30,
color: Colors.white,
),
SizedBox(
height: 10,
),
Icon(
Icons.image,
size: 30,
color: Colors.white,
),
SizedBox(
height: 10,
),
Icon(
Icons.person,
size: 30,
color: Colors.white,
),
SizedBox(
height: 10,
),
Icon(
Icons.person_add,
size: 30,
color: Colors.white,
),
],
),
)
],
),
);
}
onchahged(int index) {
setState(() {
currentIndex = index;
});
}
}
Here's what it looks like
For the specific Widget you must to wrap it with a GestureDetector and prevent from the current widget being scrollable.
An example:
GestureDetector(
onHorizontalDragUpdate: (_) {},
child: WidgetToNotBeingScrollableInTheHorizontal(),
);
Any help is appreciated! I've been to trying to figure out why my app doesn't handle different screen size.. I added width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height inside a container to make it more responsive, however, still not responsive. only it's responsive on ios simulator with the overflow error.. not on android simulator. What am I doing wrong?!
How can I make my app handle different screen size both on android and ios simulator?
home: Builder(builder: (context) {
return DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.deepOrange.shade200,
title: Text('Weather App', style: GoogleFonts.roboto()),
bottom:
tabs: [
Tab(
icon: FaIcon(
FontAwesomeIcons.solidSun,
color: Colors.orange,
),
),
Tab(
icon: Icon(
Icons.favorite,
color: Colors.pink,
)),
]),
),
body: Stack(children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.deepOrange.shade400, Colors.white],
),
),
child: TabBarView(
children: <Widget>[
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ForecastWeather(),
),
);
},
child: Card(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.only(top: 120.0),
child: Weather(weather: weatherData),
),
),
I think this is main.dart file could u try like this?
class AppName extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
Go home_page.dart and do there.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container( //this container can be your background.dart or whatever u want
height: size.height * 1,
width: size.width * 1,
);
}
}
like this.
It depends on your goal. Do you want different behavior on different Screen sizes or do you just want to arrange your Elements to get a lean experience on all devices?
If it is the second, then it's not practical to use MediaQueries to measure it all by yourself. Instead try to learn and use flutters layouting.
Here is a Basics Codelab for that:
https://docs.flutter.dev/codelabs/layout-basics
For basic responsive Design without fancy stuff like different layouts for Tables or Foldables, it's way easier to handle it with Layout Design.
I am using flutter_screenutil in my application.
Initallize it with your design size.
Widget build(BuildContext context) {
ScreenUtil.init(
BoxConstraints(
maxWidth: MediaQuery.of(context).size.width,
maxHeight: MediaQuery.of(context).size.height),
designSize: Size(360, 690),
minTextAdapt: true,
orientation: Orientation.portrait);
return Scaffold();
}
And use like this:
Container(
width: 50.w,
height:200.h
)
This turns 50 dp in your design responsive. Check out their documentation for more information.
I've been attempting to define a bespoke Card in Flutter using row and column and cannot seem to get a fixed format layout similar to the image above (the red lines denote the areas of the card and are just there to show the areas).
e.g.
return Card(child: Column(
children: [
Row(
children: [
Column( children: [
Text('Riverside cafe...'),
Ratingbar(),
],),
ImageWidget(),
],
),
Container(child: Text('Pubs & restaurants'), color : Colors.purple)
],
The resulting cards are to be displayed in a listview and using rows and columns above results in the areas being different sized depending on the data.
It seems to me that using row and column may not be the best way to achieve this. Is there a better way?
As for the best, I suppose that's for you and your client to decide.
For as long as I've been working with Flutter, I haven't come across anything like CSS grid which is great for situations like this. The closest comparison is StaggeredGrid (https://pub.dev/packages/flutter_staggered_grid_view) but that doesn't offer as much control as CSS grid and doesn't seem to quite fit your use case.
Rows, Columns (and other layout widgets) can get the job done:
Here's the main.dart that produced the above example. Code quality isn't perfect, but hopefully you can follow it well enough and it helps you get done what you need to get done.
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
static const String _title = 'Bespoke card example';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Bespoke card example')),
body: Center(
child: Wrap(runSpacing: 10.0, children: [
BespokeCard(title: 'Short name', width: 350),
BespokeCard(
title: 'Riverside Cafe with a really long name', width: 350)
]),
),
);
}
}
class BespokeCard extends StatelessWidget {
final String title;
final double width;
BespokeCard({this.title, this.width});
#override
Widget build(BuildContext context) {
Widget _restaurantNameContainer = Container(
constraints: BoxConstraints(
minHeight: 0,
maxHeight: 120,
maxWidth: (500.0 - 40 - 175 + 1),
minWidth: (500.0 - 40 - 175 + 1),
),
child: AutoSizeText(
title,
style: TextStyle(fontSize: 60),
maxLines: 2,
minFontSize: 10,
stepGranularity: 0.1,
overflow: TextOverflow.ellipsis,
),
);
Widget _rightSideSection = Container(
width: 175,
height: Size.infinite.height,
child: Center(
child: Icon(
Icons.umbrella,
size: 70,
),
),
);
Widget _topSection = Flexible(
flex: 1,
child: Row(
children: [
Flexible(
fit: FlexFit.tight,
flex: 3,
child: Padding(
padding: EdgeInsets.only(left: 40.0, top: 25.0),
child: Column(
children: [
Flexible(child: Container(), flex: 1),
_restaurantNameContainer,
Text('* * * * *', style: TextStyle(fontSize: 70)),
],
),
),
),
_rightSideSection
],
),
);
Widget _bottomSection = Container(
height: 70,
width: Size.infinite.width,
child: Center(
child: Text('Pubs & Restaurants',
style: TextStyle(color: Colors.white, fontSize: 40)),
),
color: Colors.purple);
Widget unfittedCard = Card(
child: SizedBox(
width: 500,
height: 300,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [_topSection, _bottomSection],
),
));
return Container(
width: this.width,
child: FittedBox(fit: BoxFit.fitWidth, child: unfittedCard));
}
}
NOTES:
Be aware of flexFit (tight or loose) property: https://api.flutter.dev/flutter/widgets/Flexible/fit.html
You can either define fixed ratios with all flexibles, or you can mix Flexibles with Containers / SizedBoxes what have you
The package auto_size_text is great for situations like this. (Add auto_size_text: ^2.1.0 to your dependencies)
Be aware of box constraints. I needed them to make the title autosizing text be able to grow tall without also sitting in a large container.
Fitted box is really handy and makes scaling very easy in flutter.
Currently, I have a String with 12 words which is extracted from an Argument from another page:
Widget build(BuildContext context) {
final String seed = ModalRoute.of(context).settings.arguments;
I then split the String and shuffle them into an Array which then display as MaterialButton in a GridView. I need that when the user click on a MaterialButton it will add the splitted word into another String Array which then display in a Container above the GridView. The GridView is built by using a for loop to add MaterialButton to <Widget>[] which call a setState() to change a bool value which in turn change the appearance of the button and add the word into the Container. At first I had trouble when clicking on a button, the setState() is called thus refreshing the whole page and reshuffle the word, but after finding Update a part of the UI on Flutter I wrap my MaterialButton in a StatefulBuilder and preventing it from rebuilding the whole page. But that also stop the Text in the container above from updating. What can I do so that when the user click a button, it change it appearance and also update the Text in the Container above?
Here is my code so far:
import 'package:flutter/material.dart';
import 'package:myapp/color_utils.dart';
class SeedConfirmPage extends StatefulWidget {
SeedConfirmPage({Key key, this.title}) : super(key: key);
final String title;
#override
_SeedConfirmPageState createState() => _SeedConfirmPageState();
}
class _SeedConfirmPageState extends State<SeedConfirmPage> {
List<bool> clicked = [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
];
#override
Widget build(BuildContext context) {
final String seed = ModalRoute.of(context).settings.arguments;
List<String> seedArray = seed.split(" ")..shuffle();
final seedChip = <Widget>[];
List<String> seedText = [];
for (var i = 0; i < seedArray.length; i++) {
seedChip.add(StatefulBuilder(builder: (BuildContext context, setState) {
return MaterialButton(
color: clicked[i] ? colorBlack : Colors.white,
textColor: clicked[i] ? Colors.white : colorBlack,
minWidth: MediaQuery.of(context).size.width,
height: 32,
child: Text(
seedArray[i],
style: TextStyle(fontSize: 12),
),
onPressed: () {
setState(() {
clicked[i] = !clicked[i];
if (clicked[i]) {
seedText.add(seedArray[i]);
} else {
seedText.remove(seedArray[i]);
}
});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
);
}));
}
return Scaffold(
appBar: AppBar(
backgroundColor: splashBG,
leading: BackButton(color: Colors.white),
title: Text("Back"),
),
backgroundColor: splashBG,
body: Container(
padding: EdgeInsets.only(
left: 16,
right: 16,
),
child: Column(
children: <Widget>[
Flexible(
child: Container(
width: MediaQuery.of(context).size.width / 2,
child: Image(
image: AssetImage('assets/images/logo_1.png'),
),
),
),
Container(
height: 120,
padding: EdgeInsets.all(32.0),
margin: EdgeInsets.only(top: 28, bottom: 28),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), color: colorBlack),
child: Center(
child: Text(
seedText.toString(),
style: TextStyle(color: Colors.white),
),
),
),
Container(
width: MediaQuery.of(context).size.width,
height: 120,
child: GridView.count(
crossAxisCount: 4,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 5),
children: seedChip,
),
),
],
),
),
);
}
}
I know this is not optimal to check the state of the button to know whether it is click or not. So a side question is what can I do to check the if the button has been clicked yet?
EDIT
Here is the screenshot of what I am trying to archive:
Before user press:
After user press:
You can do it in the same ways you changed button colors. In MaterialButton add this to child
child: clicked[i] ?
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(seedArray[i],style: TextStyle(fontSize: 12),),
Text('x',style: TextStyle(fontSize: 12),),
]) :
Text(seedArray[i],style: TextStyle(fontSize: 12),),
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