我需要在底部显示一个“购物车”图标,并显示其中的许多物品。问题是我不能将数字标签放置得足够高。它受到其父约束的限制。屏幕截图演示了它
按钮本身是Column小部件,在其顶部具有Frare动画“ wave” actor,在其下方有一个堆栈(绿线下方) 这就是将标签上移的结果:
标签本身被剪裁,并且波浪以某种方式消失。 我试图将堆栈包装在LimitedBox,OverflowBox,SizedBox中,但是都不能解决问题。
这是我想要的(理想情况下):
将父级的原始位置和大小留给父级,但在子级之外显示一部分子级
这是按钮类的完整代码(计数器是通过_getCounter()方法创建的):
class BottomBarButton extends StatefulWidget {
BottomBarMenuItemModel itemModel;
final double barHeight;
BottomBarButton(this.itemModel, this.barHeight);
@override
_BottomBarButtonState createState() => _BottomBarButtonState();
}
class _BottomBarButtonState extends State<BottomBarButton> with SingleTickerProviderStateMixin {
AnimationController _scaleController;
Animation<double> _scaleTween;
Animation<Color> _colorTween;
Animation<Color> _reversedColorTween;
StreamSubscription<String> _streamSubscription;
StreamSubscription<String> _counterSubscription;
String _inactiveAnimation = 'idle';
@override
void initState() {
_streamSubscription = Dispatch().onChangeBottomBar.stream.listen((menuId) {
if (widget.itemModel.id == menuId) {
return;
}
setState(() {});
});
_scaleController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 250)
);
_scaleTween = Tween(begin: 1.0, end: 1.2).animate(
CurvedAnimation(
parent: _scaleController,
curve: Curves.bounceInOut
)
);
_colorTween = ColorTween(begin: pizzaBottomBarIconNormalColor, end: pizzaYellow).animate(
CurvedAnimation(parent: _scaleController, curve: Curves.bounceInOut)
);
_reversedColorTween = ColorTween(begin: pizzaYellow, end: pizzaBottomBarIconNormalColor).animate(
CurvedAnimation(parent: _scaleController, curve: Curves.bounceInOut)
);
DataStore().onCartDataChange.stream.listen((newCounter) {
setState(() {});
});
super.initState();
}
@override
void dispose() {
_scaleController?.dispose();
_streamSubscription.cancel();
_counterSubscription.cancel();
super.dispose();
}
Widget _getCounter() {
if (widget.itemModel.id == Dispatch.CartMenu) {
var itemsInCart = DataStore().cartData.length;
if (itemsInCart > 0) {
return AnimatedBuilder(
animation: _scaleTween,
builder: (c, w) {
return Positioned(
right: 25 / _scaleTween.value,
top: -15 + (20 / _scaleTween.value),
child: AnimatedBuilder(
animation: _colorTween,
builder: (c, w) {
return Container(
width: 20,
height: 20,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _reversedColorTween.value,
),
child: Text(
itemsInCart.toString(),
textAlign: TextAlign.center,
style: TextStyle(
color: pizzaBottomBarColor,
fontFamily: "OpenSans",
fontWeight: FontWeight.w500
),
),
);
},
),
);
},
);
}
}
return Container();
}
@override
Widget build(BuildContext context) {
widget.itemModel.isActive
? _scaleController.forward()
: _scaleController.reverse();
var animationName = widget.itemModel.isActive ? 'jump_in' : _inactiveAnimation;
return Expanded(
child: GestureDetector(
onTap: () {
setState(() {
// нужно чтобы при первом рендере не запускать все анимации, а врубить айдл
_inactiveAnimation = 'jump_out';
animationName = widget.itemModel.isActive ? 'jump_in' : _inactiveAnimation;
Dispatch().selectMenu(widget.itemModel.id);
// print(widget.itemModel.id);
});
},
child: AbsorbPointer(
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container( // выпрыгивающаяя волна сверху
// анимацию надо сдвинуть на 20 пиеселей вверх,
// чтобы учесть пространство
// для выпрыгивающей части
transform: Matrix4.translationValues(0, -20, 0),
alignment: Alignment.bottomCenter,
height: 20,
width: double.infinity,
child: FlareActor(
"assets/anim/bottom_bar_jumpy_button.flr",
alignment: Alignment.bottomCenter,
fit: BoxFit.fitWidth,
animation: animationName,
shouldClip: false,
)
),
ScaleTransition(
scale: _scaleTween,
child: Container(
// неанимированная иконка
alignment: Alignment.center,
child: AnimatedBuilder(
animation: _colorTween,
builder: (context, w) {
return Icon(
widget.itemModel.iconData,
size: 20,
color: _colorTween.value,
);
},
),
height: widget.barHeight - 22,
),
),
_getCounter(),
],
),
ScaleTransition(
// текст кнопок в нижнем баре
scale: _scaleTween,
alignment: FractionalOffset.topCenter, // пивот по верхней кромке
child: Transform(
transform: Matrix4.translationValues(0, -6, 0),
child: AnimatedBuilder(
animation: _colorTween,
builder: (context, w) {
return Padding(
padding: const EdgeInsets.only(top: 7.0),
child: Text(widget.itemModel.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: 'OpenSans',
fontWeight: FontWeight.w500,
fontSize: 13,
height: 1,
color: _colorTween.value
),
),
);
},
),
),
)
],
),
),
),
);
}
}
答案 0 :(得分:1)
我认为您可以通过使用
解决此问题overflow:Overflow.visible,
在堆栈内部。 因此,您的代码将类似于:
Stack(
overflow: Overflow.visible,
children: [
/* Your children*/
],
)
答案 1 :(得分:0)
一些魔术发生了。我已经为此苦苦挣扎了几个小时,但是在创建了这个主题之后的几分钟内,我想出了一个解决方案。 因此,可以使用Transform小部件很容易地解决它。 就是这样:
Widget _getCounter() {
if (widget.itemModel.id == Dispatch.CartMenu) {
var itemsInCart = DataStore().cartData.length;
if (itemsInCart > 0) {
return AnimatedBuilder(
animation: _scaleTween,
builder: (c, w) {
return Transform(
transform: Matrix4.translationValues(
45 + (5 * _scaleTween.value),
6 - (6 * _scaleTween.value), 0
),
child: AnimatedBuilder(
animation: _colorTween,
builder: (c, w) {
return Container(
width: 20,
height: 20,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _reversedColorTween.value,
),
child: Text(
itemsInCart.toString(),
textAlign: TextAlign.center,
style: TextStyle(
color: pizzaBottomBarColor,
fontFamily: "OpenSans",
fontWeight: FontWeight.w500
),
),
);
},
),
);
},
);
}
}
return Container();
}
答案 2 :(得分:0)
请勿使用overflow
,现在已弃用。请改用clipBehavior
。
Stack(
clipBehavior: Clip.none, // This is what you need.
children: [],
)