I have created a custom button widget class with Icon and onTap constructors. I want to use this button in any screen with custom icon and custom function on button tapped.
class ActionButton extends StatelessWidget {
ActionButton({this.icon, this.onPress});
final FaIcon? icon;
final Function? onPress;
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(18.0),
// padding: const EdgeInsets.all(0.2),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(6.0)),
// padding: const EdgeInsets.all(1.0),
child: IconButton(
onPressed: () {
onPress!;
},
icon: icon!,
color: Colors.black,
),
);
}
}
As you can see, with this widget I can use this ActionButton in any screen with any icon and its action will be any function what I pass as argument.
But when I am using this button on my another page and passing function, function does not get executed:
class ProductDetailsScreen extends StatelessWidget {
final Product? product;
const ProductDetailsScreen({Key? key, this.product}) : super(key: key);
#override
Widget build(BuildContext context) {
Sizes(context).initSize();
final double _h = Sizes.screenHeight;
final double _w = Sizes.screenWidth;
final _theme = Theme.of(context);
final product = ModalRoute.of(context)!.settings.arguments as Product;
void _goBack() {
Navigator.of(context).pop();
print('the page is popped');
}
return Scaffold(
// backgroundColor: _theme.scaffoldBackgroundColor,
body: SafeArea(
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ActionButton(
icon: FaIcon(
Icons.arrow_back,
),
onPress: () {
_goBack();
}),
ActionButton(
icon: FaIcon(Icons.share),
)
],
),
ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
Container(
height: 60,
child: Image.asset('${product.imageSource}'),
)
],
)
],
),
),
);
}
}
that_ goBack() function is not working
please help me, thanks in advance
In Product Details page you need to pass the onPress parameter as follows:
ActionButton(icon:FaIcon(
Icons.arrow_back,
),onPress:_goBack)`
And in ActionButton class
IconButton( onPressed: () { onPress!(); }, icon: icon!, color: Colors.black, ),
Related
I have an application like this:
My aim is that when I press the eye icon next to the text "Hello", I want a box to open just below the text and write the German version of "Hello". So it will say "Hallo".
My purpose is to show the meaning of the word.
When I press the eye, I want to show the German of the word. How can I make a white box under the word Hello, that is, the box in which the German language will be written?
Codes:
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
class selamlasmaLearn extends StatelessWidget {
List <wordAndMeaning> wordsList = [wordAndMeaning("Hello", "Hallo"), wordAndMeaning("Go", "Gehen")];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (context) {
final double height = MediaQuery.of(context).size.height;
return CarouselSlider(
options: CarouselOptions(
height: height,
viewportFraction: 1.0,
enlargeCenterPage: false,
),
items: wordsList.map((wordAndMeaning word) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Colors.amber),
child: Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
word.word,
style: TextStyle(fontSize: 45, color: Colors.white),
),
SizedBox(width: 10,),
Icon(Icons.remove_red_eye_sharp, color: Colors.white, size: 25,), // <<<<<<<<<
],
),
),
);
},
);
}).toList(),
);
}
),
);
}
}
class wordAndMeaning {
String word;
String meaning;
wordAndMeaning(this.word, this.meaning);
}
I keep the word and its German in a list called wordsList.
Thanks for the help in advance.
You can convert the widget to StatefulWidget or use a ValueNotifier to control the preserve/notify the state visibility.
You can use Visibility widget or just if to show and hide German text.
class selamlasmaLearn extends StatefulWidget {
#override
State<selamlasmaLearn> createState() => _selamlasmaLearnState();
}
class _selamlasmaLearnState extends State<selamlasmaLearn> {
bool _showGerman = false;
List<wordAndMeaning> wordsList = [
wordAndMeaning("Hello", "Hallo"),
wordAndMeaning("Go", "Gehen")
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(builder: (context) {
final double height = MediaQuery.of(context).size.height;
return CarouselSlider(
options: CarouselOptions(
height: height,
viewportFraction: 1.0,
enlargeCenterPage: false,
),
items: wordsList.map((wordAndMeaning word) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Colors.amber),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(word.word,
style:
TextStyle(fontSize: 45, color: Colors.white)),
if (_showGerman) Text(word.meaning), //modify the way you want
],
),
const SizedBox(
width: 10,
),
IconButton(
icon: Icon(Icons.remove_red_eye_sharp),
color: Colors.white,
iconSize: 25,
onPressed: () {
setState(() {
_showGerman = !_showGerman;
});
},
),
],
),
);
},
);
}).toList(),
);
}),
);
}
}
Use the Tooltip widget
I'm emphasizing on the popup part in your question title. When using a Tooltip you ensure that your widgets do not shift position or jump when the Tooltip widget appear, as the example below illustrates.
Example code:
import 'package:flutter/material.dart';
class TooltipExample extends StatelessWidget {
const TooltipExample({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Tooltip(
// Set the tooltip to trigger on a single tap, tapping outside the
// widget will make the tooltip disappear.
triggerMode: TooltipTriggerMode.tap,
// The message shown when the tooltip appears.
message: "Tooltip showing!",
// Consider adjusting this to your needs.
showDuration: const Duration(days: 1),
// The widget that must be clicked to show the tooltip.
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text("Hello"),
SizedBox(
width: 8,
),
Icon(Icons.visibility),
],
),
),
),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text("Cover me!"),
)
],
),
);
}
}
// Some code to run the above example, note the theme part that turns the
// tooltip white.
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
// Style the overall design of tooltips in the app in one place,
// or provide in each tooltip individually.
theme: ThemeData(
tooltipTheme: const TooltipThemeData(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(4),
),
),
textStyle: TextStyle(
backgroundColor: Colors.white,
color: Colors.black,
),
),
),
home: const Scaffold(
backgroundColor: Colors.amber,
body: TooltipExample(),
),
);
}
}
void main() => runApp(const App());
Here is how it looks:
Note that the Tooltip widget overlays whatever is below it. (instead of pushing it further down - like toggling the visibility of a normal widget in a row or column would have done)
Hello i have been stock here trying to figure out what am doing wrong, the male and female reuseable cards are surpose to change color when tapped but after placing the GestureDetector inside my card Class it stopped working. The color refuse to change when tapped, take a look at the code below.
import 'package:bmi_calculator/card_icon.dart';
import 'package:bmi_calculator/cards.dart';
import 'package:flutter/material.dart';
Color activeCardColor = const Color(0XFF1D1E33);
Color inactiveCardColor = const Color(0XFF111328);
Color buttomContainerColor = const Color(0xffeb1555);
const double buttomContainerHeight = 70.0;
enum Gender {
male,
female,
}
class InputPage extends StatefulWidget {
const InputPage({Key? key}) : super(key: key);
#override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender? selectedGender;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BMI CALCULATOR'),
),
body: Column(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: ReuseableCard(
ontapped: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male
? activeCardColor
: inactiveCardColor,
cardChild: const CardIcon(Icons.male, 'Male'),
),
),
Expanded(
child: ReuseableCard(
ontapped: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female
? activeCardColor
: inactiveCardColor,
cardChild: const CardIcon(Icons.male, 'Female'),
),
)
],
),
),
Expanded(
child: ReuseableCard(
colour: activeCardColor,
),
),
Expanded(
child: Row(
children: [
Expanded(
child: ReuseableCard(
colour: activeCardColor,
),
),
Expanded(
child: ReuseableCard(
colour: activeCardColor,
),
)
],
),
),
Container(
margin: const EdgeInsets.only(top: 10.0),
color: buttomContainerColor,
height: buttomContainerHeight,
width: double.infinity,
)
],
));
}
}
And here is my Card Class
import 'package:flutter/material.dart';
class ReuseableCard extends StatelessWidget {
final Color? colour;
final Widget? cardChild;
final void Function()? ontapped;
const ReuseableCard({this.colour, this.cardChild, this.ontapped});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
ontapped;
print('Button Pressed');
},
child: Container(
child: cardChild,
margin: const EdgeInsets.all(10),
width: double.infinity,
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
add brackets to the function call
onTap: () {
ontapped(); // here
print('Button Pressed');
},
The problem is in passing the ontapped function. When you simply place ontapped without Parenthesis () the function will not be called so you need to change that in following ways. When using Lambda function you have options to pass function
For multiple functions
onTap: () {
ontapped(); // here
},
For single function
onTap: ontapped, // here
I have a quantity that needs to be updated in the parent widget. Quantity needs to be updated when pressing + or - Icon in the child widget. I passed the callback function the the child stateless widget, but it is not working. Instead I get an error saying setstate() or markneedsbuild() called during build.
This is the parent widget
class Wash extends StatefulWidget {
#override
_WashState createState() => _WashState();
}
class _WashState extends State<Wash> {
int quantity = 0;
void updateQuantity(command) {
if (command == 'add') {
setState(() {
quantity++;
});
} else {
setState(() {
quantity--;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: OrderTile(
imgPath: 'shorts',
itemType: 'Shorts',
quantityCallBack: updateQuantity,
),
);
}
This is the child widget
class OrderTile extends StatelessWidget {
OrderTile({this.itemType, this.imgPath, this.quantityCallBack});
final String imgPath;
final String itemType;
final Function quantityCallBack;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(12.0),
child: Row(
children: <Widget>[
Expanded(
flex: 1,
child: CircleAvatar(
backgroundImage: AssetImage('images/${imgPath}.jpg'),
radius: 30.0,
),
),
Expanded(
flex: 3,
child: _Description(
title: itemType,
),
),
GestureDetector(
onTap: quantityCallBack('add'),
child: Icon(
Icons.add,
size: 24.0,
),
),
SizedBox(
width: 14,
),
Text('1'),
SizedBox(
width: 14,
),
GestureDetector(
onTap: quantityCallBack('remove'),
child: Icon(
Icons.remove,
size: 24.0,
),
),
],
),
);
}
}
Am I doing the right thing for the function call back implementation?
You're calling your callback function in the wrong way inside your onTap callback. Change:
onTap: quantityCallBack('add'),
for
onTap: () => quantityCallBack('add'),
You can only pass a function the way you passed if they have the same type. In this case the onTap is void function() it doesn't have any arguments.
Also, your not passing the updated quantity value to your Text Widget
I'm developing a catalog of products, with a List of Cards, each Card has a button, but when I press it, all the Cards, direct me to the same activity, how could I make each card I went to a different activity and modified it my way.
I've tried the Hero widget, but it's the same thing it repeats the same screen, just with different image and text.
PAGE OF LIST CARDS
import 'package:flutter/material.dart';
class SlidingCard extends StatelessWidget {
final String name; //<-- title of the event
final String date; //<-- date of the event
final String assetName; //<-- name of the image to be displayed
const SlidingCard({
Key key,
#required this.name,
#required this.date,
#required this.assetName,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.only(left: 8, right: 8, bottom: 24),
elevation: 8,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(32)), //<--custom shape
child: Column(
children: <Widget>[
ClipRRect( //<--clipping image
borderRadius: BorderRadius.vertical(top: Radius.circular(32)),
child: Image.asset( //<-- main image
'lib/assets/$assetName',
height: MediaQuery.of(context).size.height * 0.35,
width: 500,
fit: BoxFit.cover,
),
),
SizedBox(height: 8),
Expanded(
child: CardContent(
name: name,
date :date,
), //<-- will be replaced soon :)
),
],
),
);
}
}
class CardContent extends StatelessWidget {
final String name;
final String date;
const CardContent({Key key, #required this.name, #required this.date})
: super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(name, style: TextStyle(fontSize: 20)),
SizedBox(height: 8),
Text(date, style: TextStyle(color: Colors.grey)),
Spacer(),
//SizedBox(width: 30),
Row(
children: <Widget>[
RaisedButton(
color: Color(0xFF162A49),
child: Text('VER PRODUCTOS'),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
onPressed: () {print("Hello");}, //<-- I want this button to allow each card to navigate to a different activity
),
SizedBox(width: 4),
Icon( Icons.visibility),
SizedBox(width: 16),
],
)
],
),
);
}
}
PAGE CARDS
import 'package:flutter/material.dart';
import 'package:pt_nisira_app/controller/cards_ex.dart';
class pagePay extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
body: Center(
child : Padding(
padding: const EdgeInsets.only(top:15.0),
child: SlidingCardsView(),
),
),
);
}
}
class SlidingCardsView extends StatefulWidget {
#override
_SlidingCardsViewState createState() => _SlidingCardsViewState();
}
class _SlidingCardsViewState extends State<SlidingCardsView> {
PageController pageController;
#override
void initState() {
super.initState();
pageController = PageController(viewportFraction: 0.8);
}
#override
void dispose() {
pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: 350,
height: MediaQuery.of(context).size.height * 0.65, //<-- set height of the card
child: PageView(
controller: pageController,
children: <Widget>[
SlidingCard(
name: 'CATALAGO DE GASEOSAS',
date: '4.20-30',
assetName: 'bebidas_gaseosas.jpg',
),
SlidingCard(
name: 'CATALAGO DE GOLOSINAS',
date: '4.28-31',
assetName: 'golosinas_productos.jpg',
),
SlidingCard(
name: 'CATALAGO DE LACTEOS',
date: '4.28-31',
assetName: 'lacteos_productos.jpg',
),
SlidingCard(
name: 'CATALAGO DE PRODUCTOS DE COCINA',
date: '4.28-31',
assetName: 'cocina_productos.jpg',
),
],
),
);
}
}
I would like each page to be customized
First, you should create a list of routes as :
final routes = ['/FirstPage', '/SecondPage'];
Then, on onTap() of the list item :
Navigator.pushNamed(context, routes[index]);
you can pass activity prop to your SlidingCard.
SlidingCard(
name: 'CATALAGO DE GOLOSINAS',
date: '4.28-31',
assetName: 'golosinas_productos.jpg',
activity: () {
print('do some acitivity');
}
),
SlidingCard(
name: 'CATALAGO DE GOLOSINAS',
date: '4.28-31',
assetName: 'golosinas_productos.jpg',
activity: () {
print('do some another acitivity');
}
),
and in your CardContent widget :
RaisedButton(
color: Color(0xFF162A49),
child: Text('VER PRODUCTOS'),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
onPressed: () {
activity(); // pass your acitivity prop from top level widget to CardContent widget and call it on the RaisedButton;
},
),
I have a main dart file and a settings dart file. The settings dart file is responsible for the appearance of the main dart file. Settings dart has a AppTheme class. Upon users typing on this settings page I want the main page to update.
My attempt at this was calling the class and redefining the variables based on user input. Doesnt work whether or not I use setState(). I also tried jus staying on the main page and tried changing the theme onPressed for the settings button. That didnt work either. Iconbutton update doesnt update the state either.
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:resume/settings.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Title',
theme: ThemeData.light(),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
double buttonMargin = MediaQuery.of(context).size.width / 10;
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
return MaterialApp(
home: Scaffold(
backgroundColor: AppTheme().backgroundMain,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Column(
children: <Widget>[
Container(
height: (MediaQuery.of(context).size.height / 2.25),
child: Column(children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: Text(AppTheme().name,
style: TextStyle(
fontFamily: 'Pacifico',
fontSize: screenWidth / 8.57142857143,
color: AppTheme().nameTextColor,
fontWeight: FontWeight.bold)),
),
]),
),
Container(
height: screenHeight / 2.3,
alignment: Alignment.bottomCenter,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(
buttonMargin * 1.5,
buttonMargin * 3,
buttonMargin * 1.5,
buttonMargin * 3),
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width / 2,
child: RaisedButton(
color: AppTheme().backgroundSecondary,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.settings,
color: Colors.white,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Settings',
style: TextStyle(color: Colors.white),
),
)
],
),
onPressed: () {
setState(() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return MySettings();
}),
);
},
);
},
),
),
],
),
),
],
),
),
),
),
);
}
}
settings.dart
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
void settings() {
runApp(MySettings());
}
class AppTheme {
var backgroundMain = Colors.red;
var backgroundSecondary = Colors.teal;
var backgroundAvatar = Colors.white;
var nameTextColor = Colors.white;
var professionTextColor = Colors.red[100];
var contactTextColor = Colors.teal;
var testPrint = print("hi");
String name = 'John Doe';
String nameFont = 'Pacifico';
String professionFont = 'roboto';
}
class MySettings extends StatefulWidget {
#override
MySettingsState createState() => MySettingsState();
}
class MySettingsState extends State<MySettings> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: AppTheme().backgroundMain,
title: Text('Settings'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
setState(() {
AppTheme().backgroundMain = Colors.yellow;
print(AppTheme().name);
Navigator.pop(context);
});
},
),
),
backgroundColor: Colors.teal,
body: SafeArea(
child: ListView(
children: <Widget>[
Container(
child: TextField(
onChanged: (text) {
setState(() {
AppTheme().name = text;
});
},
),
),
Container(
child: TextField(),
),
],
)),
),
);
}
}
1 Make sure to properly import
Flutter/Dart Static variables lost / keep getting reinitialized
2 You cannot alter the variables in the class. You must create an object and alter the object.
i.e I was doing
Class MyClass {
var myVariable = someValue
}
MyClass.myVariale = aDifferentValue
This did not update MyClass
What I needed to do worked once I created an object
var myClassObject = new Myclass();
myClassObject.myVariable = aDifferentValue
Now I just alter and call on myClassObject.