Fundamentals - Widgets

The majority of people prefers symmetrical and simple displays so it seems worthwhile to try and find a way to construct a default template for defining the widgets. While testing, I have realized that there are 2 ways to construct a Widget and use as a wrapper for items.

The objective is to build a Widget, MyMenuBox that acts like a wrapper around Icon Buttons to display at the main page (page where the user enters the app). The Icon Buttons navigates the user to the corresponding pages.

Method 1: Widget as a StatelessWidget class

This constructs the Widget using OOP design.

class MyMenuBox extends StatelessWidget {
  final IconData iconData;
  final String label;
  final VoidCallback onPressed;
  final Color foregroundColor = Colors.white;
  final Color backgroundColor = Colors.transparent;

  const MyMenuBox({
    super.key,
    required this.iconData,
    required this.label,
    required this.onPressed,
  });

  @override
  Widget build(BuildContext context) {
    return TextButton.icon(
      style: TextButton.styleFrom(
        foregroundColor: foregroundColor, // Text color
        backgroundColor: backgroundColor, // Background color
        // padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 32.0),
        //shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
        //side: BorderSide(
        //  color: Colors.white.withOpacity(0.3),
        //), // Light border for glossy look
        elevation: 1,
      ),
      onPressed: onPressed,
      icon: Icon(iconData, size: 35, color: Colors.white),
      label: Text(label, style: TextStyle(color: Colors.white)),
    );
  }
}

Method 2: Method 1: Stateful Widget using StatelessWidget Class

This constructs the Widget as standalone.

// Standalone Widget version of the CoverTextButton 
Widget myMenuBox(IconData iconData, String label, VoidCallback onPressed) {
  return TextButton.icon(
    style: TextButton.styleFrom(
      foregroundColor: Colors.white, // Text color
      backgroundColor: Colors.white.withAlpha(1), // Background color
      // padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 32.0),
      //shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      //side: BorderSide(
      //  color: Colors.white.withOpacity(0.3),
      //), // Light border for glossy look
      elevation: 1,
    ),
    onPressed: onPressed,
    icon: Icon(iconData, size: 35, color: Colors.white),
    label: Text(label, style: TextStyle(color: Colors.white)),
  );
}

Comparison

The table below highlights the key differences in usage between the methods.

Case
Method 1
Method 2

Calling the Widget

CoverTextButton(
  iconData: Icons.insights,
  label: 'Begin Reading',
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => const HomePage()),
    );
  },    
myMenuBox(Icons.insights, 'Start Reading', () {
  _navigateTo(context, const HomePage());
}),

Another Example

// Implementing myTemplate where the CosmicBackground() is an animated background. This is useful when you want the animated background to stay across navigated pages. 

// MyTemplate as StatelessWidget 
class MyTemplate extends StatelessWidget {
  final Widget body;
  const MyTemplate({super.key, required this.body});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor:
          Colors.transparent, // Make Scaffold background transparent
      body: Stack(
        children: [
          const CosmicBackground(), // Cosmic background as default
          body,
        ],
      ),
    );
  }
}
// myTemplate as standalone function 
Widget myTemplate(body) {
  return Scaffold(
    backgroundColor: Colors.transparent,
    body: Stack(children: [const CosmicBackground(), body]),
  );
}

Summary

  • Method 1 (Class-Based Widget): Best for when your widget is part of a more structured and larger app, especially when you need state management, custom constructors, or default values. It’s ideal for complex, reusable widgets that may grow in functionality.

  • Method 2 (Function-Based Widget): Suitable for simpler, smaller widgets that don’t need complex logic or state management. It’s a great choice for quick, reusable UI elements that are not likely to change much.

Last updated