Dhairya Lakhera
Dhairya Lakhera

Reputation: 4808

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'),
            )
          ],
        ));
  }
}

Upvotes: 0

Views: 1979

Answers (5)

Tejaswini Dev
Tejaswini Dev

Reputation: 1469

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'),
            )
          ],
        ));
  }
}

Upvotes: 2

Rintu Banerjee
Rintu Banerjee

Reputation: 124

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.

Upvotes: 0

Ravindra S. Patil
Ravindra S. Patil

Reputation: 14775

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: enter image description here

Your Screen with button pressed:enter image description here

Upvotes: 0

Ranjit Shrestha
Ranjit Shrestha

Reputation: 762

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.

Upvotes: 0

Karan Mehta
Karan Mehta

Reputation: 1541

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'),
            )
          ],
        ));
  }
}

Upvotes: 0

Related Questions