DEV Community

Cover image for Extend your Flutter code
Paurakh Sharma Humagain
Paurakh Sharma Humagain

Posted on • Edited on

Extend your Flutter code

Extend your Flutter code

Are you looking for an alternative to the nested widget structure of Flutter? Extracting the complex widgets into a different widget, can be a good solution. There is another solution, or even both solutions can work together.

For this, we can leverage the power of Dart feature called Extension which was introduced in Dart 2.7.

So, what is extension in Dart?

An extension is a way of adding additional functionality to your dart data types.

Let's take the String data type as an example.


String myString = 'Hello world!'

// here toUpperCase() is a method which can
// be applied to a String data type.
print(myString.toUpperCase())

Likewise, we can add our own methods to the data type.

We can create an extension for a datatype using the syntax:

extension StringExtend on String {
    // define methods here
}

And inside this, we can define the methods.


extension StringExtend on String {
  count(String a) {
    int count = 0;
    for (int i = 0; i < this.length; i++) {
      if (this[i] == a) count = count + 1;
    }
    return count;
  }
}

Note: the variable in which the extension method is called can be accessed inside the method using this keyword

Here we have defined a simple method count() which takes a String as a parameter and returns the number occurrence of this string in the called String.

The whole code would look like this:


extension StringExtend on String {
  count(String a) {
    int count = 0;
    for (int i = 0; i < this.length; i++) {
      if (this[i] == a) count = count + 1;
    }
    return count;
  }
}

void main() {
  String myText = 'This is my string';

  // prints 3 in the console
  print(myText.count('i'));
}

Similarly, we can add other methods to the extension.

extension StringExtend on String {
  count(String a) {
    int count = 0;
    for (int i = 0; i < this.length; i++) {
      if (this[i] == a) count = count + 1;
    }
    return count;
  }

  makeFunky() {
    String result = '';
    for (int i = 0; i < this.length; i++) {
      final text = i % 2 == 0 ? this[i].toLowerCase() : this[i].toUpperCase();
      result = result + text;
    }
    return result;
  }
}

void main() {
  String myText = 'This is my string';

  // prints 3 in the console
  print(myText.count('i'));
  // prints iHiS Is mY StTiNg
  print(myText.makeFunky());
}

Now we have a good understanding of the syntax of extension let's see how we can implement this in FLutter.

Since, everything is Widget in flutter. We can add extension to the Widget datatype. Or even an specific Widget such as Text() or Container().

Let's create a flutter extension that changes the font size of a Text() widget.

Without extension the code would look something like this:

build() {
    return Text(
       'Hello world!',
       style: TextStyle(
         fontSize: 24,
        ),
    );
}

With extension

// first define the extension
extension TextModifier on Text {
  Text fontSize(double fontSize) {
    // if the Text() widget doesn't already have an style
    // just apply the fontSize
    if (this.style == null) {
      return Text(
        this.data,
        style: TextStyle(fontSize: fontSize),
      );
    }

    // if there is already an style applied to it
    // extend that style with fontSize
    return Text(
      this.data,
      style: this.style.copyWith(fontSize: fontSize),
    );
  }
}


// actual code implementation

build() {
    return Text('Hello World!').fontSize(24);
}

SEE how readable your code looks like?
Yes there is more boilerplate to define the extension, but that is something you have to do only once and only use it's fruits latter on while using the Text() widget.

Similarly, we can add methods to the extension to chain the methods.

// define extension

extension TextModifier on Text {
  Text color(Color color) {
    if (this.style == null) {
      return Text(
        this.data,
        style: TextStyle(color: color),
      );
    }
    return Text(
      this.data,
      style: this.style.copyWith(color: color),
    );
  }

  Text fontSize(double fontSize) {
    if (this.style == null) {
      return Text(
        this.data,
        style: TextStyle(fontSize: fontSize),
      );
    }

    return Text(
      this.data,
      style: this.style.copyWith(fontSize: fontSize),
    );
  }
}

// use the goodness
build() {
    return Text('Hello World!')
    .fontSize(24)
    .color(Colors.green);
}

SEE how readable the code looks like.

Let's see more examples

Define the extension

extension TextModifier on Text {
  Text color(Color color) {
    if (this.style == null) {
      return Text(
        this.data,
        style: TextStyle(color: color),
      );
    }
    return Text(
      this.data,
      style: this.style.copyWith(color: color),
    );
  }

  Text fontSize(double fontSize) {
    if (this.style == null) {
      return Text(
        this.data,
        style: TextStyle(fontSize: fontSize),
      );
    }

    return Text(
      this.data,
      style: this.style.copyWith(fontSize: fontSize),
    );
  }
}

extension WidgetModifier on Widget {
  Widget padding({horizontal, vertical}) {
    return Padding(
      padding: EdgeInsets.symmetric(
        horizontal: horizontal,
        vertical: vertical,
      ),
      child: this,
    );
  }

  Widget background(Color color) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: color,
      ),
      child: this,
    );
  }
}

Without extension

build(BuildContext context) {
    return Container(
      color: Colors.purple,
      padding: const EdgeInsets.symmetric(
        horizontal: 10,
        vertical: 20,
      ),
      child: Container(
        color: Colors.lightBlue,
        child: Text(
          'Hello, World!',
          style: TextStyle(
              color: Colors.purple,
              fontSize: 50.0,
            ),
        ),
      ),
    );
  }

With extension

build(BuildContext context) {
    return Text('Hello, World!')
        .color(Colors.purple)
        .fontSize(50.0)
        .background(Colors.lightBlue)
        .padding(horizontal: 10, vertical: 20)
        .background(Colors.purple)
  }

Conclusion

The example app using things taught in this blog can be found at Github

Dart extension can be used in flutter to decrease the boilerplate code for repeating simple widgets. If the widget is more complex it is better to extract it into a separate widget.

I would love to hear your thoughts on using extensions on Flutter code. If you like this you might love an awesome UI framework VelocityX by The Pawan Kumar

Please let me know what you want me to cover next, in the mean time follow me on Twitter

Happy Coding

Top comments (3)

Collapse
 
anzannepal profile image
Anjan Nepal

I love you 💗💛😂

Collapse
 
paurakhsharma profile image
Paurakh Sharma Humagain

Love you 3000 😂

Collapse
 
rajiv24joshi profile image
rajiv24joshi

I love You ♥