I am trying to pass some color info from one widget to another but I am not able to get that color in destination widget. I wanted to build a single class with some UI code in it and just call this class in my main widget so that I don't have to repeat the code all over again, but I am not able to pass the data,
Here is the code that I am working on: What I am doing wrong?
void main(List<String> args) => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: Scaffold(
appBar: AppBar(
title: const Text('Stateless/Clean Code'),
),
body: const StatelessOne(),
),
);
}
}
class StatelessOne extends StatelessWidget {
const StatelessOne({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Text(
'Widget color can be customised without \nhaving to retype the entire code'),
StatelessTwo(key: key, param: Colors.green),
StatelessTwo(key: key, param: Colors.pink),
StatelessTwo(key: key, param: Colors.blue),
StatelessTwo(key: key, param: Colors.orange),
],
),
);
}
}
class StatelessTwo extends StatelessWidget {
StatelessTwo({Key? key, #required param}) : super(key: key);
final Map param = {};
#override
Widget build(BuildContext context) {
return Container(
height: 120,
width: 250,
color: param['color'],
child: Center(child: Text('Your Repetitive Widget $key')),
);
}
}
Simple way will be
class StatelessTwo extends StatelessWidget {
final Color color;
const StatelessTwo({
Key? key,
required this.color,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 120,
width: 250,
color: color,
child: Center(
child: Text('Your Repetitive Widget ${key ?? "no key found"}')),
);
}
}
-----
color: color, //use
Pass color
StatelessTwo(key: key, color: Colors.green), and seems you are passing same key, avoid it is not necessary for Ui-logic. Most likely, you don't need to pass key, if you still want to pass use UinqueKey()
Related
I need to create a custom text-widget in the Flutter. I have to change any color it accepts in the style with an opacity of 0.7. If it does not have a style, I have to show the color from the default style with an opacity of 0.7 .
My problem is creating a new text widget with the feature I described.
There are multiple ways to approach this problem:
You can make a function based Widget or a class based Widget:
Function based Widget:
Widget myCustomText({required String data, Color? customColor}) {
return Opacity(
opacity: 0.7,
child: Text(
data,
style: TextStyle(
color: customColor ?? Colors.black,
),
),
);
}
Another approach is making a class based widget:
class MyCustomText extends StatelessWidget {
final String data;
final Color? customColor;
const MyCustomText({Key? key, required this.data, this.customColor})
: super(key: key);
#override
Widget build(BuildContext context) {
return Opacity(
opacity: 0.7,
child: Text(
data,
style: TextStyle(color: customColor ?? Colors.black),
),
);
}
}
Here's how you can implement your custom text wherever required:
// Code M:
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//Widget based Implementation
myCustomTextWidget(data: "Hello world"),
myCustomTextWidget(data: "Hello Peter", customColor: Colors.amber),
//Class based implementation
MyCustomTextClassWidget(data: "Hello Spidey"),
MyCustomTextClassWidget(data: "Hello 007", customColor: Colors.orange,)
],
),
);
}
}
Explanation: Null(??) operator checks if whether the value is given or not and if not given, then it will used default value after it.
Conclusion: Using Class based Widget i.e. Approach Number 2 is more robust and using class based widget is recommended by Flutter Official Team. It is also rebuild freindly and highly performant.
Output of the above code(M):
The working solution simply uses
ThemeData.primaryColor for the configuration of default text color;
If it does not have a TextStyle passes to CustomTextWidget, the default text color is used with an opacity of 0.7;
If it does have a TextStyle passes to CustomTextWidget, the textStyle is used with an opacity of 0.7.
Codes here:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: const HomeWidget(title: _title),
theme: ThemeData.light().copyWith(
// default text color
primaryColor: Colors.pink,
colorScheme: ColorScheme.fromSwatch().copyWith(
// change the appbar color
primary: Colors.green[800],
),
),
);
}
}
class HomeWidget extends StatelessWidget {
const HomeWidget({
Key? key,
required String title,
}) : _title = title,
super(key: key);
final String _title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
CustomTextWidget(text: 'text does not have a style'),
CustomTextWidget(
text: 'text with passed black color style and fontSize 24',
textStyle: TextStyle(
fontSize: 24,
color: Colors.black
),
),
CustomTextWidget(
text: 'text with passed blue color style',
textStyle: TextStyle(
color: Colors.blue
),
),
],
),
);
}
}
class CustomTextWidget extends StatelessWidget {
final String text;
final TextStyle? textStyle;
const CustomTextWidget({Key? key, required this.text, this.textStyle}) : super(key: key);
#override
Widget build(BuildContext context) {
final TextStyle finalTextStyle = textStyle ?? const TextStyle();
final Color? finalColor = textStyle != null && textStyle!.color != null
? textStyle!.color
: Theme.of(context).primaryColor;
return Text(
text,
// it accepts in the style with an opacity of 0.7.
style: finalTextStyle.copyWith(color: finalColor!.withOpacity(0.7)),
);
}
}
Expected outcome:
I could have used the widget Opacity very easily, but due to the Flutter document for Opacity Widget (resource) and the high cost of re-rendering the child, it was not necessary.
The whole problem could be solved by DefaultTextStyle. You only need to pay attention to handling the context, which is documented in the code below.
Two modes are seen in the following code:
1- If TextStyle is not defined for your Text widget, it follows the default color at DefaultTextStyle.of.(context) or Theme and then manual Opacity value is also set.
2- If TextStyle is defined for your Text widget, it follows the defined color and its manual Opacity value is also set.
import 'package:flutter/material.dart';
const double OPACITY_VALUE = 0.7;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomeWidget(),
);
}
}
class HomeWidget extends StatelessWidget {
const HomeWidget({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
/// ATTENTION: parent of this context is Material App .
return Scaffold(
body: Center(
child: Builder(builder: (context2) {
/// context2 is important because referred to parent , and parent is Scaffold .
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
/// color and textStyle of this text widget referred to current Theme or DefaultTextStyle .
Text(
'You have pushed the button this many times:',
style: DefaultTextStyle.of(context2).style.copyWith(
color: DefaultTextStyle.of(context2)
.style
.color!
.withOpacity(OPACITY_VALUE)),
),
const CustomizedTextWidget(color: Colors.purple),
],
);
}),
),
);
}
}
class CustomizedTextWidget extends StatelessWidget {
const CustomizedTextWidget({
Key? key,
required this.color,
}) : super(key: key);
final Color color;
#override
Widget build(BuildContext context) {
return Text(
'0',
style: TextStyle(color: color, fontSize: 32)
.copyWith(color: color.withOpacity(OPACITY_VALUE)),
);
}
}
I have SVG as an image file where I want to do this cursor hover effect.
I tried onhoverbutton but that does not work here.
I am using flutter_svg package for showing SVG image
Container(
width: double.infinity,
height: 400,
child: SvgPicture.asset('assets/below.svg',
cacheColorFilter: true,
color: const Color(0xff2C66B8)),
)
This is what I want in my web-app
if you run below code in dartpad, you will get idea about how hover works in flutter.
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MouseRegion with custom cursor',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: MouseRegionWithCustomCursor(
cursor: const Icon(Icons.refresh, color: Colors.white),
// here you have to replace this with your svg image
child: Container(width: 300, height: 200, color: Colors.blueGrey),
),
);
}
}
// and in this class you can implement your blue line expansion and compression lines
class MouseRegionWithCustomCursor extends HookWidget {
final Widget cursor;
final Widget child;
const MouseRegionWithCustomCursor({
Key? key,
required this.cursor,
required this.child,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final cursorPosition = useState<Offset?>(null);
return MouseRegion(
cursor: SystemMouseCursors.none,
onHover: (event) => cursorPosition.value = event.localPosition,
onExit: (event) => cursorPosition.value = null,
child: Stack(
children: [
child,
if (cursorPosition.value != null)
AnimatedPositioned(
duration: const Duration(),
left: cursorPosition.value?.dx,
top: cursorPosition.value?.dy,
child: cursor,
),
],
),
);
}
}
i know this is not best explanation but you can start with this.
I would like to have a persistent container occupy the space about my material Scaffolds AppBar. I would like the Scaffold to resize to take up the available space.
When I try to do this, my Scaffold continues to be the height of the entire screen, and it is simply pushed lower, with a portion overflowing off the screen.
Is there a way I can have the Scaffold to resize to the available space?
Here is what I have coded so far...
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return PersistenTopBar(
child: Scaffold(
appBar: AppBar(
title: const Text("Test App"),
),
body: Container(),
),
);
}
}
class PersistenTopBar extends StatelessWidget {
final Widget child;
const PersistenTopBar({Key? key , required this.child }) : super(key: key);
#override
Widget build(BuildContext context) {
var mediaQuery = MediaQuery.of(context);
return Column(
children: [
Container(
width: double.infinity,
height: 200,
color: Colors.red,
),
SizedBox(
width: mediaQuery.size.width,
height: mediaQuery.size.height,
child: child,
),
],
);
}
}
You could also create a CustomAppBar that would take as children a topChild and an appBar.
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
final double height;
final Widget topChild;
final AppBar appBar;
const CustomAppBar(
{Key? key,
this.height = 200.0,
required this.topChild,
required this.appBar})
: super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(child: topChild),
appBar,
],
);
}
#override
Size get preferredSize => Size.fromHeight(height);
}
Full code sample
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
topChild: Container(color: Colors.red),
appBar: AppBar(title: const Text('My awesome Test App')),
),
body: const Center(
child: Text(
"Test App",
style: TextStyle(fontSize: 32.0),
),
),
);
}
}
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
final double height;
final Widget topChild;
final AppBar appBar;
const CustomAppBar(
{Key? key,
this.height = 200.0,
required this.topChild,
required this.appBar})
: super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(child: topChild),
appBar,
],
);
}
#override
Size get preferredSize => Size.fromHeight(height);
}
the available space = mediaQuery.size.height - the Height of the Container above the appBar so the SizedBox under the appBar wil be :
SizedBox(
width: mediaQuery.size.width,
height: mediaQuery.size.height - 200,
child: child,
),
the result:
or you can wrap your SizedBox with Expanded Widget :
Expanded(
child: SizedBox(
width: mediaQuery.size.width,
child: child,
),
),
the same result :
Why I still got error functio at flutter?
I'd removed the old function and used new function, but it was still got old function.
In my main.dart, I tried to called LoginScreen
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'yocamp',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: mobileBackgroundColor,
),
home: LoginScreen(),
);
}
}
But it was called MobileScreenLayout
home: const ResponsiveLayout(
mobileScreenLayout: MobileScreenLayout(),
webScreenLayout: WebScreenLayout(),
),
In my LoginScreen
class LoginScreen extends StatefulWidget {
const LoginScreen({Key? key}) : super(key: key);
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 32),
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//sva image
SvgPicture.asset(
'assets/yocampLogo.svg',
//color: primaryColor,
height: 64,
),
const SizedBox(height: 64),
//text field input for email
//text field input for password
//button login
//Transitioning to singing up
],
),
),
));
}
}
in the MobileScreenLayout
class MobileScreenLayout extends StatelessWidget {
const MobileScreenLayout({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('This is mobile'),
));
}
}
I want to show svg, but it's still show This is mobile
where has problems?
I am totally new to flutter/dart and not sure if my question is correct. In the following is a part of the code I am writing. Now I want to get that text variable from the SecondRoute widget and make a list of string using word from text variable(I do not know if I can do it with StatelessWidget).Now I can not get this "text" variable from the _SecondRouteState class and also I can not make a list from it in the SecondRoute widget. The text varibale is taking string from the user input and it is coming from the home screen.
class SecondRoute extends StatefulWidget {
String text;
SecondRoute({Key? key, required this.text}) : super(key: key);
#override
_SecondRouteState createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Second Route"),
),
body: Center(
child: Text(
"hello world",
// text,
style: TextStyle(fontSize: 24),
),
),
);
}
}
You need to call with widget
class SecondRoute extends StatefulWidget {
String text;
SecondRoute({Key? key, required this.text}) : super(key: key);
#override
_SecondRouteState createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Second Route"),
),
body: Center(
child: Text(
widget.text, // changes need
style: TextStyle(fontSize: 24),
),
),
);
}
}
Try below code
Text(widget.text),