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())
Related
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'),
),
),
]))));
}
}
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
I am using crossAxisAlignment: CrossAxisAlignment.center, but somehow the text 'Logo' is just not centered. Really not too sure what is causing it and am I missing something here.
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text('Login'),
),
body: GestureDetector(
child: Container(
padding: EdgeInsets.only(
top: 100.0, right: 20.0, left: 20.0, bottom: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Logo',
style: TextStyle(fontSize: 50.0),
),
],
),
),
),
);
}
}
From Flutter docs about Container:
Containers with no children try to be as big as possible unless the incoming constraints are unbounded, in which case they try to be as small as possible. Containers with children size themselves to their children. The width, height, and constraints arguments to the constructor override this.
https://api.flutter.dev/flutter/widgets/Container-class.html
Your Column and Text('Logo') aren't big enough to use all screen width, so Container doesn't use all screen width as you can see in the image (taken with Dart DevTools, which is very useful for debug)
You can add more widgets to your Column and the width will grow as they use it, or just add width: MediaQuery.of(context).size.width to your Container to take up all the available width of the parent.
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text('Login'),
),
body: GestureDetector(
child: Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(
top: 100.0, right: 20.0, left: 20.0, bottom: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Logo',
style: TextStyle(fontSize: 50.0),
),
],
),
),
),
);
}
}
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,
),
)
],
),
),
),
);
}
}
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