您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
241 行
10 KiB
241 行
10 KiB
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.widgets;
|
|
|
|
namespace Unity.UIWidgets.material
|
|
{
|
|
public static class CircleAvatarUtils
|
|
{
|
|
// The default radius if nothing is specified.
|
|
public static float _defaultRadius = 20.0f;
|
|
|
|
// The default min if only the max is specified.
|
|
public static float _defaultMinRadius = 0.0f;
|
|
|
|
// The default max if only the min is specified.
|
|
public static float _defaultMaxRadius = float.PositiveInfinity;
|
|
}
|
|
|
|
public class CircleAvatar : StatelessWidget
|
|
{
|
|
/// The color with which to fill the circle. Changing the background
|
|
/// color will cause the avatar to animate to the new color.
|
|
///
|
|
/// If a [backgroundColor] is not specified, the theme's
|
|
/// [ThemeData.primaryColorLight] is used with dark foreground colors, and
|
|
/// [ThemeData.primaryColorDark] with light foreground colors.
|
|
public readonly Color backgroundColor;
|
|
|
|
/// The background image of the circle. Changing the background
|
|
/// image will cause the avatar to animate to the new image.
|
|
///
|
|
/// Typically used as a fallback image for [foregroundImage].
|
|
///
|
|
/// If the [CircleAvatar] is to have the user's initials, use [child] instead.
|
|
public readonly ImageProvider backgroundImage;
|
|
|
|
/// The widget below this widget in the tree.
|
|
///
|
|
/// Typically a [Text] widget. If the [CircleAvatar] is to have an image, use
|
|
/// [backgroundImage] instead.
|
|
public readonly Widget child;
|
|
|
|
/// The default text color for text in the circle.
|
|
///
|
|
/// Defaults to the primary text theme color if no [backgroundColor] is
|
|
/// specified.
|
|
///
|
|
/// Defaults to [ThemeData.primaryColorLight] for dark background colors, and
|
|
/// [ThemeData.primaryColorDark] for light background colors.
|
|
public readonly Color foregroundColor;
|
|
|
|
/// The foreground image of the circle.
|
|
///
|
|
/// Typically used as profile image. For fallback use [backgroundImage].
|
|
public readonly ImageProvider foregroundImage;
|
|
|
|
/// The maximum size of the avatar, expressed as the radius (half the
|
|
/// diameter).
|
|
///
|
|
/// If [maxRadius] is specified, then [radius] must not also be specified.
|
|
///
|
|
/// Defaults to [double.infinity].
|
|
///
|
|
/// Constraint changes are animated, but size changes due to the environment
|
|
/// itself changing are not. For example, changing the [maxRadius] from 10 to
|
|
/// 20 when the [CircleAvatar] is in an unconstrained environment will cause
|
|
/// the avatar to animate from a 20 pixel diameter to a 40 pixel diameter.
|
|
/// However, if the [maxRadius] is 40 and the [CircleAvatar] has a parent
|
|
/// [SizedBox] whose size changes instantaneously from 20 pixels to 40 pixels,
|
|
/// the size will snap to 40 pixels instantly.
|
|
public readonly float? maxRadius;
|
|
|
|
/// The minimum size of the avatar, expressed as the radius (half the
|
|
/// diameter).
|
|
///
|
|
/// If [minRadius] is specified, then [radius] must not also be specified.
|
|
///
|
|
/// Defaults to zero.
|
|
///
|
|
/// Constraint changes are animated, but size changes due to the environment
|
|
/// itself changing are not. For example, changing the [minRadius] from 10 to
|
|
/// 20 when the [CircleAvatar] is in an unconstrained environment will cause
|
|
/// the avatar to animate from a 20 pixel diameter to a 40 pixel diameter.
|
|
/// However, if the [minRadius] is 40 and the [CircleAvatar] has a parent
|
|
/// [SizedBox] whose size changes instantaneously from 20 pixels to 40 pixels,
|
|
/// the size will snap to 40 pixels instantly.
|
|
public readonly float? minRadius;
|
|
|
|
/// An optional error callback for errors emitted when loading
|
|
/// [backgroundImage].
|
|
public readonly ImageErrorListener onBackgroundImageError;
|
|
|
|
/// An optional error callback for errors emitted when loading
|
|
/// [foregroundImage].
|
|
public readonly ImageErrorListener onForegroundImageError;
|
|
|
|
/// The size of the avatar, expressed as the radius (half the diameter).
|
|
///
|
|
/// If [radius] is specified, then neither [minRadius] nor [maxRadius] may be
|
|
/// specified. Specifying [radius] is equivalent to specifying a [minRadius]
|
|
/// and [maxRadius], both with the value of [radius].
|
|
///
|
|
/// If neither [minRadius] nor [maxRadius] are specified, defaults to 20
|
|
/// logical pixels. This is the appropriate size for use with
|
|
/// [ListTile.leading].
|
|
///
|
|
/// Changes to the [radius] are animated (including changing from an explicit
|
|
/// [radius] to a [minRadius]/[maxRadius] pair or vice versa).
|
|
public readonly float? radius;
|
|
|
|
/// Creates a circle that represents a user.
|
|
public CircleAvatar(
|
|
Key key = null,
|
|
Widget child = null,
|
|
Color backgroundColor = null,
|
|
Color foregroundColor = null,
|
|
ImageProvider backgroundImage = null,
|
|
ImageProvider foregroundImage = null,
|
|
ImageErrorListener onBackgroundImageError = null,
|
|
ImageErrorListener onForegroundImageError = null,
|
|
float radius = 0.0f,
|
|
float minRadius = 0.0f,
|
|
float maxRadius = 0.0f
|
|
) : base(key)
|
|
{
|
|
D.assert(radius == null || minRadius == null && maxRadius == null);
|
|
D.assert(backgroundImage != null || onBackgroundImageError == null);
|
|
D.assert(foregroundImage != null || onForegroundImageError == null);
|
|
this.child = child;
|
|
this.backgroundColor = backgroundColor;
|
|
this.backgroundImage = backgroundImage;
|
|
this.foregroundImage = foregroundImage;
|
|
this.onBackgroundImageError = onBackgroundImageError;
|
|
this.onForegroundImageError = onForegroundImageError;
|
|
this.foregroundColor = foregroundColor;
|
|
this.radius = radius;
|
|
this.minRadius = minRadius;
|
|
this.maxRadius = maxRadius;
|
|
}
|
|
|
|
|
|
private float _minDiameter
|
|
{
|
|
get
|
|
{
|
|
if (radius == null && minRadius == null && maxRadius == null)
|
|
return CircleAvatarUtils._defaultRadius * 2.0f;
|
|
return 2.0f * (radius ?? minRadius ?? CircleAvatarUtils._defaultMinRadius);
|
|
}
|
|
}
|
|
|
|
private float _maxDiameter
|
|
{
|
|
get
|
|
{
|
|
if (radius == null && minRadius == null && maxRadius == null)
|
|
return CircleAvatarUtils._defaultRadius * 2.0f;
|
|
return 2.0f * (radius ?? maxRadius ?? CircleAvatarUtils._defaultMaxRadius);
|
|
}
|
|
}
|
|
|
|
public override Widget build(BuildContext context)
|
|
{
|
|
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
|
|
var theme = Theme.of(context);
|
|
var textStyle = theme.primaryTextTheme.subtitle1.copyWith(color: foregroundColor);
|
|
var effectiveBackgroundColor = backgroundColor;
|
|
if (effectiveBackgroundColor == null)
|
|
switch (ThemeData.estimateBrightnessForColor(textStyle.color))
|
|
{
|
|
case Brightness.dark:
|
|
effectiveBackgroundColor = theme.primaryColorLight;
|
|
break;
|
|
case Brightness.light:
|
|
effectiveBackgroundColor = theme.primaryColorDark;
|
|
break;
|
|
}
|
|
else if (foregroundColor == null)
|
|
switch (ThemeData.estimateBrightnessForColor(backgroundColor))
|
|
{
|
|
case Brightness.dark:
|
|
textStyle = textStyle.copyWith(color: theme.primaryColorLight);
|
|
break;
|
|
case Brightness.light:
|
|
textStyle = textStyle.copyWith(color: theme.primaryColorDark);
|
|
break;
|
|
}
|
|
|
|
var minDiameter = _minDiameter;
|
|
var maxDiameter = _maxDiameter;
|
|
return new AnimatedContainer(
|
|
constraints: new BoxConstraints(
|
|
minHeight: minDiameter,
|
|
minWidth: minDiameter,
|
|
maxWidth: maxDiameter,
|
|
maxHeight: maxDiameter
|
|
),
|
|
duration: material_.kThemeChangeDuration,
|
|
decoration: new BoxDecoration(
|
|
effectiveBackgroundColor,
|
|
backgroundImage != null
|
|
? new DecorationImage(
|
|
backgroundImage,
|
|
onBackgroundImageError,
|
|
fit: BoxFit.cover
|
|
)
|
|
: null,
|
|
shape: BoxShape.circle
|
|
),
|
|
foregroundDecoration: foregroundImage != null
|
|
? new BoxDecoration(
|
|
image: new DecorationImage(
|
|
foregroundImage,
|
|
onForegroundImageError,
|
|
fit: BoxFit.cover
|
|
),
|
|
shape: BoxShape.circle
|
|
)
|
|
: null,
|
|
child: child == null
|
|
? null
|
|
: new Center(
|
|
child: new MediaQuery(
|
|
// Need to ignore the ambient textScaleFactor here so that the
|
|
// text doesn't escape the avatar when the textScaleFactor is large.
|
|
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0f),
|
|
child: new IconTheme(
|
|
data: theme.iconTheme.copyWith(textStyle.color),
|
|
child: new DefaultTextStyle(
|
|
style: textStyle,
|
|
child: child
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
}
|