From 4eae7e698f8cdb2851bc58095b7cb80403634014 Mon Sep 17 00:00:00 2001 From: dom Date: Mon, 19 Jan 2026 13:43:57 +0800 Subject: [PATCH] opt live border indicator Signed-off-by: dom --- lib/pages/live_room/view.dart | 106 ++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 29 deletions(-) diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 40decd70c..9004fef17 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -901,30 +901,18 @@ class _LiveRoomPageState extends State if (_liveRoomController.showSuperChat) { return Stack( children: [ + child, Positioned( left: 0, top: 0, right: 0, - child: Obx(() { - return ClipRect( - clipper: _BorderClipper( - _liveRoomController.pageIndex.value == 0, - ), - child: const DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), - ), - border: Border( - top: BorderSide(color: Colors.white38), - ), - ), - child: SizedBox(width: double.infinity, height: 20), - ), - ); - }), + child: Obx( + () => _BorderIndicator( + radius: const Radius.circular(20), + isLeft: _liveRoomController.pageIndex.value == 0, + ), + ), ), - child, ], ); } @@ -957,27 +945,87 @@ class _LiveRoomPageState extends State }); } -class _BorderClipper extends CustomClipper { - _BorderClipper(this.isLeft); +class _BorderIndicator extends LeafRenderObjectWidget { + const _BorderIndicator({ + required this.radius, + required this.isLeft, + }); + final Radius radius; final bool isLeft; @override - Rect getClip(Size size) { - return Rect.fromLTRB( - isLeft ? 0 : size.width / 2, - 0, - isLeft ? size.width / 2 : size.width, - size.height, + RenderObject createRenderObject(BuildContext context) { + return RenderBorderIndicator( + radius: radius, + isLeft: isLeft, ); } @override - bool shouldReclip(_BorderClipper oldClipper) { - return isLeft != oldClipper.isLeft; + void updateRenderObject( + BuildContext context, + RenderBorderIndicator renderObject, + ) { + renderObject + ..radius = radius + ..isLeft = isLeft; } } +class RenderBorderIndicator extends RenderBox { + RenderBorderIndicator({ + required Radius radius, + required bool isLeft, + }) : _radius = radius, + _isLeft = isLeft; + + Radius _radius; + Radius get radius => _radius; + set radius(Radius value) { + if (_radius == value) return; + _radius = value; + markNeedsLayout(); + } + + bool _isLeft; + bool get isLeft => _isLeft; + set isLeft(bool value) { + if (_isLeft == value) return; + _isLeft = value; + markNeedsPaint(); + } + + @override + void performLayout() { + size = constraints.constrain(Size(constraints.maxWidth, _radius.x)); + } + + @override + void paint(PaintingContext context, Offset offset) { + final size = this.size; + final canvas = context.canvas; + final width = size.width / 2; + if (!_isLeft) { + canvas.translate(width, 0); + } + BoxBorder.paintNonUniformBorder( + canvas, + Rect.fromLTWH(0, 0, width, size.height), + borderRadius: BorderRadius.only( + topLeft: _isLeft ? _radius : .zero, + topRight: _isLeft ? .zero : _radius, + ), + textDirection: null, + top: const BorderSide(), + color: Colors.white38, + ); + } + + @override + bool get isRepaintBoundary => true; +} + class LiveDanmaku extends StatefulWidget { final LiveRoomController liveRoomController; final PlPlayerController plPlayerController;