Flutter Custom Title Dropdown (Material Page Filter) - material-design

Following the concept of the app bar "page filter" I'd like to put a DropdownButton as the title of the AppBar. I tried, but it doesn't look good.
https://material.io/guidelines/layout/structure.html#structure-app-bar
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _value = 'one';
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new DropdownButton<String>(
value: _value,
items: <DropdownMenuItem<String>>[
new DropdownMenuItem(
child: new Text('one'),
value: 'one',
),
new DropdownMenuItem(
child: new Text('two'),
value: 'two'
),
],
onChanged: (String value) {
setState(() => _value = value);
},)
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'hello world',
),
],
),
),
);
}
}
However it looks like:
which doesn't follow the material pattern found at the link stated above due to the weird looking underline... bonus: the text and button should be white.

I did find some things that helped my situation... The widgets DropdownButtonHideUnderline and Theme will help control how the dropdown looks in the title of the AppBar
new AppBar(
title: new Theme(
child: new DropdownButtonHideUnderline(
child: new DropdownButton<String>(
value: _value,
items: <DropdownMenuItem<String>>[
new DropdownMenuItem(
child: new Text('My Page'),
value: 'one',
),
],
onChanged: (String value) {
setState(() => _value = value);
},
),
),
data: new ThemeData.dark(),
),
),
However, now the popup's background color is black to match the dark theme... not sure if there's a way to have the theme not affect the actual popup.
I personally can live with the black background color of the popup... unless someone can also solve that.

Do something like this:
appBar: AppBar(
title: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton(
value: _selectedItem,
items: _dropdownMenuItems,
underline: SizedBox(height: 0,),
//underline: SizedBox(),
onChanged: onChangeDropdownItem,
),
],
),
),
Then change your dropdown menu's style here:
/// Initialize dropdown menu
List<DropdownMenuItem<String>> buildDropdownMenuItems(List menu) {
List<DropdownMenuItem<String>> items = List();
for (String li in menu) {
items.add(
DropdownMenuItem(
value: li,
child: SizedBox(
width: 100,
child: Text(li, style: TextStyle(color: labelColor, fontWeight:
FontWeight.bold),
textAlign: TextAlign.center, overflow: TextOverflow.ellipsis,),),
),
);
}
return items;
}

Please just change your code to the one I have mentioned below and this one might work for your app., sorry for the bad editing of the picture. I have included the full code for your reference,.
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new MyHomePage(),
));
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _value = 'one';
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title:
new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new DropdownButton<String>(
value: _value,
items: <DropdownMenuItem<String>>[
new DropdownMenuItem(
child: new Text('one'),
value: 'one',
),
new DropdownMenuItem(child: new Text('two'), value: 'two'),
],
onChanged: (String value) {
setState(() => _value = value);
},
),
],
)
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'hello world',
),
],
),
),
);
}
}
See the demo here: https://codepen.io/andrerpena/pen/LYpZRqG

To have a white menu, change data: new Theme.dark() to Theme.of(context).copyWith(brightness: Brightness.dark))
But then another problems pop : The menu is white ; but the menu options are written in white too, making them unreadable.
After a deep inspection, it seems like it's currently not possible to have options using a different font color in the iddle state and when the dropdown is focused.
Consider creating an issue on their github

Related

How To Random Select A String From List After Tabbing Button

I would like to press a button and pick a random string from my list to display somewhere on the screen.
Currently, the convoTopic variable within the builder is running an error.
Any help is appreciated!
Below is my truncated code:
final List<String> ConvoTopics = [
'blah blah',
'black sheep',
'balh bath'
];
class ConvoPage extends StatefulWidget {
#override
_ConvoPageState createState() => _ConvoPageState();
}
class _ConvoPageState extends State<ConvoPage>
#override
Widget build(BuildContext context) {
void generateConvoTopic() {
final _random = Random();
var convoTopic = ConvoTopics[_random.nextInt(ConvoTopics.length)];
print(convoTopic);
}
return Scaffold(
backgroundColor: Color(0xff04072E),
appBar: AppBar(
title: Text('Convo', style: TextStyle(color: Colors.white)),
backgroundColor: Color(0xff04072E),
),
body: SafeArea(
child: SingleChildScrollView(
child: Column(children: <Widget>[
Container(
child: Align(
alignment: Alignment.center,
child: Text(convoTopic,
),
// where randomized string appears
),
),
ElevatedButton(
onPressed: () async {
generateConvoTopic();
},
// button's function is to randomize convo topic
child: Container(
child: Text('Get Convo'),
),
),
:
:
:
Your approach is mostly correct.
Three small things you were missing were
You should define your generateConvoTopic in your State class rather than the build method.
Your convoTopic should be a State class variable. You are currently defining it inside a function inside the build method. So it will only be accessible inside your function but you need to update it and read it, so it will go in State class.
You should call setState whenever you want to update any variable of your State class. In your case, the convoTopic after you follow step 2.
List item
;
final List<String> ConvoTopics = ['blah blah', 'black sheep', 'balh bath']
class ConvoPage extends StatefulWidget {
#override
_ConvoPageState createState() => _ConvoPageState();
}
class _ConvoPageState extends State<ConvoPage> {
String convoTopic;
void generateConvoTopic() {
setState(() {
convoTopic = ConvoTopics[Random().nextInt(ConvoTopics.length)];
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff04072E),
appBar: AppBar(
title: Text('Convo', style: TextStyle(color: Colors.white)),
backgroundColor: Color(0xff04072E),
),
body: SafeArea(
child: SingleChildScrollView(
child: Column(children: <Widget>[
Container(
child: Align(
alignment: Alignment.center,
child: Text(convoTopic),
),
),
ElevatedButton(
onPressed: () async {
generateConvoTopic();
},
child: Container(
child: Text('Get Convo'),
),
),
]))));
}
}

type 'String' is not a subtype of type 'Item' in Flutter

I created a shopping cart app by using Provide Package (State Management) for storing the selected item or product in cart page but problem is i am getting an error of "type 'String' is not a subtype of type 'Item'". Below is the dart code and models, if i try to click any item from home page then it stored the selected item in cart page and if i try to store the item from second page (Quantities Page) then gets an error.
HomePage.dart
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();}
class _HomeState extends State<Home> {
List<Item> _product=[
Item(
title: "Cake",
image: "assets/1.png",
price: 20.00,
),
Item(
title: "Pasteries",
image: "assets/2.png",
price: 30.00,
),];
#override
Widget build(BuildContext context) {
return Consumer<Cart>(
builder: (context,cart,child){
return PlatformScaffold(
body: ListView.builder(
itemCount: _product.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(
top: 35.0, bottom: 15.0, left: 20.0, right: 20.0),
child: GestureDetector(
onTap: (){
//cart.add(_product[index]);//Here i try to select the item and it successfully stored in cart page
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Quantities(
productname: _product[index].title,
productprice: _product[index].price,
productimage: _product[index].image,
)));},
child: Container(
child: new FittedBox(
child: Material(
color: Colors.white,
elevation: 15.0,
borderRadius: BorderRadius.circular(15.0),
shadowColor: Color(0x802196F3),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 250,
height: 200,
child: ClipRRect(
borderRadius: new BorderRadius.circular(15.0),
child: new Image.asset(
_product[index].image,
fit: BoxFit.cover,),),),
Padding(
padding: const EdgeInsets.only(top: 5.0,bottom: 5.0),
child: Text(_product[index].title,style: TextStyle(color: Colors.blueGrey[700],
fontWeight: FontWeight.bold,fontSize: 18.0),),
),],)),),),),);}));},);}}
Quantities.dart
class Quantities extends StatefulWidget {
var productprice;
String productimage;
final productname;
Quantities({this.productprice, this.productimage, this.productname});
#override
_QuantitiesState createState() => _QuantitiesState(productprice,productimage,productname);}
class _QuantitiesState extends State<Quantities> {
final productprice;
final productimage;
final productname;
_QuantitiesState(this.productprice, this.productimage, this.productname);
#override
Widget build(BuildContext context) {
return Consumer<Cart>(
builder: (context,cart,child){
return PlatformScaffold(
appBar: PlatformAppBar(
backgroundColor: Colors.lightBlue[900],
title: Text('Details'),),
body: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Container(
child: Column(
children: <Widget>[
Container(
height: 150.0,
child: GridTile(
child: Container(
color: Colors.white,
child: Image.asset(productimage),),),),
Text(productname,style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20.0),),
Text("Price: "+productprice.toString()+" SAR",style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20.0),),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Center(
child: PlatformButton(
onPressed: () {
cart.add(productname);},// Here i am getting an error
child: Text('Add to Cart',style: TextStyle(color: Colors.white),),
androidFlat: (_) => MaterialFlatButtonData(
color: Colors.cyan),
ios: (_) => CupertinoButtonData(
color: Colors.cyan
)),),),],),),),],),);},);}}
CartPage.dart
class CartPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _CartPageState();}}
class _CartPageState extends State<CartPage> {
#override
Widget build(BuildContext context) {
return Consumer<Cart>(
builder: (context,cart,child){
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.indigo,
title: Text("Cart"),),
body: cart.basketItems.length==0
?Text("no items"):ListView.builder(
itemCount: cart.basketItems.length,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text(cart.basketItems[index].title),),);}),);},);}}
cartmodel.dart
class Item {
String title;
String image;
double price;
Item({this.title, this.price,this.image});}
Cart.dart
class Cart extends ChangeNotifier {
List<Item> _items = [];
double _totalPrice = 0.0;
void add(Item item) {
_items.add(item);
_totalPrice += item.price;
notifyListeners();}
void remove(Item item) {
_totalPrice -= item.price;
_items.remove(item);
notifyListeners();}
int get count {
return _items.length;}
double get totalPrice {
return _totalPrice;}
List<Item> get basketItems {
return _items;}}
You get this error because your add method form Cart class is waiting an Item object and you pass the productname which is a String.
From your code, you need to build a new Item from your Quantities widget like this :
cart.add(Item(title: productname, image: productimage, price : productprice));
But if you want to improve your code, you could replace those 3 attributes with your Item object on your Quantities class. You can first transform your class to a StatelessWidget :
class Quantities extends StatelessWidget {
final Item item;
Quantities(this.item);
#override
Widget build() {
...
Generally, you should use that Item object on your methods/Widgets where it's possible

How to convert double to string in Text Widget in Flutter

I create two pages first page is home page which display the image and name, second page is the detail page which shows image, name and price. Now problem is if i click on the image it should be display the image,name and price in second page but it is showing an error of type 'double' is not a subtype of type string even i tried to convert it to string. Below is the code of two pages and one dart class model.
HomePage.dart
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();}
class _HomeState extends State<Home> {
List<Product> _product=[
Product(
name: "Small Cake",
image: "assets/1.png",
price: 50.00,
),];
#override
Widget build(BuildContext context) {
return PlatformScaffold(
body: ListView.builder(
itemCount: _product.length,
itemBuilder: (BuildContext context, int index) {
return Products(
product_image: _product[index].image,
product_name: _product[index].name,
product_price: _product[index].price,);}));}}
class Products extends StatelessWidget {
final product_name;
final product_image;
final product_price;
Products({this.product_name, this.product_image, this.product_price});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
top: 35.0, bottom: 15.0, left: 20.0, right: 20.0),
child: GestureDetector(
onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Quantities(
productname: product_name,
productprice: product_price,
productimage: product_image,
)));},
child: Container(
child: new FittedBox(
child: Material(
color: Colors.white,
elevation: 15.0,
borderRadius: BorderRadius.circular(15.0),
shadowColor: Color(0x802196F3),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 250,
height: 200,
child: ClipRRect(
borderRadius: new BorderRadius.circular(15.0),
child: new Image.asset(
product_image,
fit: BoxFit.cover,),),),
Padding(
padding: const EdgeInsets.only(top: 5.0,bottom: 5.0),
child: Text(product_name,style: TextStyle(color: Colors.blueGrey[700],
fontWeight: FontWeight.bold,fontSize: 18.0),),),],)),),),),);}}
Quantities.dart
class Quantities extends StatefulWidget {
var productprice;
String productimage;
final productname;
Quantities({this.productprice, this.productimage, this.productname});
#override
_QuantitiesState createState() => _QuantitiesState(productprice,productimage,productname);
}
class _QuantitiesState extends State<Quantities> {
final productprice;
final productimage;
final productname;
var finalprice;
_QuantitiesState(this.productprice, this.productimage, this.productname);
#override
void initState() {
finalprice=double.parse(productprice);// tried to convert into string
super.initState();}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Details'),),
body: Container(
child: Column(
children: <Widget>[
Container(
height: 200.0,
child: GridTile(
child: Container(
color: Colors.white,
child: Image.asset(productimage),),),),
Text(productname),
Text(finalprice.toString()),// This line getting an error of type double is not a subtype of string
],),),);}}
Product.dart
class Product {
String name;
String image;
double price;
Product({this.name, this.price,this.image});}
Double To String
productprice.toString().
String To Double
double.parse(productprice.toString())

When I start flutter project I have this error "Error connecting to the service protocol: HttpException: Connection closed before full header"

I start to learn flutter and set up all settings and other things. But when I start project in VS Code or Android Studio I take this error "Error connecting to the service protocol: HttpException: Connection closed before full header was received, uri = http://127.0.0.1:60944/JpB2Y6E0g_g=/ws" and app don't start but when I go terminal and say "flutter run" then I have still take this error but application starts. Hovever I cant run application direckly and can't use "HOT-RELOAD"
I try clear flurred and close defender or any antivirus program that I have and somethings in the internet but any of them couldn't help me
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Anasayfa'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
I cant run project direckly only run from terminal ı want run application on the IDE and use "hot-reload"
Try to downgrade your Android version form Q to Pie.
It worked for me and many others on here

Display a svg from a String in Flutter/Dart

I'm trying to display an image from a svg String to the screen.
I'm using: https://pub.dartlang.org/packages/flutter_svg for svg support.
final String svgAsString = '''<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="109" height="109" viewBox="0
0 109 109">
<g id="kvg:StrokePaths_080a1" style="fill:none;stroke:#000000;stroke-
width:3;stroke-linecap:round;stroke-linejoin:round;">
<path id="kvg:080a1-s1"
d="M20.22,18.74c0.77,0.77,0.79,2.14,0.8,3.05C21.38,62,20.62,75,11.5,89.39"/>
</g>
</svg>''';
I'm having trouble getting this rendered to either an image widget or draw onto a canvas. I've tried both ways and not getting anywhere.
The full code I will paste below: I'm not sure if I'm on the right tracks.
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class KanjiGradeGenerator extends StatefulWidget {
#override
_KanjiGradeState createState() => _KanjiGradeState();
}
class _KanjiGradeState extends State<KanjiGradeGenerator> {
_KanjiGradeState() {}
displaySVG() async {
<g id="kvg:StrokePaths_080a1" style="fill:none;stroke:#000000;stroke-
width:3;stroke-linecap:round;stroke-linejoin:round;">
<path id="kvg:080a1-s1"
d="M20.22,18.74c0.77,0.77,0.79,2.14,0.8,3.05C21.38,62,20.62,75,11.5,89.39"/>
</g>
</svg>''';
final DrawableRoot svgRoot = await svg.fromSvgString(rawSvg, rawSvg);
final Picture picture = svgRoot.toPicture();
PictureRecorder picRec;
Canvas can = Canvas(picRec);
setState(() {
can.drawPicture(picture);
});
}
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: displaySVG()
),
);
}
}
The error I receive is:
I/flutter ( 7791): type 'Future' is not a subtype of type 'Widget'
Despite the documentation suggesting to do this:
final DrawableRoot svgRoot = await svg.fromSvgString(rawSvg, rawSvg);
I found you can run in to difficulties converting this to a Widget.
If your image string is encoded/decoded from Base64 then you can do this.
Once you have a string that is a raw string of an SVG you can do:
import 'package:flutter_svg/flutter_svg.dart';
String decoded; // Decoded image
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: SvgPicture.string(decoded)
),
);
}
You can use FutureBuilder widget for display image.
class KanjiGradeGenerator extends StatefulWidget {
#override
_KanjiGradeGeneratorState createState() => _KanjiGradeGeneratorState();
}
class _KanjiGradeGeneratorState extends State<KanjiGradeGenerator> {
final rawSvg = 'YOUR_PATH';
displaySvg() async {
final DrawableRoot svgRoot = await svg.fromSvgString(rawSvg, rawSvg);
return await svgRoot.toPicture().toImage(500, 500);
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: displaySvg(),
builder: (context,snapshot){
return Container(
child: snapshot.data,
);
},
);
}
}
You can do it like this:
SvgPicture.string(
'''<svg viewBox="...">...</svg>''' //Or your store it in a variable
)
then complete(inside State) sample usage would be:
class _SampleSvgState extends State<_SampleSvg> {
late String rawSvg;
#override
void initState() {
super.initState();
rawSvg = '''<svg viewBox="...">...</svg>''';
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(right: Const.space15),
child: InkWell(
onTap: (){},
borderRadius: BorderRadius.circular(Const.space12),
child: SizedBox(
width: 60,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 45,
height: 45,
padding: const EdgeInsets.all(Const.space12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(Const.space12),
),
child: SvgPicture.string(
rawSvg
),
),
const SizedBox(height: Const.space8),
Expanded(
child: Text(
"I am Sample Text",
maxLines: 1,
textAlign: TextAlign.center,
style: _theme.textTheme.subtitle2,
),
)
],
),
),
),
);
}
}

Resources