Commit 1adfbd4e authored by Luke's avatar Luke Committed by Ian Hickson

Adds highlight + splash color properties to material button (#8643)

* adds highlight + splash color properties to material button

* add states to raised button + flat button

* fixes an issue where the custom highlight would not be properly set

* Add preliminary tests for theme highlight + splash and via theme

* documentation changes. tweaks per code review feedback

* comment out unused variable

* remove unused import

* documentation updates. removed commented code
parent 32d09a3a
......@@ -130,6 +130,8 @@ class MaterialButton extends StatefulWidget {
this.textTheme,
this.textColor,
this.color,
this.highlightColor,
this.splashColor,
this.elevation,
this.highlightElevation,
this.minWidth,
......@@ -152,9 +154,40 @@ class MaterialButton extends StatefulWidget {
/// The color to use for this button's text.
final Color textColor;
/// The color of the button, as printed on the [Material].
/// The primary color of the button, as printed on the [Material], while it
/// is in its default (unpressed, enabled) state.
///
/// Defaults to null, meaning that the color is automatically derived from the [Theme].
///
/// Typically, a material design color will be used, as follows:
///
/// ```dart
/// new MaterialButton(
/// color: Colors.blue[500],
/// onPressed: _handleTap,
/// child: new Text('DEMO'),
/// ),
/// ```
final Color color;
/// The primary color of the button when the button is in the down (pressed) state.
/// The splash is represented as a circular overlay that appears above the
/// [highlightColor] overlay. The splash overlay has a center point that matches
/// the hit point of the user touch event. The splash overlay will expand to
/// fill the button area if the touch is held for long enough time. If the splash
/// color has transparency then the highlight and button color will show through.
///
/// Defaults to the splash color from the [Theme].
final Color splashColor;
/// The secondary color of the button when the button is in the down (pressed)
/// state. The higlight color is represented as a solid color that is overlaid over the
/// button color (if any). If the highlight color has transparency, the button color
/// will show through. The highlight fades in quickly as the button is held down.
///
/// Defaults to the highlight color from the [Theme].
final Color highlightColor;
/// The z-coordinate at which to place this button.
///
/// The following elevations have defined shadows: 1, 2, 3, 4, 6, 8, 9, 12, 16, 24
......@@ -250,8 +283,9 @@ class _MaterialButtonState extends State<MaterialButton> {
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final ThemeData theme = Theme.of(context);
final Color textColor = _textColor;
final TextStyle style = Theme.of(context).textTheme.button.copyWith(color: textColor);
final TextStyle style = theme.textTheme.button.copyWith(color: textColor);
final ButtonTheme buttonTheme = ButtonTheme.of(context);
final double height = config.height ?? buttonTheme.height;
final int elevation = (_highlight ? config.highlightElevation : config.elevation) ?? 0;
......@@ -261,6 +295,8 @@ class _MaterialButtonState extends State<MaterialButton> {
color: textColor
),
child: new InkWell(
highlightColor: config.highlightColor ?? theme.highlightColor,
splashColor: config.splashColor ?? theme.splashColor,
onTap: config.onPressed,
onHighlightChanged: _handleHighlightChanged,
child: new Container(
......
......@@ -53,6 +53,8 @@ class FlatButton extends StatelessWidget {
this.textColor,
this.disabledTextColor,
this.color,
this.highlightColor,
this.splashColor,
this.disabledColor,
this.textTheme,
this.colorBrightness,
......@@ -76,8 +78,10 @@ class FlatButton extends StatelessWidget {
/// Defaults to a color derived from the [Theme].
final Color disabledTextColor;
/// The color of the button, as printed on the [Material]. Defaults to null,
/// meaning that the color is automatically derived from the [Theme].
/// The primary color of the button, as printed on the [Material], while it
/// is in its default (unpressed, enabled) state.
///
/// Defaults to null, meaning that the color is automatically derived from the [Theme].
///
/// Typically, a material design color will be used, as follows:
///
......@@ -90,6 +94,24 @@ class FlatButton extends StatelessWidget {
/// ```
final Color color;
/// The primary color of the button when the button is in the down (pressed) state.
/// The splash is represented as a circular overlay that appears above the
/// [highlightColor] overlay. The splash overlay has a center point that matches
/// the hit point of the user touch event. The splash overlay will expand to
/// fill the button area if the touch is held for long enough time. If the splash
/// color has transparency then the highlight and button color will show through.
///
/// Defaults to the splash color from the [Theme].
final Color splashColor;
/// The secondary color of the button when the button is in the down (pressed)
/// state. The higlight color is represented as a solid color that is overlaid over the
/// button color (if any). If the highlight color has transparency, the button color
/// will show through. The highlight fades in quickly as the button is held down.
///
/// Defaults to the highlight color from the [Theme].
final Color highlightColor;
/// The color of the button when the button is disabled. Buttons are disabled
/// by default. To enable a button, set its [onPressed] property to a non-null
/// value.
......@@ -120,6 +142,8 @@ class FlatButton extends StatelessWidget {
onPressed: onPressed,
textColor: enabled ? textColor : disabledTextColor,
color: enabled ? color : disabledColor,
highlightColor: highlightColor ?? Theme.of(context).highlightColor,
splashColor: splashColor ?? Theme.of(context).splashColor,
textTheme: textTheme,
colorBrightness: colorBrightness,
child: child
......
......@@ -107,7 +107,6 @@ class InkSplash extends InkFeature {
}
final Point _position;
final Color _color;
final double _targetRadius;
final RectCallback _clipCallback;
final bool _repositionToReferenceBox;
......@@ -118,6 +117,17 @@ class InkSplash extends InkFeature {
Animation<int> _alpha;
AnimationController _alphaController;
/// The color of the splash.
Color get color => _color;
Color _color;
set color(Color value) {
if (value == _color)
return;
_color = value;
controller.markNeedsPaint();
}
/// The user input is confirmed.
///
/// Causes the reaction to propagate faster across the material.
......
......@@ -218,7 +218,9 @@ class _InkResponseState<T extends InkResponse> extends State<T> {
@override
Widget build(BuildContext context) {
assert(config.debugCheckContext(context));
_lastHighlight?.color = Theme.of(context).highlightColor;
final ThemeData themeData = Theme.of(context);
_lastHighlight?.color = config.highlightColor ?? themeData.highlightColor;
_currentSplash?.color = config.splashColor ?? themeData.splashColor;
final bool enabled = config.onTap != null || config.onDoubleTap != null || config.onLongPress != null;
return new GestureDetector(
onTapDown: enabled ? _handleTapDown : null,
......
......@@ -40,6 +40,8 @@ class RaisedButton extends StatelessWidget {
Key key,
@required this.onPressed,
this.color,
this.highlightColor,
this.splashColor,
this.disabledColor,
this.elevation: 2,
this.highlightElevation: 8,
......@@ -53,8 +55,12 @@ class RaisedButton extends StatelessWidget {
/// If this is set to null, the button will be disabled.
final VoidCallback onPressed;
/// The color of the button, as printed on the [Material]. Defaults to null,
/// meaning that the color is automatically derived from the [Theme].
/// The primary color of the button, as printed on the [Material], while it
/// is in its default (unpressed, enabled) state.
///
/// Defaults to null, meaning that the color is automatically derived from the [Theme].
///
/// Typically, a material design color will be used, as follows:
///
/// ```dart
/// new RaisedButton(
......@@ -65,6 +71,25 @@ class RaisedButton extends StatelessWidget {
/// ```
final Color color;
/// The primary color of the button when the button is in the down (pressed) state.
/// The splash is represented as a circular overlay that appears above the
/// [highlightColor] overlay. The splash overlay has a center point that matches
/// the hit point of the user touch event. The splash overlay will expand to
/// fill the button area if the touch is held for long enough time. If the splash
/// color has transparency then the highlight and button color will show through.
///
/// Defaults to the splash color from the [Theme].
final Color splashColor;
/// The secondary color of the button when the button is in the down (pressed)
/// state. The higlight color is represented as a solid color that is overlaid over the
/// button color (if any). If the highlight color has transparency, the button color
/// will show through. The highlight fades in quickly as the button is held down.
///
/// Defaults to the highlight color from the [Theme].
final Color highlightColor;
/// The color of the button when the button is disabled. Buttons are disabled
/// by default. To enable a button, set its [onPressed] property to a non-null
/// value.
......@@ -129,6 +154,8 @@ class RaisedButton extends StatelessWidget {
return new MaterialButton(
onPressed: onPressed,
color: _getColor(context),
highlightColor: highlightColor ?? Theme.of(context).highlightColor,
splashColor: splashColor ?? Theme.of(context).splashColor,
elevation: enabled ? elevation : disabledElevation,
highlightElevation: enabled ? highlightElevation : disabledElevation,
colorBrightness: colorBrightness,
......
......@@ -40,4 +40,103 @@ void main() {
semantics.dispose();
});
Widget _buttonWidget({
Key buttonKey,
Key materialKey,
Color color, Color
highlightColor,
Color splashColor,
double minWidth = 150.0,
double height = 60.0,
bool useTheme = false
}) {
final Key definedMaterialKey = materialKey ?? new UniqueKey();
final Key definedButtonKey = buttonKey ?? new UniqueKey();
Widget buttonWidget = new Material(
key: definedMaterialKey,
child: new Center(
child: new MaterialButton(
key: definedButtonKey,
color: color,
highlightColor: !useTheme ? highlightColor : null,
splashColor: !useTheme ? splashColor : null,
minWidth: minWidth,
height: height,
onPressed: () { },
),
),
);
if (useTheme) {
final ThemeData themeData = new ThemeData(
accentColor: color,
highlightColor: highlightColor,
splashColor: splashColor,
);
buttonWidget = new Theme(
data: themeData,
child: buttonWidget,
);
}
return buttonWidget;
}
testWidgets('Does button highlight + splash colors work if set directly', (WidgetTester tester) async {
final Color buttonColor = new Color(0xFFFFFF00);
final Color highlightColor = new Color(0xDD0000FF);
final Color splashColor = new Color(0xAA0000FF);
final Key materialKey = new UniqueKey();
final Key buttonKey = new UniqueKey();
await tester.pumpWidget(
_buttonWidget(
materialKey: materialKey,
buttonKey: buttonKey,
color: buttonColor,
highlightColor: highlightColor,
splashColor: splashColor,
),
);
final Point center = tester.getCenter(find.byKey(buttonKey));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(new Duration(milliseconds: 200));
// TODO(ianh) - the object returned by renderObject does not contain splash or highlights (??)
await gesture.up();
});
testWidgets('Does button highlight color work if set via theme', (WidgetTester tester) async {
final Color buttonColor = new Color(0xFFFFFF00);
final Color highlightColor = new Color(0xDD0000FF);
final Color splashColor = new Color(0xAA0000FF);
final Key materialKey = new UniqueKey();
final Key buttonKey = new UniqueKey();
await tester.pumpWidget(
_buttonWidget(
useTheme: true, // use a theme wrapper
materialKey: materialKey,
buttonKey: buttonKey,
color: buttonColor,
highlightColor: highlightColor,
splashColor: splashColor,
),
);
final Point center = tester.getCenter(find.byKey(buttonKey));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(new Duration(milliseconds: 200));
// TODO(ianh) - the object returned by renderObject does not contain splash or highlights (??)
await gesture.up();
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment