4

I am a Java developer and currently learning about Flutter/Dart. I am an adept of clean code with small functions and some widget examples just scare the s*** out of me.

I am trying to implement a Card widget with some transaction information (price, title and date). Currently the code looks like this:

class TransactionCard extends StatelessWidget {
  final Transaction _transaction;

  TransactionCard(this._transaction);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Card(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            _PriceContainer(_transaction.amount),
            _DetailContainer(_transaction.title, _transaction.date),
          ],
        ),
      ),
    );
  }
}

// Inner Widgets

class _PriceContainer extends Container {
  _PriceContainer(double amount)
      : super(
    margin: EdgeInsets.symmetric(
      vertical: 10,
      horizontal: 15,
    ),
    decoration: BoxDecoration(
      border: Border.all(
        color: Colors.purple,
        width: 2,
      ),
    ),
    padding: EdgeInsets.all(10),
    child: Text(
      amount.toString(),
      style: _amountTextStyle(),
    ),
  );
}

class _DetailContainer extends Container {
  _DetailContainer(String title, DateTime date)
      : super(
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text(
          title,
          style: _titleTextStyle(),
        ),
        Text(
          date.toString(),
          style: _dateTextStyle(),
        ),
      ],
    ),
  );
}

// Text styles

TextStyle _amountTextStyle() {
  return TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 20,
    color: Colors.purple,
  );
}

TextStyle _titleTextStyle() {
  return TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 18,
  );
}

TextStyle _dateTextStyle() {
  return TextStyle(color: Colors.grey);
}

I have used two approaches:

  1. For the inner widgets I extended Containers and gave then specific styling.
  2. For the text styles I created a function returning the desired style.

Is there an approach preferable to the other? A third one? Is there a bad practice to create multiple Widgets on the same file?

2
  • 1
    Both are bad. Extending widgets is an anti-pattern, use composition instead. As for function, see stackoverflow.com/questions/53234825/… Commented Nov 12, 2019 at 19:22
  • @RémiRousselet I agree for the first one, but I think you missed the point of the "function" question in relating to your problem. Commented Nov 12, 2019 at 19:33

1 Answer 1

2

Composition > inheritance

As mentioned in the comments and in the Flutter documentation, you should always compose widgets instead of inheriting from e.g. a Container.

In your case, this would look like this:

class _PriceContainer extends StatelessWidget {
  final double amount;

  const _PriceContainer({
    Key key,
    this.amount,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) => Container(
        margin: const EdgeInsets.symmetric(
          vertical: 10,
          horizontal: 15,
        ),
        decoration: BoxDecoration(
          border: Border.all(
            color: Colors.purple,
            width: 2,
          ),
        ),
        padding: EdgeInsets.all(10),
        child: Text(
          amount.toString(),
          style: _amountTextStyle,
        ),
      );
}

This is analogous for your other widgets.

Top-level functions

Declaring top-level functions is generally fine, however, in this case, you should really define a top-level property instead - preferably declare a const to take advantage of compile-time constants:

const _amountTextStyle = TextStyle(
  fontWeight: FontWeight.bold,
  fontSize: 20,
  color: Colors.purple,
);

You should be able to apply the same to your other text styles.

Sign up to request clarification or add additional context in comments.

1 Comment

How can I adjust the fontSize according to the screen size? Is this a bad practice and should I always use exact pixel?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.