[Solved] flutter build only a single widget

Question

Asked by Curious on December 30, 2021 (source).

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

Answer

Question answered by Tejaswini D (source).

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

FLUTTER
SHARE: