1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | /// @docImport 'search_anchor.dart'; |
6 | library; |
7 | |
8 | import 'dart:ui' show lerpDouble; |
9 | |
10 | import 'package:flutter/foundation.dart'; |
11 | import 'package:flutter/rendering.dart'; |
12 | import 'package:flutter/services.dart'; |
13 | import 'package:flutter/widgets.dart'; |
14 | |
15 | import 'material_state.dart'; |
16 | import 'theme.dart'; |
17 | |
18 | // Examples can assume: |
19 | // late BuildContext context; |
20 | |
21 | /// Defines default property values for descendant [SearchBar] widgets. |
22 | /// |
23 | /// Descendant widgets obtain the current [SearchBarThemeData] object using |
24 | /// `SearchBarTheme.of(context)`. Instances of [SearchBarThemeData] can be customized |
25 | /// with [SearchBarThemeData.copyWith]. |
26 | /// |
27 | /// Typically a [SearchBarThemeData] is specified as part of the overall [Theme] |
28 | /// with [ThemeData.searchBarTheme]. |
29 | /// |
30 | /// All [SearchBarThemeData] properties are `null` by default. When null, the |
31 | /// [SearchBar] will use the values from [ThemeData] if they exist, otherwise it |
32 | /// will provide its own defaults based on the overall [Theme]'s colorScheme. |
33 | /// See the individual [SearchBar] properties for details. |
34 | /// |
35 | /// See also: |
36 | /// |
37 | /// * [ThemeData], which describes the overall theme information for the |
38 | /// application. |
39 | @immutable |
40 | class SearchBarThemeData with Diagnosticable { |
41 | /// Creates a theme that can be used for [ThemeData.searchBarTheme]. |
42 | const SearchBarThemeData({ |
43 | this.elevation, |
44 | this.backgroundColor, |
45 | this.shadowColor, |
46 | this.surfaceTintColor, |
47 | this.overlayColor, |
48 | this.side, |
49 | this.shape, |
50 | this.padding, |
51 | this.textStyle, |
52 | this.hintStyle, |
53 | this.constraints, |
54 | this.textCapitalization, |
55 | }); |
56 | |
57 | /// Overrides the default value of the [SearchBar.elevation]. |
58 | final MaterialStateProperty<double?>? elevation; |
59 | |
60 | /// Overrides the default value of the [SearchBar.backgroundColor]. |
61 | final MaterialStateProperty<Color?>? backgroundColor; |
62 | |
63 | /// Overrides the default value of the [SearchBar.shadowColor]. |
64 | final MaterialStateProperty<Color?>? shadowColor; |
65 | |
66 | /// Overrides the default value of the [SearchBar.surfaceTintColor]. |
67 | final MaterialStateProperty<Color?>? surfaceTintColor; |
68 | |
69 | /// Overrides the default value of the [SearchBar.overlayColor]. |
70 | final MaterialStateProperty<Color?>? overlayColor; |
71 | |
72 | /// Overrides the default value of the [SearchBar.side]. |
73 | final MaterialStateProperty<BorderSide?>? side; |
74 | |
75 | /// Overrides the default value of the [SearchBar.shape]. |
76 | final MaterialStateProperty<OutlinedBorder?>? shape; |
77 | |
78 | /// Overrides the default value for [SearchBar.padding]. |
79 | final MaterialStateProperty<EdgeInsetsGeometry?>? padding; |
80 | |
81 | /// Overrides the default value for [SearchBar.textStyle]. |
82 | final MaterialStateProperty<TextStyle?>? textStyle; |
83 | |
84 | /// Overrides the default value for [SearchBar.hintStyle]. |
85 | final MaterialStateProperty<TextStyle?>? hintStyle; |
86 | |
87 | /// Overrides the value of size constraints for [SearchBar]. |
88 | final BoxConstraints? constraints; |
89 | |
90 | /// Overrides the value of [SearchBar.textCapitalization]. |
91 | final TextCapitalization? textCapitalization; |
92 | |
93 | /// Creates a copy of this object but with the given fields replaced with the |
94 | /// new values. |
95 | SearchBarThemeData copyWith({ |
96 | MaterialStateProperty<double?>? elevation, |
97 | MaterialStateProperty<Color?>? backgroundColor, |
98 | MaterialStateProperty<Color?>? shadowColor, |
99 | MaterialStateProperty<Color?>? surfaceTintColor, |
100 | MaterialStateProperty<Color?>? overlayColor, |
101 | MaterialStateProperty<BorderSide?>? side, |
102 | MaterialStateProperty<OutlinedBorder?>? shape, |
103 | MaterialStateProperty<EdgeInsetsGeometry?>? padding, |
104 | MaterialStateProperty<TextStyle?>? textStyle, |
105 | MaterialStateProperty<TextStyle?>? hintStyle, |
106 | BoxConstraints? constraints, |
107 | TextCapitalization? textCapitalization, |
108 | }) { |
109 | return SearchBarThemeData( |
110 | elevation: elevation ?? this.elevation, |
111 | backgroundColor: backgroundColor ?? this.backgroundColor, |
112 | shadowColor: shadowColor ?? this.shadowColor, |
113 | surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, |
114 | overlayColor: overlayColor ?? this.overlayColor, |
115 | side: side ?? this.side, |
116 | shape: shape ?? this.shape, |
117 | padding: padding ?? this.padding, |
118 | textStyle: textStyle ?? this.textStyle, |
119 | hintStyle: hintStyle ?? this.hintStyle, |
120 | constraints: constraints ?? this.constraints, |
121 | textCapitalization: textCapitalization ?? this.textCapitalization, |
122 | ); |
123 | } |
124 | |
125 | /// Linearly interpolate between two [SearchBarThemeData]s. |
126 | /// |
127 | /// {@macro dart.ui.shadow.lerp} |
128 | static SearchBarThemeData? lerp(SearchBarThemeData? a, SearchBarThemeData? b, double t) { |
129 | if (identical(a, b)) { |
130 | return a; |
131 | } |
132 | return SearchBarThemeData( |
133 | elevation: MaterialStateProperty.lerp<double?>(a?.elevation, b?.elevation, t, lerpDouble), |
134 | backgroundColor: MaterialStateProperty.lerp<Color?>( |
135 | a?.backgroundColor, |
136 | b?.backgroundColor, |
137 | t, |
138 | Color.lerp, |
139 | ), |
140 | shadowColor: MaterialStateProperty.lerp<Color?>( |
141 | a?.shadowColor, |
142 | b?.shadowColor, |
143 | t, |
144 | Color.lerp, |
145 | ), |
146 | surfaceTintColor: MaterialStateProperty.lerp<Color?>( |
147 | a?.surfaceTintColor, |
148 | b?.surfaceTintColor, |
149 | t, |
150 | Color.lerp, |
151 | ), |
152 | overlayColor: MaterialStateProperty.lerp<Color?>( |
153 | a?.overlayColor, |
154 | b?.overlayColor, |
155 | t, |
156 | Color.lerp, |
157 | ), |
158 | side: _lerpSides(a?.side, b?.side, t), |
159 | shape: MaterialStateProperty.lerp<OutlinedBorder?>( |
160 | a?.shape, |
161 | b?.shape, |
162 | t, |
163 | OutlinedBorder.lerp, |
164 | ), |
165 | padding: MaterialStateProperty.lerp<EdgeInsetsGeometry?>( |
166 | a?.padding, |
167 | b?.padding, |
168 | t, |
169 | EdgeInsetsGeometry.lerp, |
170 | ), |
171 | textStyle: MaterialStateProperty.lerp<TextStyle?>( |
172 | a?.textStyle, |
173 | b?.textStyle, |
174 | t, |
175 | TextStyle.lerp, |
176 | ), |
177 | hintStyle: MaterialStateProperty.lerp<TextStyle?>( |
178 | a?.hintStyle, |
179 | b?.hintStyle, |
180 | t, |
181 | TextStyle.lerp, |
182 | ), |
183 | constraints: BoxConstraints.lerp(a?.constraints, b?.constraints, t), |
184 | textCapitalization: t < 0.5 ? a?.textCapitalization : b?.textCapitalization, |
185 | ); |
186 | } |
187 | |
188 | @override |
189 | int get hashCode => Object.hash( |
190 | elevation, |
191 | backgroundColor, |
192 | shadowColor, |
193 | surfaceTintColor, |
194 | overlayColor, |
195 | side, |
196 | shape, |
197 | padding, |
198 | textStyle, |
199 | hintStyle, |
200 | constraints, |
201 | textCapitalization, |
202 | ); |
203 | |
204 | @override |
205 | bool operator ==(Object other) { |
206 | if (identical(this, other)) { |
207 | return true; |
208 | } |
209 | if (other.runtimeType != runtimeType) { |
210 | return false; |
211 | } |
212 | return other is SearchBarThemeData && |
213 | other.elevation == elevation && |
214 | other.backgroundColor == backgroundColor && |
215 | other.shadowColor == shadowColor && |
216 | other.surfaceTintColor == surfaceTintColor && |
217 | other.overlayColor == overlayColor && |
218 | other.side == side && |
219 | other.shape == shape && |
220 | other.padding == padding && |
221 | other.textStyle == textStyle && |
222 | other.hintStyle == hintStyle && |
223 | other.constraints == constraints && |
224 | other.textCapitalization == textCapitalization; |
225 | } |
226 | |
227 | @override |
228 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
229 | super.debugFillProperties(properties); |
230 | properties.add( |
231 | DiagnosticsProperty<MaterialStateProperty<double?>>( |
232 | 'elevation' , |
233 | elevation, |
234 | defaultValue: null, |
235 | ), |
236 | ); |
237 | properties.add( |
238 | DiagnosticsProperty<MaterialStateProperty<Color?>>( |
239 | 'backgroundColor' , |
240 | backgroundColor, |
241 | defaultValue: null, |
242 | ), |
243 | ); |
244 | properties.add( |
245 | DiagnosticsProperty<MaterialStateProperty<Color?>>( |
246 | 'shadowColor' , |
247 | shadowColor, |
248 | defaultValue: null, |
249 | ), |
250 | ); |
251 | properties.add( |
252 | DiagnosticsProperty<MaterialStateProperty<Color?>>( |
253 | 'surfaceTintColor' , |
254 | surfaceTintColor, |
255 | defaultValue: null, |
256 | ), |
257 | ); |
258 | properties.add( |
259 | DiagnosticsProperty<MaterialStateProperty<Color?>>( |
260 | 'overlayColor' , |
261 | overlayColor, |
262 | defaultValue: null, |
263 | ), |
264 | ); |
265 | properties.add( |
266 | DiagnosticsProperty<MaterialStateProperty<BorderSide?>>('side' , side, defaultValue: null), |
267 | ); |
268 | properties.add( |
269 | DiagnosticsProperty<MaterialStateProperty<OutlinedBorder?>>( |
270 | 'shape' , |
271 | shape, |
272 | defaultValue: null, |
273 | ), |
274 | ); |
275 | properties.add( |
276 | DiagnosticsProperty<MaterialStateProperty<EdgeInsetsGeometry?>>( |
277 | 'padding' , |
278 | padding, |
279 | defaultValue: null, |
280 | ), |
281 | ); |
282 | properties.add( |
283 | DiagnosticsProperty<MaterialStateProperty<TextStyle?>>( |
284 | 'textStyle' , |
285 | textStyle, |
286 | defaultValue: null, |
287 | ), |
288 | ); |
289 | properties.add( |
290 | DiagnosticsProperty<MaterialStateProperty<TextStyle?>>( |
291 | 'hintStyle' , |
292 | hintStyle, |
293 | defaultValue: null, |
294 | ), |
295 | ); |
296 | properties.add( |
297 | DiagnosticsProperty<BoxConstraints>('constraints' , constraints, defaultValue: null), |
298 | ); |
299 | properties.add( |
300 | DiagnosticsProperty<TextCapitalization>( |
301 | 'textCapitalization' , |
302 | textCapitalization, |
303 | defaultValue: null, |
304 | ), |
305 | ); |
306 | } |
307 | |
308 | // Special case because BorderSide.lerp() doesn't support null arguments |
309 | static MaterialStateProperty<BorderSide?>? _lerpSides( |
310 | MaterialStateProperty<BorderSide?>? a, |
311 | MaterialStateProperty<BorderSide?>? b, |
312 | double t, |
313 | ) { |
314 | if (identical(a, b)) { |
315 | return a; |
316 | } |
317 | return MaterialStateBorderSide.lerp(a, b, t); |
318 | } |
319 | } |
320 | |
321 | /// Applies a search bar theme to descendant [SearchBar] widgets. |
322 | /// |
323 | /// Descendant widgets obtain the current theme's [SearchBarTheme] object using |
324 | /// [SearchBarTheme.of]. When a widget uses [SearchBarTheme.of], it is automatically |
325 | /// rebuilt if the theme later changes. |
326 | /// |
327 | /// A search bar theme can be specified as part of the overall Material theme using |
328 | /// [ThemeData.searchBarTheme]. |
329 | /// |
330 | /// See also: |
331 | /// |
332 | /// * [SearchBarThemeData], which describes the actual configuration of a search bar |
333 | /// theme. |
334 | class SearchBarTheme extends InheritedWidget { |
335 | /// Constructs a search bar theme that configures all descendant [SearchBar] widgets. |
336 | const SearchBarTheme({super.key, required this.data, required super.child}); |
337 | |
338 | /// The properties used for all descendant [SearchBar] widgets. |
339 | final SearchBarThemeData data; |
340 | |
341 | /// Returns the configuration [data] from the closest [SearchBarTheme] ancestor. |
342 | /// If there is no ancestor, it returns [ThemeData.searchBarTheme]. |
343 | /// |
344 | /// Typical usage is as follows: |
345 | /// |
346 | /// ```dart |
347 | /// SearchBarThemeData theme = SearchBarTheme.of(context); |
348 | /// ``` |
349 | static SearchBarThemeData of(BuildContext context) { |
350 | final SearchBarTheme? searchBarTheme = |
351 | context.dependOnInheritedWidgetOfExactType<SearchBarTheme>(); |
352 | return searchBarTheme?.data ?? Theme.of(context).searchBarTheme; |
353 | } |
354 | |
355 | @override |
356 | bool updateShouldNotify(SearchBarTheme oldWidget) => data != oldWidget.data; |
357 | } |
358 | |