How can I implement a validator to a TextField. I know TextFormField has a validator option, but I need the validator in a TextField. If the TextField value is not valid I need to decorate it, just like a TextFormField.
You can do like this:
class MyHomePage extends StatefulWidget {
#override
MyHomePageState createState() {
return new MyHomePageState();
}
}
class MyHomePageState extends State<MyHomePage> {
final _text = TextEditingController();
bool _validate = false;
#override
void dispose() {
_text.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TextField Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Error Showed if Field is Empty on Submit button Pressed'),
TextField(
controller: _text,
decoration: InputDecoration(
labelText: 'Enter the Value',
errorText: _validate ? 'Value Can\'t Be Empty' : null,
),
),
RaisedButton(
onPressed: () {
setState(() {
_text.text.isEmpty ? _validate = true : _validate = false;
});
},
child: Text('Submit'),
textColor: Colors.white,
color: Colors.blueAccent,
)
],
),
),
);
}
}
This code shows error text when the user don't enter anything in the TextField
Related
here is my code of dropDownButton.I'm trying to making select GenderList dropDownButton but when I assign variable selectedGender to value of dropDownButton it's hide hint text and default select first index value Male.
I want this output
But I'm getting this output when i assign selectedGender variable type int to value in dropDownButton
Here is my code when I comment on the value then it shows a hint text let's see my code below.
import'package:flutter/material.dart';
class DropDownButton extends StatefulWidget {
const DropDownButton({Key? key}) : super(key: key);
#override
State<DropDownButton> createState() => _DropDownButtonState();
}
class _DropDownButtonState extends State<DropDownButton> {
List<DropdownMenuItem<int>> genderList=[];
void loadGenderlist(){
genderList=[];
genderList.add(const DropdownMenuItem(
child: Text('Male'),
value: 0,));
genderList.add(const DropdownMenuItem(
child: Text('Female'),
value: 1,));
genderList.add(const DropdownMenuItem(
child: Text('Other'),
value: 2,));
}
String selectval = "United Kingdom";
int selectedGender = 0;
#override
Widget build(BuildContext context) {
loadGenderlist();
return Scaffold(
appBar: AppBar(
title: Text("Form Validation with All Controls"),
backgroundColor: Colors.redAccent
),
body: SafeArea(
child: ListView(
children: [
DecoratedBox(
decoration: BoxDecoration(
color: Colors.green,
border: Border.all(color: Colors.black38,width: 3)
),
child: DropdownButton(
hint: Text("Select Gender"),
items: genderList,
//value: selectedGender,
onChanged: (value){
setState(() {
selectedGender =int.parse(value.toString()) ;
});
},
underline: Container(),
),
)
],
),
)
);
}
}
I want this output:
I try to create a widget test. But I can't understand how to identify widgets can find the key in the main code and do a test?
Main. dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Reversi',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var _controller;
var _reversed;
#override
void initState() {
super.initState();
_controller = TextEditingController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Reversi'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Enter string to reverse"),
),
const SizedBox(height: 10.0),
if (_reversed != null) ...[
Text(
_reversed,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
const SizedBox(height: 10.0),
],
RaisedButton(
child: Text("Reverse"),
onPressed: () {
if (_controller.text.isEmpty) return;
setState(() {
_reversed = reverseString(_controller.text);
});
},
),
],
),
),
);
}
}
String reverseString(String initial) {
return initial.split('').reversed.join();
}
This is the widget test code I created. Is this code correct to find the key in the main code and do the test?
main_widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_testing/main.dart';
import 'package:flutter_test/flutter_test.dart';
void main(){
testWidgets('Reverse string widget test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
var textField = find.byType(TextField);
expect(textField, findsOneWidget);
await tester.enterText(textField, 'Hello');
expect(find.text('Hello'), findsOneWidget);
var button = find.text("Reverse");
expect(button,findsOneWidget);
await tester.tap(button);
await tester.pump();
expect(find.text("olleH"),findsOneWidget);
});
}
How can we identify whether the widget can find the key in the main code and do a test? Can someone explain to me if this code is correct?
I have an app with a tab bar and to make the UI better, I wanted to make it so that the colour changes when you got to another tab. How do I make it so that when I click or swipe to another tab, let's say the yellow tab, the whole appbar changes to that colour?
Code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ColorChange>(
create: (context) => ColorChange(),
child: MaterialApp(
theme: ThemeData.light(),
home: SimpleTab(),
),
);
}
}
class _TestPageState extends State<TestPage> {
TabController controller;
class ColorChange extends ChangeNotifier {
Color color = colors[0];
Color getColor() {
return color;
}
void changeColor() {
color = colors[controller.index];
print(color);
notifyListeners();
}
}
List<Color> colors = const [
Colors.green,
Colors.yellow,
Colors.red,
Colors.blue,
Colors.deepOrange,
Colors.deepPurple,
];
class SimpleTab extends StatefulWidget {
#override
_SimpleTabState createState() => _SimpleTabState();
}
class _SimpleTabState extends State<SimpleTab>
with SingleTickerProviderStateMixin {
Tester tester = Tester();
#override
void initState() {
super.initState();
controller = TabController(length: colors.length, vsync: this);
controller.addListener(ColorChange().changeColor);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Simple Tab Demo"),
backgroundColor: Provider.of<ColorChange>(context).getColor(),
bottom: TabBar(
controller: controller,
tabs: [
Tab(
text: 'Green',
),
Tab(
text: 'Yellow',
),
Tab(
text: 'Red',
),
Tab(
text: 'Blue',
),
Tab(
text: 'Orange',
),
Tab(
text: 'Purple',
),
],
isScrollable: true,
),
),
body: TabBarView(
controller: controller,
children: <Widget>[
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
],
),
);
}
}
This is just a very simplified demo of my real app. My real app deals with a lot of data fetched from APIs, hence it is probably better if setstate() was not used, because re-building the whole widget may call http requests unnecessarily.
You can try this
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Demo App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: SimpleTab(),
);
}
}
class CustomTab {
const CustomTab({this.title, this.color});
final String title;
final Color color;
}
class SimpleTab extends StatefulWidget {
#override
_SimpleTabState createState() => _SimpleTabState();
}
class _SimpleTabState extends State<SimpleTab>
with SingleTickerProviderStateMixin {
TabController controller;
List<CustomTab> tabs = const <CustomTab>[
const CustomTab(title: 'Home', color: Colors.deepOrangeAccent),
const CustomTab(title: 'Setting', color: Colors.blueGrey),
const CustomTab(title: 'Map', color: Colors.teal),
];
CustomTab selectedTab;
#override
void initState() {
super.initState();
controller = new TabController(length: tabs.length, vsync: this);
controller.addListener(_select);
selectedTab = tabs[0];
}
void _select() {
setState(() {
selectedTab = tabs[controller.index];
});
}
#override
Widget build(BuildContext context) {
textStyle() {
return new TextStyle(color: Colors.white, fontSize: 30.0);
}
return new Scaffold(
appBar: new AppBar(
title: new Text("Smiple Tab Demo"),
backgroundColor: selectedTab.color,
bottom: new TabBar(
controller: controller,
tabs: tabs
.map((e) => new Tab(
text: e.title,
))
.toList()),
),
body: new TabBarView(
controller: controller,
children: tabs
.map(
(e) => new Container(
color: e.color,
child: new Center(
child: new Text(
e.title,
style: textStyle(),
),
),
),
)
.toList()),
);
}
}
I have a widget called Classroom, and in this widget has a button that navigattes you to another page called ButtonPage. It has only one button that triggers a function which affects Classroom's state. It works perfectly. But the problem is that I also want to change LightButton's color with the updated state in Classroom widget. Here is codes.
Classroom
class Classroom extends StatefulWidget {
#override
_ClassroomState createState() => _ClassroomState();
}
class _ClassroomState extends State<Classroom> {
bool isLightOn = false;
final List<String> lightColor = ["red", "green", "blue"];
String currentItem = "red";
void onButtonPress() {
setState(() {
isLightOn = isLightOn;
});
}
void selectItem(String selectedItem) {
setState(() {
currentItem = selectedItem;
});
}
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
padding: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
LightBulb(
isLightOn: isLightOn,
currentItem: currentItem,
),
Container(
child: MaterialButton(
textColor: Colors.white,
color: Colors.blue,
child: Text("Go to button's page"),
onPressed: () {
Navigator.push(context,
MaterialPageRoute<void>(builder: (BuildContext context) {
return ButtonPage(
isLightOn: isLightOn,
onButtonPress: onButtonPress,
);
}));
},
),
),
LightColorSelector(
selectItem: selectItem,
currentItem: currentItem,
lightColor: lightColor,
),
],
),
);
}
}
ButtonPage
class ButtonPage extends StatelessWidget {
final bool isLightOn;
final VoidCallback onButtonPress;
const ButtonPage({this.isLightOn, this.onButtonPress});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Button Page"),
),
body: Center(
child: Container(
child: LightButton(
isLightOn: isLightOn,
onButtonPress: onButtonPress,
),
)),
);
}
}
LightButton
class LightButton extends StatelessWidget {
final bool isLightOn;
final VoidCallback onButtonPress;
const LightButton({this.isLightOn, this.onButtonPress});
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
padding: EdgeInsets.all(5.0),
child: MaterialButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
color: Colors.blue,
textColor: Colors.white,
child:
isLightOn ?? false ? Text("Turn light off") : Text("Turn light on"),
onPressed: () {
onButtonPress();
},
),
);
}
}
When I click MaterialButton which is labeled as Go to button's page, it navigates me to ButtonPage with isLightOn and onButtonPress variables. In LightButton, when onButtonPress is triggered, it rebuild only previous page. That's why Light Button's label isn't changed. How can I make it affected?
When long tab on Text widget, a tooltip show up with 'copy'. When click on the 'copy' the text content should copy to system clipboard.
The following will copy the text on long tap, but does not show up 'copy', so user will not know, the content is copied to the clipboard.
class CopyableText extends StatelessWidget {
final String data;
final TextStyle style;
final TextAlign textAlign;
final TextDirection textDirection;
final bool softWrap;
final TextOverflow overflow;
final double textScaleFactor;
final int maxLines;
CopyableText(
this.data, {
this.style,
this.textAlign,
this.textDirection,
this.softWrap,
this.overflow,
this.textScaleFactor,
this.maxLines,
});
#override
Widget build(BuildContext context) {
return new GestureDetector(
child: new Text(data,
style: style,
textAlign: textAlign,
textDirection: textDirection,
softWrap: softWrap,
overflow: overflow,
textScaleFactor: textScaleFactor,
maxLines: maxLines),
onLongPress: () {
Clipboard.setData(new ClipboardData(text: data));
},
);
}
}
Since Flutter 1.9 you can use
SelectableText("Lorem ipsum...")
When text is selected the "Copy" context button will appear.
You can use a SnackBar to notify the user about the copy.
Here is a relevant code:
String _copy = "Copy Me";
#override
Widget build(BuildContext context) {
final key = new GlobalKey<ScaffoldState>();
return new Scaffold(
key: key,
appBar: new AppBar(
title: new Text("Copy"),
centerTitle: true,
),
body:
new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new GestureDetector(
child: new Text(_copy),
onLongPress: () {
Clipboard.setData(new ClipboardData(text: _copy));
key.currentState.showSnackBar(
new SnackBar(content: new Text("Copied to Clipboard"),));
},
),
new TextField(
decoration: new InputDecoration(hintText: "Paste Here")),
]),
);
}
EDIT
I was working on something and I did the followin, so I thought of revisiting this answer:
import "package:flutter/material.dart";
import 'package:flutter/services.dart';
void main() {
runApp(new MaterialApp(home: new MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
String _copy = "Copy Me";
#override
Widget build(BuildContext context) {
final key = new GlobalKey<ScaffoldState>();
return new Scaffold(
key: key,
appBar: new AppBar(
title: new Text("Copy"),
centerTitle: true,
),
body:
new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new GestureDetector(
child: new CustomToolTip(text: "My Copyable Text"),
onTap: () {
},
),
new TextField(
decoration: new InputDecoration(hintText: "Paste Here")),
]),
);
}
}
class CustomToolTip extends StatelessWidget {
String text;
CustomToolTip({this.text});
#override
Widget build(BuildContext context) {
return new GestureDetector(
child: new Tooltip(preferBelow: false,
message: "Copy", child: new Text(text)),
onTap: () {
Clipboard.setData(new ClipboardData(text: text));
},
);
}
}
There is also list of properties it in SelectableText to enable option copy, paste, selectAll, cut
child: Center(
child: SelectableText('Hello Flutter Developer',
cursorColor: Colors.red,
showCursor: true,
toolbarOptions: ToolbarOptions(
copy: true,
selectAll: true,
cut: false,
paste: false
),
style: Theme.of(context).textTheme.body2)
),
SelectableText widget
const SelectableText(
this.data, {
Key key,
this.focusNode,
this.style,
this.strutStyle,
this.textAlign,
this.textDirection,
this.showCursor = false,
this.autofocus = false,
ToolbarOptions toolbarOptions,
this.maxLines,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection = true,
this.onTap,
this.scrollPhysics,
this.textWidthBasis,
})
SelectableText(
"Copy me",
onTap: () {
// you can show toast to the user, like "Copied"
},
)
If you want to have different styling for text, use
SelectableText.rich(
TextSpan(
children: [
TextSpan(text: "Copy me", style: TextStyle(color: Colors.red)),
TextSpan(text: " and leave me"),
],
),
)
I use Clipboard.setData inside function.
...
child: RaisedButton(
onPressed: (){
Clipboard.setData(ClipboardData(text: "$textcopy"));
},
disabledColor: Colors.blue[400],
child: Text("Copy", style: TextStyle(color: Colors.white),),
),
I created a helper class CopiableText to accomplish my job. Just copy the class from below and put it in your code.
Helper class
copiable_text_widget.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CopiableText extends StatelessWidget {
final String text;
final String copyMessage;
final Widget child;
CopiableText(this.text, {this.copyMessage, this.child});
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
child: InkWell(
onTap: () {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(this.copyMessage ?? 'Copied to clipboard'),
));
Clipboard.setData(new ClipboardData(text: this.text));
},
child: Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 2),
child: this.child ??
Text(
this.text,
style: TextStyle(color: Color(0xFF1E272E), fontSize: 14),
),
),
),
),
);
}
}
Use it in different ways
import 'package:chaincargo_courier/ui/widgets/copiable_text_widget.dart';
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
// Just straightforward, click to copy
CopiableText('You are awesome'),
// Give a custom confirmation message
CopiableText(
'Asia, Nepal, Biratnagar',
copyMessage: 'Address copied to clipboard',
),
// Set custom child
CopiableText(
'Stunning view of mount everest',
copyMessage: 'Caption copied to clipboard',
child: Column(
children: [
Image.network(
'https://cdn.pixabay.com/photo/2010/11/29/mount-everest-413_960_720.jpg',
errorBuilder: (BuildContext context, Object exception,
StackTrace stackTrace) {
return Text('Cannot load picture');
},
),
Text('Stunning view of mount everest')
],
),
),
],
),
);
}
}
Just use SelectableText
SelectableText(
iosInfo.identifierForVendor.toString(),
),
Support Links and Copy&Paste
If you want to support both Links and Copy&Paste, use the SelectableLinkify widget.
This widget is part of the flutter_linkify package.
SelectableLinkify(
text: "Made by https://cretezy.com\n\nMail: example#gmail.com",
);