skip to Main Content

I want to create a design system for my new app.

Standard elevated button

      child: ElevatedButton.icon(               
            icon: Icon(Icons.power_settings_new),
            onPressed: () => context.go('/login'),
            label: const Text('Log out'),
          ),

It’s ok but in this scenario it should have a red color accent. This goal is easily achievable by use of foregroundColor property. By use of this technique there is no need to worry about icon’s color, text’s color, ripple effect color.

enter image description here

      child: ElevatedButton.icon(
            style: ElevatedButton.styleFrom(
              foregroundColor: Colors.red,
            ),
            icon: Icon(Icons.power_settings_new),
            onPressed: () => context.go('/login'),
            label: const Text('Log out'),
          ),

However I don’t want to specify this color every time. I’d prefer to make something like this and I’d like to avoid writing anny wrappers for buttons.

      child: ElevatedButton.error( // Color accent is red
                    icon: Icon(Icons.power_settings_new),
                    onPressed: () => context.go('/login'),
                    label: const Text('Log out'),
                  ),

Question 1: Is it event possible?

Question 2: How icon, text and ripple effects know that they need use a foreground color to render themselves?

3

Answers


  1. I would look into Extensions (https://dart.dev/guides/language/extension-methods)

    @override
    Widget build(BuildContext context) {
      return ElevatedButton.icon(
        icon: const Icon(Icons.power_settings_new),
        label: const Text('Log out'),
        onPressed: () {},
      ).error();
    }
    
    extension ExtendedElevatedButton on ElevatedButton {
      ElevatedButton error() {
        return ElevatedButton(
          style: ElevatedButton.styleFrom(
            foregroundColor: Colors.red,
          ),
          onPressed: onPressed,
          child: child,
        );
      }
    }
    
    Login or Signup to reply.
  2. Wrap a widget with Theme:

    extension ThemeModifiers on Widget {
      Widget theme(ThemeData data) {
        return Theme(data: data, child: this);
      }
    }
    
    ElevatedButton.icon(
      icon: const Icon(Icons.power_settings_new),
      onPressed: () {},
      label: const Text('Log out'),
    ).theme(
      Theme.of(context).copyWith(
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
              foregroundColor: Colors.red,
          ),
        ),
      ),
    )
    

    Then go for a more specific style as needed:

    extension ElevatedButtoneModifier on ElevatedButton {
      Widget error(BuildContext context) {
        return theme(
          Theme.of(context).copyWith(
            elevatedButtonTheme: ElevatedButtonThemeData(
              style: ElevatedButton.styleFrom(
                foregroundColor: Colors.red,
              ),
            ),
          ),
        );
      }
    }
    
    ElevatedButton.icon(
      icon: const Icon(Icons.power_settings_new),
      onPressed: () {},
      label: const Text('Log out'),
    ).error(context)
    
    
    Login or Signup to reply.
  3. Extension without parameter

    You can define every instance for error, success, by just changing the color.

    extension ExtendedElevatedButton on ElevatedButton {
      ElevatedButton error() {
        return ElevatedButton(
          style: ElevatedButton.styleFrom(
            foregroundColor: Colors.red,
          ),
          onPressed: onPressed,
          child: child,
        );
      }
    }
    

    And use it as

    ElevatedButton(
       onPressed: () => context.go('/login'),
       child: const Text('Log out'),
    ).error(),
    

    Extension with parameter

    You can make it more generic by using the parameter and pass in the required color

    extension ExtendedElevatedButton on ElevatedButton {
      ElevatedButton addColor(Color color) {
        return ElevatedButton(
          style: ElevatedButton.styleFrom(
            foregroundColor: color,
          ),
          onPressed: onPressed,
          child: child,
        );
      }
    }
    

    And use it as

    ElevatedButton(
       onPressed: () => context.go('/login'),
       child: const Text('Log out'),
    ).addColor(Colors.red),
    

    Extra: if you further want to use the extension with all parameters you should define every desired extension with the preferred name.

    extension ExtendedElevatedButton on ElevatedButton {
      ElevatedButton error(Function<void> onPressed,Widget child) {
        return ElevatedButton(
          style: ElevatedButton.styleFrom(
            foregroundColor: Colors.red,
          ),
          onPressed: onPressed,
          child: child,
        );
      }
      ElevatedButton success(Function<void> onPressed,Widget child) {
        return ElevatedButton(
          style: ElevatedButton.styleFrom(
            foregroundColor: Colors.green,
          ),
          onPressed: onPressed,
          child: child,
        );
      }
    }
    

    And use it as

    ElevatedButton.error(
       onPressed: () => context.go('/login'),
       child: const Text('Log out'),
    );
    
    ElevatedButton.success(
       onPressed: () => context.go('/login'),
       child: const Text('Log out'),
    );
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search