How to copy the value of a Widget Text to another using onPressed property of a button - flutter

I need to copy a value of a Text Widget and copy this to another.
I tried to this using keys, but I don't know how to acess the Text Widget in this case.
Is it possible to do in Flutter, using the onPressed property?
import 'package:flutter/material.dart';
class TextWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Value to be copied",
key: Key('text1')
),
RaisedButton(
onPressed: (){
// code here
},
child: Text("Copy value"),
),
SizedBox(height: 40),
Text(
"",
key: Key('text2')
)
],
),
),
);
}
}

Answering your question directly: you can access text inside Text widget using its data property.
Text widget = Text('text value');
String text = widget.data;
print(text); // text value
Next, you can't access widgets by their key properties. At least you shouldn't, because they were designed for different purpose: here's a video and an article about keys in Flutter.
What you can do here is turn your TextWidget from StatelessWidget into StatefulWidget and render contents of your second Text based on the state. Good introduction into what the state is and why you should use it can be found on official Flutter website: Start thinking declaratively.
Then you can save your first Text widget in a variable and then access its contents directly using data property update, then update state of the whole widget.
Example 1 on DartPad
More canonical and in general preferrable approach is to render contents of both buttons based on the state and get desired text from state variable and not from the widget itself, as proposed by Sebastian and MSARKrish.
Example 2 on DartPad
Note that you can't change data attribute of a Text widget imperatively, like you would do in JavaScript DOM API with innerText:
_textWidget.data = "New text"; // Doesn't work
because its data is final. In Flutter you have to think declaratively, and it worth it.

Try this
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
String _text = "Value to be copied";
bool _buttonToggle;
#override
void initState() {
super.initState();
_buttonToggle = false;
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_text),
SizedBox(height: 40),
RaisedButton(
onPressed: _toggle,
child: Text("Copy value"),
),
Switch(
value: _buttonToggle,
onChanged: (_) => _toggle(),
),
SizedBox(height: 40),
Text(_buttonToggle ? _text : '')
],
);
}
void _toggle() {
setState(() => _buttonToggle = !_buttonToggle);
}
}

class TextWidget extends StatefulWidget {
#override
_TextWidgetState createState() => _TextWidgetState();
}
class _TextWidgetState extends State<TextWidget> {
String text1Value = "text to be copied";
String text2Value = "";
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
text1Value,
),
RaisedButton(
onPressed: () {
setState(() {
text2Value = text1Value;
});
},
child: Text("Copy value"),
),
SizedBox(height: 40),
Text(
text2Value,
)
],
),
),
);
}
}

Related

flutter Change part of text selected color in textfield

I want when the user selects a part of the text in textfield and clicks on the color button, only that part of the selected text will be colored.
Thanks
I searched all the articles but couldn't find any results.
Nima jan Salaam,
you need to use rich_text_controller package like this code below:
first of all add rich_text_controller: ^1.4.0 in your pubspec.yaml (or any compatible versions).
import 'package:flutter/material.dart';
import 'package:rich_text_controller/rich_text_controller.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: RichTextControllerDemo(),
);
}
}
class RichTextControllerDemo extends StatefulWidget {
const RichTextControllerDemo({super.key});
#override
State<RichTextControllerDemo> createState() => _RichTextControllerDemoState();
}
class _RichTextControllerDemoState extends State<RichTextControllerDemo> {
RichTextController? _controller;
#override
void initState() {
_controller = RichTextController(
stringMatchMap: {
"test": const TextStyle(color: Colors.red),
},
onMatch: (List<String> matches){
}
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _controller,
onChanged: (value){
},
),
Padding(
padding: const EdgeInsets.only(top : 20.0),
child: InkWell(
child: const Text('click'),
onTap: (){
var start = _controller!.selection.start;
var end = _controller!.selection.end;
var text = _controller!.text.substring(start,end);
setState(() {
_controller!.stringMatchMap!.addAll(
{
text : const TextStyle(color: Colors.cyan),
}
);
});
},
),
)
],
)),
);
}
}
happy coding bro...

How do i print the value which is coming from modal bottom sheet to the main scaffold body in dart+flutter

ive created a text and icon button, onpressing that icon
modal bottom sheet gets generated, in that
and ive created a separate dart file with text field and a submit button
when giving an input on text field and after clicking on submit button the given input string will be printed below
atlast i called the function in first dart file
but i want the text to be printed on the main scaffold page.
Below is the main code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:practice1/StatefulModalbtn.dart';
void main() {
runApp(Modalbtn());
}
class Modalbtn extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Modal Bottom Test'),
),
body: Column(
children: <Widget>[Mymodal()],
),
),
);
}
}
class Mymodal extends StatelessWidget {
const Mymodal({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'Press the icon to select the Tractor model',
style: TextStyle(fontSize: 15),
),
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: <Widget>[StatefulModalbtn()],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
)
],
),
);
}
}
and below code is for creating a text field and submit button
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatefulWidget {
const StatefulModalbtn({Key? key}) : super(key: key);
#override
_StatefulModalbtnState createState() => _StatefulModalbtnState();
}
class _StatefulModalbtnState extends State<StatefulModalbtn> {
TextEditingController textController = TextEditingController();
String displayText = "";
#override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: textController,
maxLines: null,
),
ElevatedButton(
onPressed: () {
setState(() {
displayText = textController.text;
});
},
child: Text('Submit')),
Text(
displayText,
style: TextStyle(fontSize: 20),
),
],
);
}
}
and below is the output link
this is the output im achieving but i want the "Hello World" to be printed on top/main screen, right after the + add icon screen
How should i solve this ??
I just slightly edited your code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'main1.dart';
void main() {
runApp(MaterialApp(
home: Modalbtn(),
));
}
class Modalbtn extends StatefulWidget {
#override
_ModalbtnState createState() => _ModalbtnState();
}
class _ModalbtnState extends State<Modalbtn> {
String value = "0";
// Pass this method to the child page.
void _update(String newValue) {
setState(() => value = newValue);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: [StatefulModalbtn(update: _update)],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
),
Text(
value,
style: TextStyle(fontSize: 40),
),
],
),
),
);
}
}
and the child class is
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatelessWidget {
final ValueChanged<String> update;
StatefulModalbtn({required this.update});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => update("100"), // Passing value to the parent widget.
child: Text('Update (in child)'),
);
}
}

flutter build only a single widget

I have two widgets in a column. One is Text and second is TextButton. What i want that if i click on button then the Text widget rebuild only not the whole page.
I am new to flutter how can i achieve this? If i convert this to a statful widget and call setState method then whole page will be rebuild. but i want to know any trick to do rebuild only a single widget out of whole page.
class Page3 extends StatelessWidget {
Color color = Colors.red;
changeColor() {
// do something to rebuild only 1st column Text not the whole page
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
Text(
'Title',
style: TextStyle(color: color),
),
//Second widget
TextButton(
onPressed: () => changeColor(),
child: Text('change color of title'),
)
],
));
}
}
Please refer to below code
ValueListenableBuilder widget. It is an amazing widget. It builds the widget every time the valueListenable value changes. Its values remain synced with there listeners i.e. whenever the values change the ValueListenable listen to it. It updates the UI without using setState() or any other state management technique.
In Dart, a ValueNotifier is a special type of class that extends a ChangeNotifer . ... It can be an int , a String , a bool or your own data type. Using a ValueNotifier improves the performance of Flutter app as it can help to reduce the number times a widget gets rebuilt.
ValueListenableBuilder will listen for changes to a value notifier and automatically rebuild its children when the value changes.
For more info refer to this link description
Solution 1
class Page3 extends StatelessWidget {
Color color = Colors.red;
final ValueNotifier<bool> updateColor = ValueNotifier(false);
changeColor(Color changedColor) {
// do something to rebuild only 1st column Text not the whole page
color = changedColor;
updateColor.value = !updateColor.value;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
ValueListenableBuilder<bool>(
valueListenable: updateColor,
builder: (context, val, child) {
return Text(
'Title',
style: TextStyle(color: color),
);
}),
//Second widget
TextButton(
onPressed: () => changeColor(Colors.purple),
child: Text('change color of title'),
)
],
));
}
}
Solution 2
In ValueListenable we pass our created ValueNotifier variable whose changes will be notified and in builder we will return a widget that will be reflected every time when the value of ValueNotifier will be changed.
class Page3 extends StatelessWidget {
// Color color = Colors.red;
final ValueNotifier<Color> updateColor = ValueNotifier(Colors.red);
changeColor(Color changedColor) {
// do something to rebuild only 1st column Text not the whole page
updateColor.value = changedColor;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
ValueListenableBuilder<Color>(
valueListenable: updateColor,
builder: (context, val, child) {
return Text(
'Title',
style: TextStyle(color: val),
);
}),
//Second widget
TextButton(
onPressed: () => changeColor(Colors.purple),
child: Text('change color of title'),
)
],
));
}
}
Here's the code of what you need to do
class Demo extends StatefulWidget {
const Demo({Key? key}) : super(key: key);
#override
State<Demo> createState() => _DemoState();
}
class _DemoState extends State<Demo> {
var isTextChanged = false;
Void changeColor() {
setState(() {
isTextChanged = true;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
Text(
'Title',
style: TextStyle(color: isTextChanged ? Colors.red : Colors.black),
),
//Second widget
TextButton(
onPressed: () => changeColor(),
child: Text('change color of title'),
)
],
));
}
}
setStatefunction can not be called inside StatelessWidget widget. if you want to rebuild the widget tree, you have to convert it to StatefulWidget.
This is what you can do.
class Page3 extends StatefulWidget {
const Page3();
#override
_Page3State createState() => _Page3State();
}
class _Page3State extends State<Page3> {
Color color = Colors.red;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
Text(
'Title',
style: TextStyle(color: color),
),
TextButton(
onPressed: () => changeColor(),
child: Text('change color of title'),
)
]),
);
}
changeColor() {
setState(() {
color = Colors.green;
});
}
}
If you want to rebuild the Text widget without rebuilding the whole Page3 then you need to got for 'state management' solution.
Try below code hope its help to you. you must used StateFulWidget for that
Create one bool variable
bool isButtonPressed = true;
Your widgets:
Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Title',
style: isButtonPressed
? TextStyle(
color: Colors.black,
fontSize: 20,
)
: TextStyle(
color: Colors.green,
fontSize: 20,
),
),
),
TextButton(
child: new Text('Change color'),
onPressed: () {
setState(() {
isButtonPressed = !isButtonPressed;
});
},
),
],
),
Your Screen without button pressed:
Your Screen with button pressed:
You need to understand how setState works.
Lets assume you have a class named HomeScreen, within the homescreen you are overriding the build method to build your own widgets.
Widget build(BuildContext context){
return Column(
children:<Widget> [
FirstTextWidget();
SecondTextWidget();
ThirdTextWidget(),
])
}
when you call SetState function within that "homesceeen" class, the homescreen class itself calls the build method again and all of componenets you have returned within build function get re-rendered. Every text within homescreen class gets rerendered.
So whats the solution?
The Solution is separate your stateful widget with different class so that only those widgets gets rerendered when needed not whole. I will prefer you to use State Management plugin like Provider, bloc etc.

Flutter: How To Change/Refresh State From Another Widget

I am trying to have a global integer that is displayed in a widget and then is updated by something (a button click or something) from another widget. All of the other ways i have tried don't work. What is the best way to do this?
Stack overflow says i have too much code so more text more text more text
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ScoreDisplay(),
PointButton(),
],
),
),
),
),
);
}
int score = 0;
class ScoreDisplay extends StatefulWidget {
#override
_ScoreDisplayState createState() => _ScoreDisplayState();
}
class _ScoreDisplayState extends State<ScoreDisplay> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: Text(
'Score: $score',
),
),
);
}
}
class PointButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: RaisedButton(
//onPressed: //increment score,
),
),
);
}
}
You need to implement some kind of State Management for that.
Here are two basic ways to implement such a feature: with a StatefulWidget and with Riverpod.
1. With a StatefulWidget
I extracted your Scaffold as a StatefulWidget maintaining the score of your application.
I then use ScoreDisplay as a pure StatelessWidget receiving the score as a parameter. And your PointButton is also Stateless and call the ScorePage thanks to a simple VoidCallback function.
Full source code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: ScorePage(),
),
);
}
class ScorePage extends StatefulWidget {
const ScorePage({
Key key,
}) : super(key: key);
#override
_ScorePageState createState() => _ScorePageState();
}
class _ScorePageState extends State<ScorePage> {
int score = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ScoreDisplay(score: score),
PointButton(onIncrement: () => setState(() => score++)),
],
),
),
);
}
}
class ScoreDisplay extends StatelessWidget {
final int score;
const ScoreDisplay({Key key, this.score}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: Text(
'Score: $score',
),
),
);
}
}
class PointButton extends StatelessWidget {
final VoidCallback onIncrement;
const PointButton({Key key, this.onIncrement}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: ElevatedButton(
onPressed: () => onIncrement?.call(),
child: Text('CLICK ME'),
),
),
);
}
}
2. With Riverpod
Create a StateProvider:
final scoreProvider = StateProvider<int>((ref) => 0);
Watch the StateProvider:
final score = useProvider(scoreProvider).state;
Update the StateProvider
context.read(scoreProvider).state++
Full Source Code
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
void main() {
runApp(
ProviderScope(
child: MaterialApp(
home: Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ScoreDisplay(),
PointButton(),
],
),
),
),
),
),
);
}
int score = 0;
class ScoreDisplay extends HookWidget {
#override
Widget build(BuildContext context) {
final score = useProvider(scoreProvider).state;
return Center(
child: Container(
child: Text(
'Score: $score',
),
),
);
}
}
class PointButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: ElevatedButton(
onPressed: () => context.read(scoreProvider).state++,
child: Text('CLICK ME'),
),
),
);
}
}
final scoreProvider = StateProvider<int>((ref) => 0);
Check Riverpod Website for more info and more advanced use cases.
But you have many more flavors of State Management available.
The best example is to use "provider" package which can be found on www.pub.dev
It is very easy state management package that can help You solve this problem. Keep in my that provider instead of setState() uses notifyListener()

Simple Riverpod example beyond the counter app: sum of two cells

I'm learning Flutter and I'm stuck on state management. I took a look at Riverpod and it looks promising, but I have a hard time to go beyond the counter app to something more complicated.
For example, I want to have two TextFields that collect numbers, and another Text widget to display the sum of the two TextField values. Here's what I have.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
void main() {
runApp(ProviderScope(
child: MyApp(),
));
}
class MyApp extends HookWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Adding two cells'),
);
}
}
final cellProvider = StateProvider((_) => <int>[0, 0]);
class MyHomePage extends HookWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Consumer(builder: (context, watch, _) {
print(watch(cellProvider).state);
num _sum = watch(cellProvider).state[0] + watch(cellProvider).state[1];
return Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Cell(0),
Cell(1),
],
),
SizedBox(
height: 100,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Sum: ${_sum.toString()}'),
],
),
],
),
);
}),
);
}
}
class Cell extends HookWidget {
Cell(this.index);
final int index;
#override
Widget build(BuildContext context) {
return Container(
width: 150,
padding: EdgeInsets.all(30),
child: TextField(
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onChanged: (value) {
context.read(cellProvider).state[index] = num.tryParse(value);
},
),
);
}
}
The Text widget does not update. Any suggestion?
Thank you very much,
Tony
The provider only updates when the object it provides changes, just as a Stream returns a final value you need to update the whole object (List<int>) so the consumer updates properly, changing inner values of an iterable won't trigger an update
onChanged: (value) {
final List<int> myList = context.read(cellProvider).state;
myList[index] = num.tryParse(value);
context.read(cellProvider).state = myList; //update the state with a new list
},