您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
721 行
26 KiB
721 行
26 KiB
using System.Collections.Generic;
|
|
using Unity.UIWidgets.animation;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.utils;
|
|
using Unity.UIWidgets.widgets;
|
|
|
|
namespace Unity.UIWidgets.material {
|
|
public abstract class MergeableMaterialItem {
|
|
public MergeableMaterialItem(
|
|
LocalKey key) {
|
|
D.assert(key != null);
|
|
this.key = key;
|
|
}
|
|
|
|
public readonly LocalKey key;
|
|
}
|
|
|
|
public class MaterialSlice : MergeableMaterialItem {
|
|
public MaterialSlice(
|
|
LocalKey key = null,
|
|
Widget child = null) : base(key: key) {
|
|
D.assert(key != null);
|
|
D.assert(child != null);
|
|
this.child = child;
|
|
}
|
|
|
|
public readonly Widget child;
|
|
|
|
public override string ToString() {
|
|
return "MergeableSlice(key: " + this.key + ", child: " + this.child + ")";
|
|
}
|
|
}
|
|
|
|
public class MaterialGap : MergeableMaterialItem {
|
|
public MaterialGap(
|
|
LocalKey key = null,
|
|
double size = 16.0) : base(key: key) {
|
|
D.assert(key != null);
|
|
this.size = size;
|
|
}
|
|
|
|
public readonly double size;
|
|
|
|
public override string ToString() {
|
|
return "MaterialGap(key: " + this.key + ", child: " + this.size + ")";
|
|
}
|
|
}
|
|
|
|
|
|
public class MergeableMaterial : StatefulWidget {
|
|
public MergeableMaterial(
|
|
Key key = null,
|
|
Axis mainAxis = Axis.vertical,
|
|
int elevation = 2,
|
|
bool hasDividers = false,
|
|
List<MergeableMaterialItem> children = null) : base(key: key) {
|
|
this.mainAxis = mainAxis;
|
|
this.elevation = elevation;
|
|
this.hasDividers = hasDividers;
|
|
this.children = children ?? new List<MergeableMaterialItem>();
|
|
}
|
|
|
|
public readonly List<MergeableMaterialItem> children;
|
|
|
|
public readonly Axis mainAxis;
|
|
|
|
public readonly int elevation;
|
|
|
|
public readonly bool hasDividers;
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.add(new EnumProperty<Axis>("mainAxis", this.mainAxis));
|
|
properties.add(new DoubleProperty("elevation", this.elevation));
|
|
}
|
|
|
|
public override State createState() {
|
|
return new _MergeableMaterialState();
|
|
}
|
|
}
|
|
|
|
|
|
public class _AnimationTuple {
|
|
public _AnimationTuple(
|
|
AnimationController controller = null,
|
|
CurvedAnimation startAnimation = null,
|
|
CurvedAnimation endAnimation = null,
|
|
CurvedAnimation gapAnimation = null,
|
|
double gapStart = 0.0) {
|
|
this.controller = controller;
|
|
this.startAnimation = startAnimation;
|
|
this.endAnimation = endAnimation;
|
|
this.gapAnimation = gapAnimation;
|
|
this.gapStart = gapStart;
|
|
}
|
|
|
|
public readonly AnimationController controller;
|
|
|
|
public readonly CurvedAnimation startAnimation;
|
|
|
|
public readonly CurvedAnimation endAnimation;
|
|
|
|
public readonly CurvedAnimation gapAnimation;
|
|
|
|
public double gapStart;
|
|
}
|
|
|
|
|
|
public class _MergeableMaterialState : TickerProviderStateMixin<MergeableMaterial> {
|
|
List<MergeableMaterialItem> _children;
|
|
|
|
public readonly Dictionary<LocalKey, _AnimationTuple> _animationTuples =
|
|
new Dictionary<LocalKey, _AnimationTuple>();
|
|
|
|
public override void initState() {
|
|
base.initState();
|
|
this._children = new List<MergeableMaterialItem>();
|
|
this._children.AddRange(this.widget.children);
|
|
|
|
for (int i = 0; i < this._children.Count; i++) {
|
|
if (this._children[i] is MaterialGap) {
|
|
this._initGap((MaterialGap) this._children[i]);
|
|
this._animationTuples[this._children[i].key].controller.setValue(1.0);
|
|
}
|
|
}
|
|
|
|
D.assert(this._debugGapsAreValid(this._children));
|
|
}
|
|
|
|
void _initGap(MaterialGap gap) {
|
|
AnimationController controller = new AnimationController(
|
|
duration: ThemeUtils.kThemeAnimationDuration,
|
|
vsync: this);
|
|
|
|
CurvedAnimation startAnimation = new CurvedAnimation(
|
|
parent: controller,
|
|
curve: Curves.fastOutSlowIn);
|
|
|
|
CurvedAnimation endAnimation = new CurvedAnimation(
|
|
parent: controller,
|
|
curve: Curves.fastOutSlowIn);
|
|
|
|
CurvedAnimation gapAnimation = new CurvedAnimation(
|
|
parent: controller,
|
|
curve: Curves.fastOutSlowIn);
|
|
|
|
controller.addListener(this._handleTick);
|
|
|
|
this._animationTuples[gap.key] = new _AnimationTuple(
|
|
controller: controller,
|
|
startAnimation: startAnimation,
|
|
endAnimation: endAnimation,
|
|
gapAnimation: gapAnimation);
|
|
}
|
|
|
|
public override void dispose() {
|
|
foreach (MergeableMaterialItem child in this._children) {
|
|
if (child is MaterialGap) {
|
|
this._animationTuples[child.key].controller.dispose();
|
|
}
|
|
}
|
|
|
|
base.dispose();
|
|
}
|
|
|
|
|
|
void _handleTick() {
|
|
this.setState(() => { });
|
|
}
|
|
|
|
bool _debugHasConsecutiveGaps(List<MergeableMaterialItem> children) {
|
|
for (int i = 0; i < this.widget.children.Count - 1; i++) {
|
|
if (this.widget.children[i] is MaterialGap &&
|
|
this.widget.children[i + 1] is MaterialGap) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool _debugGapsAreValid(List<MergeableMaterialItem> children) {
|
|
if (this._debugHasConsecutiveGaps(children)) {
|
|
return false;
|
|
}
|
|
|
|
if (children.isNotEmpty()) {
|
|
if (children.first() is MaterialGap || children.last() is MaterialGap) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void _insertChild(int index, MergeableMaterialItem child) {
|
|
this._children.Insert(index, child);
|
|
|
|
if (child is MaterialGap) {
|
|
this._initGap((MaterialGap) child);
|
|
}
|
|
}
|
|
|
|
void _removeChild(int index) {
|
|
MergeableMaterialItem child = this._children[index];
|
|
this._children.RemoveAt(index);
|
|
|
|
if (child is MaterialGap) {
|
|
this._animationTuples[child.key] = null;
|
|
}
|
|
}
|
|
|
|
bool _isClosingGap(int index) {
|
|
if (index < this._children.Count - 1 && this._children[index] is MaterialGap) {
|
|
return this._animationTuples[this._children[index].key].controller.status == AnimationStatus.reverse;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void _removeEmptyGaps() {
|
|
int j = 0;
|
|
|
|
while (j < this._children.Count) {
|
|
if (this._children[j] is MaterialGap &&
|
|
this._animationTuples[this._children[j].key].controller.status == AnimationStatus.dismissed) {
|
|
this._removeChild(j);
|
|
}
|
|
else {
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void didUpdateWidget(StatefulWidget oldWidget) {
|
|
base.didUpdateWidget(oldWidget);
|
|
|
|
MergeableMaterial _oldWidget = (MergeableMaterial) oldWidget;
|
|
HashSet<LocalKey> oldKeys = new HashSet<LocalKey>();
|
|
foreach (MergeableMaterialItem child in _oldWidget.children) {
|
|
oldKeys.Add(child.key);
|
|
}
|
|
|
|
HashSet<LocalKey> newKeys = new HashSet<LocalKey>();
|
|
foreach (MergeableMaterialItem child in this.widget.children) {
|
|
newKeys.Add(child.key);
|
|
}
|
|
|
|
HashSet<LocalKey> newOnly = new HashSet<LocalKey>();
|
|
foreach (var key in newKeys) {
|
|
if (!oldKeys.Contains(key)) {
|
|
newOnly.Add(key);
|
|
}
|
|
}
|
|
|
|
HashSet<LocalKey> oldOnly = new HashSet<LocalKey>();
|
|
foreach (var key in oldKeys) {
|
|
if (!newKeys.Contains(key)) {
|
|
oldOnly.Add(key);
|
|
}
|
|
}
|
|
|
|
List<MergeableMaterialItem> newChildren = this.widget.children;
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
D.assert(this._debugGapsAreValid(newChildren));
|
|
this._removeEmptyGaps();
|
|
|
|
while (i < newChildren.Count && j < this._children.Count) {
|
|
if (newOnly.Contains(newChildren[i].key) ||
|
|
oldOnly.Contains(this._children[j].key)) {
|
|
int startNew = i;
|
|
int startOld = j;
|
|
|
|
while (newOnly.Contains(newChildren[i].key)) {
|
|
i++;
|
|
}
|
|
|
|
while (oldOnly.Contains(this._children[j].key) || this._isClosingGap(j)) {
|
|
j++;
|
|
}
|
|
|
|
int newLength = i - startNew;
|
|
int oldLength = j - startOld;
|
|
|
|
if (newLength > 0) {
|
|
if (oldLength > 1 || oldLength == 1 && this._children[startOld] is MaterialSlice) {
|
|
if (newLength == 1 && newChildren[startNew] is MaterialGap) {
|
|
double gapSizeSum = 0.0;
|
|
|
|
while (startOld < j) {
|
|
if (this._children[startOld] is MaterialGap) {
|
|
MaterialGap gap = (MaterialGap) this._children[startOld];
|
|
gapSizeSum += gap.size;
|
|
}
|
|
|
|
this._removeChild(startOld);
|
|
j--;
|
|
}
|
|
|
|
this._insertChild(startOld, newChildren[startNew]);
|
|
this._animationTuples[newChildren[startNew].key].gapStart = gapSizeSum;
|
|
this._animationTuples[newChildren[startNew].key].controller.forward();
|
|
j++;
|
|
}
|
|
else {
|
|
for (int k = 0; k < oldLength; k++) {
|
|
this._removeChild(startOld);
|
|
}
|
|
|
|
for (int k = 0; k < newLength; k++) {
|
|
this._insertChild(startOld + k, newChildren[startNew + k]);
|
|
}
|
|
|
|
j += (newLength - oldLength);
|
|
}
|
|
}
|
|
else if (oldLength == 1) {
|
|
if (newLength == 1 && newChildren[startNew] is MaterialGap &&
|
|
this._children[startOld].key == newChildren[startNew].key) {
|
|
this._animationTuples[newChildren[startNew].key].controller.forward();
|
|
}
|
|
else {
|
|
double gapSize = this._getGapSize(startOld);
|
|
|
|
this._removeChild(startOld);
|
|
|
|
for (int k = 0; k < newLength; k++) {
|
|
this._insertChild(startOld + k, newChildren[startNew + k]);
|
|
}
|
|
|
|
j += (newLength - 1);
|
|
double gapSizeSum = 0.0;
|
|
|
|
for (int k = startNew; k < i; k++) {
|
|
if (newChildren[k] is MaterialGap) {
|
|
MaterialGap gap = (MaterialGap) newChildren[k];
|
|
gapSizeSum += gap.size;
|
|
}
|
|
}
|
|
|
|
for (int k = startNew; k < i; k++) {
|
|
if (newChildren[k] is MaterialGap) {
|
|
MaterialGap gap = (MaterialGap) newChildren[k];
|
|
|
|
this._animationTuples[gap.key].gapStart = gapSize * gap.size / gapSizeSum;
|
|
this._animationTuples[gap.key].controller.setValue(0.0);
|
|
this._animationTuples[gap.key].controller.forward();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (int k = 0; k < newLength; k++) {
|
|
this._insertChild(startOld + k, newChildren[startNew + k]);
|
|
|
|
if (newChildren[startNew + k] is MaterialGap) {
|
|
MaterialGap gap = (MaterialGap) newChildren[startNew + k];
|
|
this._animationTuples[gap.key].controller.forward();
|
|
}
|
|
}
|
|
|
|
j += newLength;
|
|
}
|
|
}
|
|
else {
|
|
if (oldLength > 1 || oldLength == 1 && this._children[startOld] is MaterialSlice) {
|
|
double gapSizeSum = 0.0;
|
|
|
|
while (startOld < j) {
|
|
if (this._children[startOld] is MaterialGap) {
|
|
MaterialGap gap = (MaterialGap) this._children[startOld];
|
|
gapSizeSum += gap.size;
|
|
}
|
|
|
|
this._removeChild(startOld);
|
|
j--;
|
|
}
|
|
|
|
if (gapSizeSum != 0.0) {
|
|
MaterialGap gap = new MaterialGap(key: new UniqueKey(), size: gapSizeSum);
|
|
this._insertChild(startOld, gap);
|
|
this._animationTuples[gap.key].gapStart = 0.0;
|
|
this._animationTuples[gap.key].controller.setValue(1.0);
|
|
this._animationTuples[gap.key].controller.reverse();
|
|
j++;
|
|
}
|
|
}
|
|
else if (oldLength == 1) {
|
|
MaterialGap gap = (MaterialGap) this._children[startOld];
|
|
this._animationTuples[gap.key].gapStart = 0.0;
|
|
this._animationTuples[gap.key].controller.reverse();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ((this._children[j] is MaterialGap) == (newChildren[i] is MaterialGap)) {
|
|
this._children[j] = newChildren[i];
|
|
|
|
i++;
|
|
j++;
|
|
}
|
|
else {
|
|
D.assert(this._children[j] is MaterialGap);
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (j < this._children.Count) {
|
|
this._removeChild(j);
|
|
}
|
|
|
|
while (i < newChildren.Count) {
|
|
this._insertChild(j, newChildren[i]);
|
|
|
|
i++;
|
|
j++;
|
|
}
|
|
}
|
|
|
|
|
|
BorderRadius _borderRadius(int index, bool start, bool end) {
|
|
D.assert(MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft ==
|
|
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topRight);
|
|
D.assert(MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft ==
|
|
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].bottomLeft);
|
|
D.assert(MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft ==
|
|
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].bottomRight);
|
|
|
|
Radius cardRadius = MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft;
|
|
Radius startRadius = Radius.zero;
|
|
Radius endRadius = Radius.zero;
|
|
|
|
if (index > 0 && this._children[index - 1] is MaterialGap) {
|
|
startRadius = Radius.lerp(
|
|
Radius.zero,
|
|
cardRadius,
|
|
this._animationTuples[this._children[index - 1].key].startAnimation.value);
|
|
}
|
|
|
|
if (index < this._children.Count - 2 && this._children[index + 1] is MaterialGap) {
|
|
endRadius = Radius.lerp(
|
|
Radius.zero,
|
|
cardRadius,
|
|
this._animationTuples[this._children[index + 1].key].endAnimation.value);
|
|
}
|
|
|
|
if (this.widget.mainAxis == Axis.vertical) {
|
|
return BorderRadius.vertical(
|
|
top: start ? cardRadius : startRadius,
|
|
bottom: end ? cardRadius : endRadius);
|
|
}
|
|
else {
|
|
return BorderRadius.horizontal(
|
|
left: start ? cardRadius : startRadius,
|
|
right: end ? cardRadius : endRadius);
|
|
}
|
|
}
|
|
|
|
|
|
double _getGapSize(int index) {
|
|
MaterialGap gap = (MaterialGap) this._children[index];
|
|
|
|
return MathUtils.lerpDouble(this._animationTuples[gap.key].gapStart,
|
|
gap.size,
|
|
this._animationTuples[gap.key].gapAnimation.value);
|
|
}
|
|
|
|
|
|
bool _willNeedDivider(int index) {
|
|
if (index < 0) {
|
|
return false;
|
|
}
|
|
|
|
if (index >= this._children.Count) {
|
|
return false;
|
|
}
|
|
|
|
return this._children[index] is MaterialSlice || this._isClosingGap(index);
|
|
}
|
|
|
|
|
|
public override Widget build(BuildContext context) {
|
|
this._removeEmptyGaps();
|
|
|
|
List<Widget> widgets = new List<Widget>();
|
|
List<Widget> slices = new List<Widget>();
|
|
int i;
|
|
|
|
for (i = 0; i < this._children.Count; i++) {
|
|
if (this._children[i] is MaterialGap) {
|
|
D.assert(slices.isNotEmpty());
|
|
widgets.Add(
|
|
new Container(
|
|
decoration: new BoxDecoration(
|
|
color: Theme.of(context).cardColor,
|
|
borderRadius: this._borderRadius(i - 1, widgets.isEmpty(), false),
|
|
shape: BoxShape.rectangle),
|
|
child: new ListBody(
|
|
mainAxis: this.widget.mainAxis,
|
|
children: slices)
|
|
)
|
|
);
|
|
|
|
slices = new List<Widget>();
|
|
widgets.Add(
|
|
new SizedBox(
|
|
width: this.widget.mainAxis == Axis.horizontal ? this._getGapSize(i) : (double?) null,
|
|
height: this.widget.mainAxis == Axis.vertical ? this._getGapSize(i) : (double?) null)
|
|
);
|
|
}
|
|
else {
|
|
MaterialSlice slice = (MaterialSlice) this._children[i];
|
|
Widget child = slice.child;
|
|
|
|
if (this.widget.hasDividers) {
|
|
bool hasTopDivider = this._willNeedDivider(i - 1);
|
|
bool hasBottomDivider = this._willNeedDivider(i + 1);
|
|
|
|
Border border;
|
|
BorderSide divider = Divider.createBorderSide(
|
|
context,
|
|
width: 0.5
|
|
);
|
|
|
|
if (i == 0) {
|
|
border = new Border(
|
|
bottom: hasBottomDivider ? divider : BorderSide.none);
|
|
}
|
|
else if (i == this._children.Count - 1) {
|
|
border = new Border(
|
|
top: hasTopDivider ? divider : BorderSide.none);
|
|
}
|
|
else {
|
|
border = new Border(
|
|
top: hasTopDivider ? divider : BorderSide.none,
|
|
bottom: hasBottomDivider ? divider : BorderSide.none
|
|
);
|
|
}
|
|
|
|
D.assert(border != null);
|
|
|
|
child = new AnimatedContainer(
|
|
key: new _MergeableMaterialSliceKey(this._children[i].key),
|
|
decoration: new BoxDecoration(border: border),
|
|
duration: ThemeUtils.kThemeAnimationDuration,
|
|
curve: Curves.fastOutSlowIn,
|
|
child: child
|
|
);
|
|
}
|
|
|
|
slices.Add(
|
|
new Material(
|
|
type: MaterialType.transparency,
|
|
child: child
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
if (slices.isNotEmpty()) {
|
|
widgets.Add(
|
|
new Container(
|
|
decoration: new BoxDecoration(
|
|
color: Theme.of(context).cardColor,
|
|
borderRadius: this._borderRadius(i - 1, widgets.isEmpty(), true),
|
|
shape: BoxShape.rectangle
|
|
),
|
|
child: new ListBody(
|
|
mainAxis: this.widget.mainAxis,
|
|
children: slices
|
|
)
|
|
)
|
|
);
|
|
slices = new List<Widget>();
|
|
}
|
|
|
|
return new _MergeableMaterialListBody(
|
|
mainAxis: this.widget.mainAxis,
|
|
boxShadows: ShadowConstants.kElevationToShadow[this.widget.elevation],
|
|
items: this._children,
|
|
children: widgets
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
class _MergeableMaterialSliceKey : GlobalKey {
|
|
public _MergeableMaterialSliceKey(LocalKey value) : base() {
|
|
this.value = value;
|
|
}
|
|
|
|
public readonly LocalKey value;
|
|
|
|
public bool Equals(_MergeableMaterialSliceKey other) {
|
|
if (ReferenceEquals(null, other)) {
|
|
return false;
|
|
}
|
|
|
|
if (ReferenceEquals(this, other)) {
|
|
return true;
|
|
}
|
|
|
|
return other.value == this.value;
|
|
}
|
|
|
|
public override bool Equals(object obj) {
|
|
if (ReferenceEquals(null, obj)) {
|
|
return false;
|
|
}
|
|
|
|
if (ReferenceEquals(this, obj)) {
|
|
return true;
|
|
}
|
|
|
|
if (obj.GetType() != this.GetType()) {
|
|
return false;
|
|
}
|
|
|
|
return this.Equals((_MergeableMaterialSliceKey) obj);
|
|
}
|
|
|
|
public static bool operator ==(_MergeableMaterialSliceKey left, _MergeableMaterialSliceKey right) {
|
|
return Equals(left, right);
|
|
}
|
|
|
|
public static bool operator !=(_MergeableMaterialSliceKey left, _MergeableMaterialSliceKey right) {
|
|
return !Equals(left, right);
|
|
}
|
|
|
|
public override int GetHashCode() {
|
|
unchecked {
|
|
var hashCode = this.value.GetHashCode();
|
|
return hashCode;
|
|
}
|
|
}
|
|
|
|
public override string ToString() {
|
|
return "_MergeableMaterialSliceKey(" + this.value + ")";
|
|
}
|
|
}
|
|
|
|
|
|
class _MergeableMaterialListBody : ListBody {
|
|
public _MergeableMaterialListBody(
|
|
List<Widget> children = null,
|
|
Axis mainAxis = Axis.vertical,
|
|
List<MergeableMaterialItem> items = null,
|
|
List<BoxShadow> boxShadows = null
|
|
) : base(children: children, mainAxis: mainAxis) {
|
|
this.items = items;
|
|
this.boxShadows = boxShadows;
|
|
}
|
|
|
|
public readonly List<MergeableMaterialItem> items;
|
|
|
|
public readonly List<BoxShadow> boxShadows;
|
|
|
|
AxisDirection _getDirection(BuildContext context) {
|
|
return AxisDirectionUtils.getAxisDirectionFromAxisReverseAndDirectionality(context, this.mainAxis, false) ??
|
|
AxisDirection.right;
|
|
}
|
|
|
|
public override RenderObject createRenderObject(BuildContext context) {
|
|
return new _RenderMergeableMaterialListBody(
|
|
axisDirection: this._getDirection(context),
|
|
boxShadows: this.boxShadows
|
|
);
|
|
}
|
|
|
|
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
|
|
_RenderMergeableMaterialListBody materialRenderListBody = (_RenderMergeableMaterialListBody) renderObject;
|
|
materialRenderListBody.axisDirection = this._getDirection(context);
|
|
materialRenderListBody.boxShadows = this.boxShadows;
|
|
}
|
|
}
|
|
|
|
|
|
class _RenderMergeableMaterialListBody : RenderListBody {
|
|
public _RenderMergeableMaterialListBody(
|
|
List<RenderBox> children = null,
|
|
AxisDirection axisDirection = AxisDirection.down,
|
|
List<BoxShadow> boxShadows = null
|
|
) : base(children: children, axisDirection: axisDirection) {
|
|
this.boxShadows = boxShadows;
|
|
}
|
|
|
|
public List<BoxShadow> boxShadows;
|
|
|
|
void _paintShadows(Canvas canvas, Rect rect) {
|
|
foreach (BoxShadow boxShadow in this.boxShadows) {
|
|
Paint paint = boxShadow.toPaint();
|
|
canvas.drawRRect(
|
|
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].toRRect(rect), paint);
|
|
}
|
|
}
|
|
|
|
public override void paint(PaintingContext context, Offset offset) {
|
|
RenderBox child = this.firstChild;
|
|
int i = 0;
|
|
|
|
while (child != null) {
|
|
ListBodyParentData childParentData = (ListBodyParentData) child.parentData;
|
|
Rect rect = (childParentData.offset + offset) & child.size;
|
|
if (i % 2 == 0) {
|
|
this._paintShadows(context.canvas, rect);
|
|
}
|
|
|
|
child = childParentData.nextSibling;
|
|
i++;
|
|
}
|
|
|
|
this.defaultPaint(context, offset);
|
|
}
|
|
}
|
|
}
|