Flutter execute a form validation with Button with seperate class - android

I have one login page .dart that contains 3 seperate object class dart such as : InputEmail , Password and ButtonLogin which its split each other but it's called together in login page
My problem is how can i validate form input email and password when i submit the button login when field is empty and email not valid
I tried to create Globalkey FormState inside login page and call it on button login class dart though
Onpressed event but nothing give me error message.
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.redAccent, Colors.lightBlueAccent]),
),
key: _formKey,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
Row(children: const <Widget>[
VerticalText(),
TextLogin(),
]),
const InputEmail(),
const PasswordInput(),
const ButtonLogin(),
const FirstTime(),
],
),
],
),
),
);
}
}
class ButtonLogin extends StatefulWidget {
const ButtonLogin({Key? key}) : super(key: key);
#override
_ButtonLoginState createState() => _ButtonLoginState();
}
class _ButtonLoginState extends State<ButtonLogin> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 40, right: 50, left: 200),
child: Container(
alignment: Alignment.bottomRight,
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.blue,
blurRadius: 10.0, // has the effect of softening the shadow
spreadRadius: 1.0, // has the effect of extending the shadow
offset: Offset(
5.0, // horizontal, move right 10
5.0, // vertical, move down 10
),
),
],
color: Colors.white,
borderRadius: BorderRadius.circular(30),
),
child: FlatButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'OK',
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
Icon(
Icons.arrow_forward,
color: Colors.lightBlueAccent,
),
],
),
),
),
);
}
}

You can pass the callback of onPressed function of button to Login Page and validate it there.
class ButtonLogin extends StatefulWidget {
const ButtonLogin({Key? key, required this.onPressed}) : super(key: key);
final VoidCallBack onPressed ;
#override
_ButtonLoginState createState() => _ButtonLoginState();
}
class _ButtonLoginState extends State<ButtonLogin> {
#override
Widget build(BuildContext context) {
return Padding(
child: Container(
....
child: FlatButton(
onPressed: widget.onPressed,
child: Row(
...
);
}
}
and change add this onPressed parameter inside ButtonLogin widget on Login page
const InputEmail(),
const PasswordInput(),
const ButtonLogin(onPressed: () {
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
},),
const FirstTime(),

The easy way is to create a single StateFulWidget and within the StateFulWidget, you brake your form Widgets (InputEmail, Password and ButtonLogin) into separate Widget methods(functions). Afterward Wrap them with a Form widget using Row, Column or any Widget that accept list.
Next you add the _formKey to the Form widget. I will advice the use of controller for your inputs. Below is an example using your code. By the way change FlatButton -> TextButton
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
#override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.redAccent, Colors.lightBlueAccent]),
),
child: Form(
key: _formKey,
child: ListView(
children: [
Column(
children: [
// inputEmail(),
// passwordInput(),
buttonLogin(),
],
),
],
),
),
),
);
}
Widget buttonLogin() {
return Padding(
padding: const EdgeInsets.only(top: 40, right: 50, left: 200),
child: Container(
alignment: Alignment.bottomRight,
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: const [
BoxShadow(
color: Colors.blue,
blurRadius: 10.0,
spreadRadius: 1.0,
offset: Offset(5.0, 5.0),
),
],
),
child: TextButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'OK',
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
Icon(
Icons.arrow_forward,
color: Colors.lightBlueAccent,
),
],
),
),
),
);
}
}

Related

Updating State of StatefulWidget from other StatefulWidget in Flutter?

i am trying to update the state of the animated switcher in the middle area. i am trying to do this using a setstate in the lower area. but it does not work.
the first thing i did is to create a variable with a boolean data type in the home class.
then i passed the variable to both the middle area and the lower area
the idea was that if the same variable is passed to the class whose state i am trying to update, and the class with the set state, it would work. but it seems i am wrong. i would appreciate some assistance.
the boolean variable i am trying to make work is the _rep variable
This is the Home widget
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
late AnimationController _animationController;
late AnimationController _controller;
late Animation<Offset> _animation;
late Animation<Offset> _anime;
bool _rep = true;
#override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 2)
);
_animation = Tween<Offset>(
begin:Offset (0.0, 0.0),
end: Offset (0.0,3.0),
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeIn));
_anime = Tween<Offset>(
begin:Offset (0.0, 0.0),
end: Offset (0.0,-0.55),
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeIn));
super.initState();
}
#override
void dispose() {
_animationController.dispose();
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
child: Padding(
padding: EdgeInsets.only(top: 3.h),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TopIcon(icons: Icons.arrow_back, color:Colors.grey.shade300 ,),
SizedBox(
height: 13.h,
width: 13.w,
child: Image.asset('assets/images/download.png')
),
TopIcon(icons: Icons.shopping_bag_outlined, color: Colors.grey.shade300,),
],
),
SizedBox(
height: 3.h,
),
Text('Frappuccino',
style: TextStyle(
fontSize: 27.sp,
fontWeight: FontWeight.bold
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('White Chocolate',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey.shade400
),
),
),
MiddleArea(
controller: _animationController,
animation: _animation,
rep: _rep,
),
LowerArea(controller: _animationController, anime: _anime, rep = _rep),
],
),
),
),
);
}
}
This is the middle area
class MiddleArea extends StatefulWidget {
MiddleArea({Key? key, required this.controller, required this.animation, required this.rep}) : super(key: key);
AnimationController controller;
Animation<Offset> animation;
final bool rep;
#override
State<MiddleArea> createState() => _MiddleAreaState();
}
class _MiddleAreaState extends State<MiddleArea> {
bool _flag = true;
bool _favourite = true;
#override
Widget build(BuildContext context) {
print(widget.rep);
return SizedBox(
height: 52.h,
child: Stack(
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 135.0),
child: Text('STARBUCKS',
style: TextStyle(
fontFamily: 'Typette',
color: Colors.brown.shade200,
fontSize: 30.sp,
fontWeight: FontWeight.w400
),
),
),
Text('STARBUCKS',
style: TextStyle(
fontFamily: 'Typette',
color: Colors.brown.shade100,
fontSize: 30.sp,
fontWeight: FontWeight.w400
),
),
Text('STARBUCKS',
style: TextStyle(
fontFamily: 'Typette',
color: Colors.brown.shade50,
fontSize: 30.sp,
fontWeight: FontWeight.w400
),
),
],
),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SizeAndFave(text: 'Preference'),
SizeAndFave(text: 'Fave!')
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: (){
setState(() {
_flag = !_flag;
});
},
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
transitionBuilder: (Widget child, Animation<double> animation){
return FadeTransition(opacity: animation, child: child,);
},
child: widget.rep == true?Padding(
padding: const EdgeInsets.all(14.0),
key: const Key('1'),
child: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
border: Border.all(
color: Colors.brown.shade300,
width: 3
),
borderRadius: BorderRadius.circular(10)
),
child: const Center(
child: Icon(
Icons.coffee_outlined,
size: 20,
),
)
),
):null,
)
),
GestureDetector(
onTap: (){
setState(() {
_favourite = !_favourite;
});
},
child: _favourite? TopIcon(icons: Icons.favorite_border, color: Colors.brown.shade300)
:TopIcon(
icons: Icons.favorite, color: Colors.brown.shade300)
)
],
)
],
),
AnimatedSwitcher(
duration: Duration(seconds: 1),
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition( opacity: animation,
child: child);
},
child: _flag == true ? Center(
key: const Key('1'),
child: SlideTransition(
position: widget.animation,
child: SizedBox(
height: 80.h,
width: 80.w,
child: Image.asset('assets/images/starcup.png'),
),
),
):Center(
key: const Key('2'),
child: SlideTransition(
position: widget.animation,
child: SizedBox(
height: 80.h,
width: 80.w,
child: Image.asset('assets/images/greeen.png'),
),
),
),
),
Positioned(
child:
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(top: 30.h),
child: TopIcon(
icons: Icons.car_crash_outlined, color: Colors.brown.shade300),
),
)),
const Positioned(
child:
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: EdgeInsets.only(top: 330.0, left: 14),
child: Text('\$ 5.99',
style: TextStyle(
fontSize: 27,
fontWeight: FontWeight.bold
),
),
),
))
],
),
);
}
}
and lastly, the lower area
class LowerArea extends StatefulWidget {
final AnimationController controller;
final Animation<Offset> anime;
bool rep;
LowerArea({Key? key, required this.controller, required this.anime, required this.rep}) : super(key: key);
#override
State<LowerArea> createState() => _LowerAreaState();
}
class _LowerAreaState extends State<LowerArea> {
bool _bigger = true;
bool _fade = true;
void move(){
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: EdgeInsets.all(1.h),
child: const Text('Tall Frappuccino',
style: TextStyle(
fontWeight: FontWeight.w500
),
),
),
Padding(
padding: EdgeInsets.only(right: 5.h),
child: const Text('Swipe Down',
style: TextStyle(
fontWeight: FontWeight.w500
),
),
),
Padding(
padding: EdgeInsets.all(2.h),
child: const Text('Pickup',
style: TextStyle(
fontWeight: FontWeight.w500
),
),
)
],
),
),
SlideTransition(
position: widget.anime,
child: AnimatedContainer(
// height: 11.h,
width: _bigger ? 35.h: 80.h,
duration: const Duration(milliseconds: 500),
child: Stack(
fit: StackFit.loose,
children: [
Center(child: Image.asset('assets/images/baggie.png')),
Center(
child: Padding(
padding: EdgeInsets.only(bottom: 4.h),
child: GestureDetector(
onTap: (){
widget.controller.forward();
setState(() {
_bigger = !_bigger;
_fade = !_fade;
widget.rep = !widget.rep;
print('this is fade $_fade ');
});
},
child: AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (Widget child, Animation<double> animation){
return FadeTransition(opacity: animation, child: child,);
},
child: _fade? Container(
key: Key('1'),
height: 8.h,
width: 7.w,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(15)
),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(0.3.h),
child: Icon(
Icons.lock_outline,
color: Colors.white54,
size: 2.5.h,
),
),
Icon(
Icons.arrow_drop_down,
color: Colors.white12,
size: 3.h,
),
],
),
):null,
),
),
),
)
],
),
),
)
],
);
}
use provider pacakges https://pub.dev/packages/provider
Create a class that inherits the functions of ChangeNotifyer to create a flag to control and create a setter.
provider class
class StateController extends ChangeNotifier{
bool _req = false;
bool get req => _req; //getter
setReqValue(){
_req = !_req;
notifyListener();
}
}
Declare the provider class in the main function. You can change the location of the declaration according to Wiget tree, but first declare it in main
Change main.dart
void main(){
runApp(
Multiprovider(
providers: [
ChangeNotifierProvider(create: (_) => StateController()),
],
child: HomePage(),
)
);
}
The UI is updated by notifyListener().
change UI
child: context.watch<StateController>().req == true ? Padding(
padding: const EdgeInsets.all(14.0),
key: const Key('1'),
child: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
border: Border.all(
color: Colors.brown.shade300,
width: 3
),
borderRadius: BorderRadius.circular(10)
),
child: const Center(
child: Icon(
Icons.coffee_outlined,
size: 20,
),
)
),
):null,
Change State
onTap: (){
widget.controller.forward();
setState(() {
_bigger = !_bigger;
_fade = !_fade;
context.read<StateController>().setReqValue();
print('this is fade $_fade ');
});
},
I am too lazy to try understand your code. But if you want to update state of the page after you pop from Navigation to it.
In page you want to update
Navigation.push(context, /* Page that will change something */)
// Future will trigger then you return to this page.
.then((_) => setState(() {}))

Method not found: 'miniPlayer'

I have a page with name playerPage which contains the bottomNavigationBar which has got mini player and navigation items respectively. I also have a MyHomePage which contains the songs to be played. I created a constructor with Function name miniPlayer in MyHomePage to call _miniPlayer method in the playerPage but I am getting an error that says Method not found: 'miniPlayer'.
MyHomePage
class MyHomePage extends StatefulWidget {
final Function miniPlayer;
const MyHomePage(this.miniPlayer);
// const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState(miniPlayer);
}
class _MyHomePageState extends State<MyHomePage> {
final Function miniPlayer;
_MyHomePageState(this.miniPlayer);
Widget _recommended(context) {
return Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection("Worship").snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.hasData) {
final snap = snapshot.data!.docs;
return ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: snap.length,
itemBuilder: (context, index) {
return Stack(
children: [
GestureDetector(
child:Container(
height:50,
width: MediaQuery.of(context).size.width,
child: Card(
child: Center(
child: Row (
children : [
Text(
snap[index]['name'],
textAlign: TextAlign.start,
style: const TextStyle(
color: Colors.black54,
fontWeight: FontWeight.bold,
),
),
SizedBox(width:50),
Text(
snap[index]['title'],
textAlign: TextAlign.start,
style: const TextStyle(
color: Colors.black54,
fontWeight: FontWeight.bold,
),
),
]
)),
)),
onTap: () {
var ur= snap[index]['url'];
var ti =snap[index]['title'];
var music =snap[index]['music'];
**miniPlayer(url:ur,le:ti,music:music);** Getting error here
},
)
],
// ),
);
},
);
} else {
return const SizedBox();
}
},
)
],
);
}
PlayerPage
this is the miniPlayer method in the playerPage
Widget miniPlayer(le,url,music) {
this.le =le;
this.url =url;
this.music =music;
setState(() {
});
if(widget.le.isEmpty) {
return SizedBox();
}
return AnimatedContainer(
duration: const Duration(milliseconds: 500),
color: Colors.indigo,
height: MediaQuery.of(context).size.height * 0.07,
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Container(
padding: EdgeInsets.only(left: 6),
child: CircleAvatar(
backgroundColor: Colors.indigo,
radius: 20,
child: IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow_rounded,
color: Colors.white,
),
onPressed: () async {
if (isPlaying) {
await audioPlayer.pause();
} else {
await audioPlayer.resume();
}
},
),
),
),
const SizedBox(
width: 10,
),
Container(
padding: EdgeInsets.only(left: 5),
width: MediaQuery.of(context).size.width * 0.85,
child: Column(
children: [
Expanded(
child: Marquee(
textDirection: TextDirection.ltr,
velocity: 30,
blankSpace: 90,
//pauseAfterRound: const Duration(seconds: 2),
text: widget.le,
style: const TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.bold),
))
],
))
],
),
);
}
First of all, here it's not properly understood. It's a little bit messy. But one thing is make sure you pass it down the widget tree. And another thing is try not to pass properties through private constructors.
You can easily access that property (aka. miniPlayer function) just by typing widget.miniPlayer. In that way you can be more sure that this function is available in the main widget class.
Also you're returning an widget inside a function. Make sure you use it. Other wise that widget getting returned won't do anything inside a function.

Flutter - How to change the visibility of a single widget in a widget list?

I pull some variables in Firebase and I create a widget list with these variables. I want to control widget visibility when I click a widget. When I use the Visibility widget and set "visible: widgetVisibility" value, all widgets are changed at the same time. I only want the widget I clicked to change. How can I do that?
body: StreamBuilder<QuerySnapshot>(
stream: _keyService.getKeys(),
builder: (context, snapshot) {
return !snapshot.hasData
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot mypost = snapshot.data!.docs[index];
return Padding(
padding: EdgeInsets.all(size * 0.3),
child: InkWell(
onTap: () {
valueVisible = !valueVisible;
},
child: Container(
decoration: BoxDecoration(
color: ColorItems.mainColor,
border: Border.all(width: 5, color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: EdgeInsets.all(size),
child: Container(
child: Row(
children: [
Expanded(
child: Text(
"${mypost['key']}",
style: const TextStyle(
color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold),
),
),
const Text(
": ",
style:
TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(
width: 20,
),
Expanded(
child: Visibility(
visible: valueVisible,
child: Text(
"${mypost['value']}",
style: const TextStyle(
color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold),
),
))
],
),
),
),
),
),
);
},
);
})
Additionally, screenshots is here..
This might not be the optimal solution, but I always create a List for that purpose:
instead of one valueVisible bool I create a List and add a bool for each item in the list.
...itemBuilder: (context, index) { valueVisibleList.add(true)...
and in the button I then use the current item index to change only the corresponding bool
onTap: () { setState(({
valueVisibleList[index] = !valueVisibleList[index];
})
},
Just use a Map<String, bool> where the keys are the post's key and the value its visibility. The visibility should default to true if the key is not present. And the state should only change inside a setState function.
It would be something like the following (Check out the live demo on DartPad):
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 const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
final posts = [
for (var i = 0; i < 100; i++) {'key': 'key$i', 'value': '$i'}
];
class _MyHomePageState extends State<MyHomePage> {
final valueVisible = <String, bool>{};
#override
Widget build(BuildContext context) {
const size = 16.0;
return Scaffold(
body: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
final mypost = posts[index];
return Padding(
padding: const EdgeInsets.all(size * 0.3),
child: InkWell(
onTap: () {
setState(() {
valueVisible[mypost['key']!] =
!(valueVisible[mypost['key']!] ?? true);
});
},
child: Container(
decoration: BoxDecoration(
color: const Color(0xffff9400),
border: Border.all(width: 5, color: Colors.grey),
borderRadius: const BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(size),
child: Row(
children: [
Expanded(
child: Text(
"${mypost['key']}",
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold),
),
),
const Text(
": ",
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold),
),
const SizedBox(
width: 20,
),
Expanded(
child: Visibility(
visible: valueVisible[mypost['key']!] ?? true,
child: Text(
"${mypost['value']}",
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold),
),
),
)
],
),
),
),
),
);
},
),
);
}
}

Hello, issue with GestureDetector, Pan and Scale issue

I've a code that allows me to move text with a finger over an image, and also scale the text using both fingers over the text, but there are two problems and not much about it at google, hope someone can help me, first problem is:
If I uncomment the commented code, I get this error:
*The following assertion was thrown building HomePage(dirty, state: _HomePageState#8b5a9):
Incorrect GestureDetector arguments.
Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan.
Just use the scale gesture recognizer.
*
If I only use scale, delta(details.delta.dx) is not available in scale, so I get an error.
And the other issue is:
When I set textScaleFactor: _scaleFactor, inside my TEXT widget, the text desappears , how can I fix this ? Thanks a lot guys.
import 'package:flutter/material.dart';
void main() {
runApp(const TextOverImage());
}
class TextOverImage extends StatelessWidget {
const TextOverImage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
// Size size = MediaQuery.of(context).size;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Text Over Image Image Example'),
),
body: Center(
child: Container(
height: 300,
width: 300,
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.blue,
image: const DecorationImage(
image: NetworkImage(
"https://thumbs.dreamstime.com/b/funny-face-baby-27701492.jpg"),
fit: BoxFit.fill)),
),
const HomePage()
],
),
),
),
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Offset offset = Offset.zero;
Offset offset2 = Offset.zero;
double scale = 0.0;
double _scaleFactor = 1.0;
double _baseScaleFactor = 1.0;
double _savedVal = 1.0;
#override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned(
left: offset.dx,
top: offset.dy,
child: Row(
children: [
GestureDetector(
onPanUpdate: (details) {
setState(() {
offset = Offset(offset.dx + details.delta.dx,
offset.dy + details.delta.dy);
});
},
// behavior: HitTestBehavior.translucent,
//
// onScaleStart: (details) {
// _baseScaleFactor = _scaleFactor;
//
// },
//
// onScaleUpdate: (details) {
// setState(() {
// _scaleFactor = _baseScaleFactor * details.scale;
// });
// },
child: SizedBox(
width: 300,
height: 300,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text("You Think You Are Funny But You Are Not",
// here if I remove _scaleFactor the text is GONE
textScaleFactor: _scaleFactor,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.red)),
),
),
),
),
],
),
),
Positioned(
left: offset2.dx,
top: offset2.dy,
child: Row(
children: [
GestureDetector(
onPanUpdate: (details) {
setState(() {
offset2 = Offset(offset2.dx + details.delta.dx,
offset2.dy + details.delta.dy);
});
},
child: const SizedBox(
width: 300,
height: 300,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: Text("xx xxxx x xx x x xxxxxx",
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.red)),
),
),
),
),
],
),
),
],
);
}
}
You can achieve the functionality using MatrixGestureDetector from matrix_gesture_detector package.
Straightforward implementation will be as follows:
class FloatingWidget extends StatefulWidget {
final Widget child;
const FloatingWidget({Key? key, required this.child}) : super(key: key);
#override
State<FloatingWidget> createState() => _FloatingWidgetState();
}
class _FloatingWidgetState extends State<FloatingWidget> {
Matrix4 _transform = Matrix4.identity();
#override
Widget build(BuildContext context) => Transform(
transform: _transform,
child: MatrixGestureDetector(
onMatrixUpdate: (matrix, translationDeltaMatrix, scaleDeltaMatrix, rotationDeltaMatrix) {
setState(() {
_transform = matrix;
});
},
child: widget.child,
),
);
}
In your case,
import 'package:flutter/material.dart';
import 'package:matrix_gesture_detector/matrix_gesture_detector.dart';
void main() {
runApp(const TextOverImage());
}
class TextOverImage extends StatelessWidget {
const TextOverImage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
// Size size = MediaQuery.of(context).size;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Text Over Image Image Example'),
),
body: Center(
child: SizedBox.fromSize(
size: const Size(300, 300),
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.blue,
image: const DecorationImage(
image: NetworkImage(
"https://thumbs.dreamstime.com/b/funny-face-baby-27701492.jpg"),
fit: BoxFit.fill)),
),
const HomePage()
],
),
),
),
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Stack(
children: [
FloatingWidget(
child: Row(
children: [
SizedBox.fromSize(
size: const Size(300, 300),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: Text("You Think You Are Funny But You Are Not",
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.red,
)
),
),
),
),
],
),
),
FloatingWidget(
child: Row(
children: [
SizedBox.fromSize(
size: const Size(300, 300),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: Text("xx xxxx x xx x x xxxxxx",
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.red,
),
),
),
),
),
],
),
),
],
);
}
}
Well, scale gesture is a superset of pan gesture and you can get its offset delta as
scaleUpdateDetails.focalPointDelta
I have no idea about the text scale factor problem at this point but it will be irrelevant if you are using Transform widget.
To learn more about Transform widget, I suggest this article from Medium.

Flutter : hintText of TextField not getting updated in Screen UI

Using builTextField() method to create textField, passing different controller.
TextEditingController phoneController;
TextEditingController otpController;
builTextField(phoneController),
builTextField(otpController),
hintText is populated using phoneController.text and otpController.text for respective textFields.
Similarly,
using buildRaisedButton() method to create Button, passing differetnt callback.
buildRaisedButton('Register', registrationCallback),
buildRaisedButton('Verify', verifyOTPCallback),
buildRaisedButton('Reset',resetCallback),
on button click 'Reset', want to clear the hitText of both the textfields
resetCallback(){
print('cleared ....');
setState(() {
phoneController.clear();
otpController.clear();
});
}
It looks like controller.clear is resetting the conroller.text value to empty(''), but as the value for hintText is chosen to be conroller.text, should also get updated in screen to 'empty'. but unfortunately somehow its not reflecting in UI, eventhough wrapped the code inside setState()
buildTextField()
Widget buildTextField(TextEditingController controller, ) {
return Container(
height: 40.0,
width: 200.0,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(32),
),
child: TextField(
keyboardType: TextInputType.number,
style: kPhoneAuthTextFields,
decoration: InputDecoration(
hintStyle: kPhoneAuthTextFields,
hintText:controller.text,
suffixIcon: Icon(Icons.phone_android,size: 20,color: Colors.white,),
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 5.0, left: 30.0),
),
onChanged: (value) {
controller.text = value;
},
),
);
}
buildRaisedButton()
Widget buildRaisedButton(String label, Function callback){
return Container(
height: 40.0,
width: 100.0,
child: RaisedButton(
child:Text(
label,
style: kPhoneLoginTextStyle,
),
color: Colors.blue,
//padding: EdgeInsets.all(8.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40.0)),
onPressed: callback,
),
);
}
any help, appreciated... Thanks in Advance...
You can copy paste run full code below
In your case, you can provide UniqueKey() in buildTextField
code snippet
Widget buildTextField(TextEditingController controller,) {
return Container(
key: UniqueKey(),
working demo
full code
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
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;
TextEditingController phoneController = TextEditingController();
TextEditingController otpController = TextEditingController();
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget buildTextField(
TextEditingController controller,
) {
return Container(
key: UniqueKey(),
height: 40.0,
width: 200.0,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(32),
),
child: TextField(
keyboardType: TextInputType.number,
//style: kPhoneAuthTextFields,
decoration: InputDecoration(
hintStyle: TextStyle(color: Colors.orange),
hintText: controller.text,
suffixIcon: Icon(
Icons.phone_android,
size: 20,
color: Colors.white,
),
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 5.0, left: 30.0),
),
onChanged: (value) {
controller.text = value;
},
),
);
}
Widget buildRaisedButton(String label, Function callback) {
return Container(
height: 40.0,
width: 100.0,
child: RaisedButton(
child: Text(
label,
//style: kPhoneLoginTextStyle,
),
color: Colors.blue,
//padding: EdgeInsets.all(8.0),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(40.0)),
onPressed: callback,
),
);
}
resetCallback() {
print('cleared ....');
setState(() {
phoneController.clear();
otpController.clear();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buildTextField(phoneController),
buildTextField(otpController),
buildRaisedButton('Reset', resetCallback),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Categories

Resources