tab_bar_theme.dart 6.33 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/foundation.dart';
6
import 'package:flutter/widgets.dart';
7

8 9
import 'ink_well.dart';
import 'material_state.dart';
10
import 'tabs.dart';
11
import 'theme.dart';
12 13 14 15 16 17 18

/// Defines a theme for [TabBar] widgets.
///
/// A tab bar theme describes the color of the tab label and the size/shape of
/// the [TabBar.indicator].
///
/// Descendant widgets obtain the current theme's [TabBarTheme] object using
19 20
/// `TabBarTheme.of(context)`. Instances of [TabBarTheme] can be customized with
/// [TabBarTheme.copyWith].
21 22 23 24 25 26
///
/// See also:
///
///  * [TabBar], a widget that displays a horizontal row of tabs.
///  * [ThemeData], which describes the overall theme information for the
///    application.
27
@immutable
28
class TabBarTheme with Diagnosticable {
29 30 31 32 33
  /// Creates a tab bar theme that can be used with [ThemeData.tabBarTheme].
  const TabBarTheme({
    this.indicator,
    this.indicatorSize,
    this.labelColor,
34
    this.labelPadding,
35
    this.labelStyle,
36
    this.unselectedLabelColor,
37
    this.unselectedLabelStyle,
38 39
    this.overlayColor,
    this.splashFactory,
40
    this.mouseCursor,
41 42 43
  });

  /// Default value for [TabBar.indicator].
44
  final Decoration? indicator;
45 46

  /// Default value for [TabBar.indicatorSize].
47
  final TabBarIndicatorSize? indicatorSize;
48 49

  /// Default value for [TabBar.labelColor].
50
  final Color? labelColor;
51

52
  /// Default value for [TabBar.labelPadding].
53 54 55 56
  ///
  /// If there are few tabs with both icon and text and few
  /// tabs with only icon or text, this padding is vertically
  /// adjusted to provide uniform padding to all tabs.
57
  final EdgeInsetsGeometry? labelPadding;
58

59
  /// Default value for [TabBar.labelStyle].
60
  final TextStyle? labelStyle;
61

62
  /// Default value for [TabBar.unselectedLabelColor].
63
  final Color? unselectedLabelColor;
64

65
  /// Default value for [TabBar.unselectedLabelStyle].
66
  final TextStyle? unselectedLabelStyle;
67

68 69 70 71 72 73
  /// Default value for [TabBar.overlayColor].
  final MaterialStateProperty<Color?>? overlayColor;

  /// Default value for [TabBar.splashFactory].
  final InteractiveInkFeatureFactory? splashFactory;

74 75 76 77 78
  /// {@macro flutter.material.tabs.mouseCursor}
  ///
  /// If specified, overrides the default value of [TabBar.mouseCursor].
  final MaterialStateProperty<MouseCursor?>? mouseCursor;

79 80 81
  /// Creates a copy of this object but with the given fields replaced with the
  /// new values.
  TabBarTheme copyWith({
82 83 84 85 86 87 88
    Decoration? indicator,
    TabBarIndicatorSize? indicatorSize,
    Color? labelColor,
    EdgeInsetsGeometry? labelPadding,
    TextStyle? labelStyle,
    Color? unselectedLabelColor,
    TextStyle? unselectedLabelStyle,
89 90
    MaterialStateProperty<Color?>? overlayColor,
    InteractiveInkFeatureFactory? splashFactory,
91
    MaterialStateProperty<MouseCursor?>? mouseCursor,
92 93
  }) {
    return TabBarTheme(
94 95 96
      indicator: indicator ?? this.indicator,
      indicatorSize: indicatorSize ?? this.indicatorSize,
      labelColor: labelColor ?? this.labelColor,
97
      labelPadding: labelPadding ?? this.labelPadding,
98 99 100
      labelStyle: labelStyle ?? this.labelStyle,
      unselectedLabelColor: unselectedLabelColor ?? this.unselectedLabelColor,
      unselectedLabelStyle: unselectedLabelStyle ?? this.unselectedLabelStyle,
101 102
      overlayColor: overlayColor ?? this.overlayColor,
      splashFactory: splashFactory ?? this.splashFactory,
103
      mouseCursor: mouseCursor ?? this.mouseCursor,
104 105 106
    );
  }

107 108
  /// The data from the closest [TabBarTheme] instance given the build context.
  static TabBarTheme of(BuildContext context) {
109
    return Theme.of(context).tabBarTheme;
110 111
  }

112 113
  /// Linearly interpolate between two tab bar themes.
  ///
114 115
  /// The arguments must not be null.
  ///
116
  /// {@macro dart.ui.shadow.lerp}
117 118 119 120 121 122 123 124
  static TabBarTheme lerp(TabBarTheme a, TabBarTheme b, double t) {
    assert(a != null);
    assert(b != null);
    assert(t != null);
    return TabBarTheme(
      indicator: Decoration.lerp(a.indicator, b.indicator, t),
      indicatorSize: t < 0.5 ? a.indicatorSize : b.indicatorSize,
      labelColor: Color.lerp(a.labelColor, b.labelColor, t),
125
      labelPadding: EdgeInsetsGeometry.lerp(a.labelPadding, b.labelPadding, t),
126 127 128
      labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
      unselectedLabelColor: Color.lerp(a.unselectedLabelColor, b.unselectedLabelColor, t),
      unselectedLabelStyle: TextStyle.lerp(a.unselectedLabelStyle, b.unselectedLabelStyle, t),
129 130
      overlayColor: _LerpColors(a.overlayColor, b.overlayColor, t),
      splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory,
131
      mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
132 133 134 135
    );
  }

  @override
136 137 138 139 140 141 142 143 144 145 146 147
  int get hashCode => Object.hash(
    indicator,
    indicatorSize,
    labelColor,
    labelPadding,
    labelStyle,
    unselectedLabelColor,
    unselectedLabelStyle,
    overlayColor,
    splashFactory,
    mouseCursor,
  );
148 149

  @override
150
  bool operator ==(Object other) {
151
    if (identical(this, other)) {
152
      return true;
153 154
    }
    if (other.runtimeType != runtimeType) {
155
      return false;
156
    }
157 158 159 160 161 162 163
    return other is TabBarTheme
        && other.indicator == indicator
        && other.indicatorSize == indicatorSize
        && other.labelColor == labelColor
        && other.labelPadding == labelPadding
        && other.labelStyle == labelStyle
        && other.unselectedLabelColor == unselectedLabelColor
164 165
        && other.unselectedLabelStyle == unselectedLabelStyle
        && other.overlayColor == overlayColor
166 167
        && other.splashFactory == splashFactory
        && other.mouseCursor == mouseCursor;
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
  }
}


@immutable
class _LerpColors implements MaterialStateProperty<Color?> {
  const _LerpColors(this.a, this.b, this.t);

  final MaterialStateProperty<Color?>? a;
  final MaterialStateProperty<Color?>? b;
  final double t;

  @override
  Color? resolve(Set<MaterialState> states) {
    final Color? resolvedA = a?.resolve(states);
    final Color? resolvedB = b?.resolve(states);
    return Color.lerp(resolvedA, resolvedB, t);
  }

  @override
  int get hashCode {
189
    return Object.hash(a, b, t);
190 191 192 193
  }

  @override
  bool operator ==(Object other) {
194
    if (identical(this, other)) {
195
      return true;
196 197
    }
    if (other.runtimeType != runtimeType) {
198
      return false;
199
    }
200 201 202 203
    return other is _LerpColors
      && other.a == a
      && other.b == b
      && other.t == t;
204 205
  }
}