2
2
// Use of this source code is governed by a BSD-style license that can be
3
3
// found in the LICENSE file.
4
4
5
+ import 'package:flutter/rendering.dart' ;
5
6
import 'package:flutter/widgets.dart' ;
6
7
7
8
import 'badge_theme.dart' ;
@@ -35,6 +36,7 @@ class Badge extends StatelessWidget {
35
36
this .textStyle,
36
37
this .padding,
37
38
this .alignment,
39
+ this .offset,
38
40
this .label,
39
41
this .isLabelVisible = true ,
40
42
this .child,
@@ -54,6 +56,7 @@ class Badge extends StatelessWidget {
54
56
this .textStyle,
55
57
this .padding,
56
58
this .alignment,
59
+ this .offset,
57
60
required int count,
58
61
this .isLabelVisible = true ,
59
62
this .child,
@@ -106,13 +109,29 @@ class Badge extends StatelessWidget {
106
109
/// left and right if the theme's value is null.
107
110
final EdgeInsetsGeometry ? padding;
108
111
109
- /// The location of the [label] relative to the [child] .
112
+ /// Combined with [offset] to determine the location of the [label]
113
+ /// relative to the [child] .
114
+ ///
115
+ /// The alignment positions the label in the same way a child of an
116
+ /// [Align] widget is positioned, except that, the alignment is
117
+ /// resolved as if the label was a [largeSize] square and [offset]
118
+ /// is added to the result.
119
+ ///
120
+ /// This value is only used if [label] is non-null.
121
+ ///
122
+ /// Defaults to the [BadgeTheme] 's alignment, or
123
+ /// [AlignmentDirectional.topEnd] if the theme's value is null.
124
+ final AlignmentGeometry ? alignment;
125
+
126
+ /// Combined with [alignment] to determine the location of the [label]
127
+ /// relative to the [child] .
110
128
///
111
129
/// This value is only used if [label] is non-null.
112
130
///
113
- /// Defaults to the [BadgeTheme] 's alignment, or `start = 12`
114
- /// and `top = -4` if the theme's value is null.
115
- final AlignmentDirectional ? alignment;
131
+ /// Defaults to the [BadgeTheme] 's offset, or
132
+ /// if the theme's value is null then `Offset(4, -4)` for
133
+ /// [TextDirection.ltr] or `Offset(-4, -4)` for [TextDirection.rtl] .
134
+ final Offset ? offset;
116
135
117
136
/// The badge's content, typically a [Text] widget that contains 1 to 4
118
137
/// characters.
@@ -168,24 +187,99 @@ class Badge extends StatelessWidget {
168
187
return badge;
169
188
}
170
189
171
- final AlignmentDirectional effectiveAlignment = alignment ?? badgeTheme.alignment ?? defaults.alignment! ;
190
+ final AlignmentGeometry effectiveAlignment = alignment ?? badgeTheme.alignment ?? defaults.alignment! ;
191
+ final TextDirection textDirection = Directionality .of (context);
192
+ final Offset defaultOffset = textDirection == TextDirection .ltr ? const Offset (4 , - 4 ) : const Offset (- 4 , - 4 );
193
+ final Offset effectiveOffset = offset ?? badgeTheme.offset ?? defaultOffset;
194
+
172
195
return
173
196
Stack (
174
197
clipBehavior: Clip .none,
175
198
children: < Widget > [
176
199
child! ,
177
- Positioned .directional (
178
- textDirection: Directionality .of (context),
179
- start: label == null ? null : effectiveAlignment.start,
180
- end: label == null ? 0 : null ,
181
- top: label == null ? 0 : effectiveAlignment.y,
182
- child: badge,
200
+ Positioned .fill (
201
+ child: _Badge (
202
+ alignment: effectiveAlignment,
203
+ offset: label == null ? Offset .zero : effectiveOffset,
204
+ textDirection: textDirection,
205
+ child: badge,
206
+ ),
183
207
),
184
208
],
185
209
);
186
210
}
187
211
}
188
212
213
+ class _Badge extends SingleChildRenderObjectWidget {
214
+ const _Badge ({
215
+ required this .alignment,
216
+ required this .offset,
217
+ required this .textDirection,
218
+ super .child, // the badge
219
+ });
220
+
221
+ final AlignmentGeometry alignment;
222
+ final Offset offset;
223
+ final TextDirection textDirection;
224
+
225
+ @override
226
+ _RenderBadge createRenderObject (BuildContext context) {
227
+ return _RenderBadge (
228
+ alignment: alignment,
229
+ offset: offset,
230
+ textDirection: Directionality .maybeOf (context),
231
+ );
232
+ }
233
+
234
+ @override
235
+ void updateRenderObject (BuildContext context, _RenderBadge renderObject) {
236
+ renderObject
237
+ ..alignment = alignment
238
+ ..offset = offset
239
+ ..textDirection = Directionality .maybeOf (context);
240
+ }
241
+
242
+ @override
243
+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
244
+ super .debugFillProperties (properties);
245
+ properties.add (DiagnosticsProperty <AlignmentGeometry >('alignment' , alignment));
246
+ properties.add (DiagnosticsProperty <Offset >('offset' , offset));
247
+ }
248
+ }
249
+
250
+ class _RenderBadge extends RenderAligningShiftedBox {
251
+ _RenderBadge ({
252
+ super .textDirection,
253
+ super .alignment,
254
+ required Offset offset,
255
+ }) : _offset = offset;
256
+
257
+ Offset get offset => _offset;
258
+ Offset _offset;
259
+ set offset (Offset value) {
260
+ if (_offset == value) {
261
+ return ;
262
+ }
263
+ _offset = value;
264
+ markNeedsLayout ();
265
+ }
266
+
267
+ @override
268
+ void performLayout () {
269
+ final BoxConstraints constraints = this .constraints;
270
+ assert (constraints.hasBoundedWidth);
271
+ assert (constraints.hasBoundedHeight);
272
+ size = constraints.biggest;
273
+
274
+ child! .layout (const BoxConstraints (), parentUsesSize: true );
275
+ final double badgeSize = child! .size.height;
276
+ final Alignment resolvedAlignment = alignment.resolve (textDirection);
277
+ final BoxParentData childParentData = child! .parentData! as BoxParentData ;
278
+ childParentData.offset = offset + resolvedAlignment.alongOffset (Offset (size.width - badgeSize, size.height - badgeSize));
279
+ }
280
+ }
281
+
282
+
189
283
// BEGIN GENERATED TOKEN PROPERTIES - Badge
190
284
191
285
// Do not edit by hand. The code between the "BEGIN GENERATED" and
@@ -200,7 +294,7 @@ class _BadgeDefaultsM3 extends BadgeThemeData {
200
294
smallSize: 6.0 ,
201
295
largeSize: 16.0 ,
202
296
padding: const EdgeInsets .symmetric (horizontal: 4 ),
203
- alignment: const AlignmentDirectional ( 12 , - 4 ) ,
297
+ alignment: AlignmentDirectional .topEnd ,
204
298
);
205
299
206
300
final BuildContext context;
0 commit comments