@@ -125,7 +125,7 @@ class PositionedList extends StatefulWidget {
125125 final bool addSemanticIndexes;
126126
127127 /// The amount of space by which to inset the children.
128- final EdgeInsets ? padding;
128+ final EdgeInsetsGeometry ? padding;
129129
130130 /// Whether to wrap each child in a [RepaintBoundary] .
131131 ///
@@ -452,57 +452,85 @@ class _PositionedListState extends State<PositionedList> {
452452 );
453453 }
454454
455- EdgeInsets get _leadingSliverPadding =>
456- (widget.scrollDirection == Axis .vertical
457- ? widget.reverse
458- ? widget.padding? .copyWith (top: 0 )
459- : widget.padding? .copyWith (bottom: 0 )
460- : widget.reverse
461- ? widget.padding? .copyWith (left: 0 )
462- : widget.padding? .copyWith (right: 0 )) ??
455+ EdgeInsets get _resolvedPadding =>
456+ widget.padding
457+ ? .resolve (Directionality .maybeOf (context) ?? TextDirection .ltr) ??
463458 EdgeInsets .zero;
464459
465- EdgeInsets get _centerSliverPadding => widget.scrollDirection == Axis .vertical
466- ? widget.reverse
467- ? widget.padding? .copyWith (
468- top: widget.positionedIndex == widget.itemCount - 1
469- ? widget.padding! .top
470- : 0 ,
471- bottom:
472- widget.positionedIndex == 0 ? widget.padding! .bottom : 0 ,
473- ) ??
474- EdgeInsets .zero
475- : widget.padding? .copyWith (
476- top: widget.positionedIndex == 0 ? widget.padding! .top : 0 ,
477- bottom: widget.positionedIndex == widget.itemCount - 1
478- ? widget.padding! .bottom
479- : 0 ,
480- ) ??
481- EdgeInsets .zero
482- : widget.reverse
483- ? widget.padding? .copyWith (
484- left: widget.positionedIndex == widget.itemCount - 1
485- ? widget.padding! .left
486- : 0 ,
487- right: widget.positionedIndex == 0 ? widget.padding! .right : 0 ,
488- ) ??
489- EdgeInsets .zero
490- : widget.padding? .copyWith (
491- left: widget.positionedIndex == 0 ? widget.padding! .left : 0 ,
492- right: widget.positionedIndex == widget.itemCount - 1
493- ? widget.padding! .right
494- : 0 ,
495- ) ??
496- EdgeInsets .zero;
497-
498- EdgeInsets get _trailingSliverPadding =>
499- widget.scrollDirection == Axis .vertical
500- ? widget.reverse
501- ? widget.padding? .copyWith (bottom: 0 ) ?? EdgeInsets .zero
502- : widget.padding? .copyWith (top: 0 ) ?? EdgeInsets .zero
503- : widget.reverse
504- ? widget.padding? .copyWith (right: 0 ) ?? EdgeInsets .zero
505- : widget.padding? .copyWith (left: 0 ) ?? EdgeInsets .zero;
460+ AxisDirection get _axisDirection {
461+ if (widget.scrollDirection == Axis .vertical) {
462+ return widget.reverse ? AxisDirection .up : AxisDirection .down;
463+ }
464+ final ltr = (Directionality .maybeOf (context) ?? TextDirection .ltr) ==
465+ TextDirection .ltr;
466+ if (widget.reverse) {
467+ return ltr ? AxisDirection .left : AxisDirection .right;
468+ }
469+ return ltr ? AxisDirection .right : AxisDirection .left;
470+ }
471+
472+ EdgeInsets _stripAxisTrailing (EdgeInsets base ) {
473+ switch (_axisDirection) {
474+ case AxisDirection .up:
475+ return base .copyWith (top: 0 );
476+ case AxisDirection .down:
477+ return base .copyWith (bottom: 0 );
478+ case AxisDirection .left:
479+ return base .copyWith (left: 0 );
480+ case AxisDirection .right:
481+ return base .copyWith (right: 0 );
482+ }
483+ }
484+
485+ EdgeInsets _stripAxisLeading (EdgeInsets base ) {
486+ switch (_axisDirection) {
487+ case AxisDirection .up:
488+ return base .copyWith (bottom: 0 );
489+ case AxisDirection .down:
490+ return base .copyWith (top: 0 );
491+ case AxisDirection .left:
492+ return base .copyWith (right: 0 );
493+ case AxisDirection .right:
494+ return base .copyWith (left: 0 );
495+ }
496+ }
497+
498+ EdgeInsets get _leadingSliverPadding => _stripAxisTrailing (_resolvedPadding);
499+
500+ EdgeInsets get _trailingSliverPadding => _stripAxisLeading (_resolvedPadding);
501+
502+ // Center keeps cross-axis padding always; carries the leading/trailing
503+ // edge padding only when it owns the first/last item.
504+ EdgeInsets get _centerSliverPadding {
505+ final resolved = _resolvedPadding;
506+ // Empty list: center is the only sliver in the tree. Drop neither
507+ // edge or the gap would be asymmetric.
508+ if (widget.itemCount == 0 ) return resolved;
509+ final isFirst = widget.positionedIndex == 0 ;
510+ final isLast = widget.positionedIndex == widget.itemCount - 1 ;
511+ switch (_axisDirection) {
512+ case AxisDirection .up:
513+ return resolved.copyWith (
514+ top: isLast ? resolved.top : 0 ,
515+ bottom: isFirst ? resolved.bottom : 0 ,
516+ );
517+ case AxisDirection .down:
518+ return resolved.copyWith (
519+ top: isFirst ? resolved.top : 0 ,
520+ bottom: isLast ? resolved.bottom : 0 ,
521+ );
522+ case AxisDirection .left:
523+ return resolved.copyWith (
524+ left: isLast ? resolved.left : 0 ,
525+ right: isFirst ? resolved.right : 0 ,
526+ );
527+ case AxisDirection .right:
528+ return resolved.copyWith (
529+ left: isFirst ? resolved.left : 0 ,
530+ right: isLast ? resolved.right : 0 ,
531+ );
532+ }
533+ }
506534
507535 void _schedulePositionNotificationUpdate () {
508536 if (! updateScheduled) {
@@ -551,32 +579,36 @@ class _PositionedListState extends State<PositionedList> {
551579 final itemOffset = reveal -
552580 viewport.offset.pixels +
553581 anchor * viewport.size.height;
554- positions.add (ItemPosition (
555- index: key.index,
556- itemLeadingEdge: itemOffset.round () /
557- scrollController.position.viewportDimension,
558- itemTrailingEdge: (itemOffset + box.size.height).round () /
559- scrollController.position.viewportDimension,
560- ));
582+ positions.add (
583+ ItemPosition (
584+ index: key.index,
585+ itemLeadingEdge: itemOffset.round () /
586+ scrollController.position.viewportDimension,
587+ itemTrailingEdge: (itemOffset + box.size.height).round () /
588+ scrollController.position.viewportDimension,
589+ ),
590+ );
561591 } else {
562592 final itemOffset =
563593 box.localToGlobal (Offset .zero, ancestor: viewport).dx;
564594 if (! itemOffset.isFinite) continue ;
565- positions.add (ItemPosition (
566- index: key.index,
567- itemLeadingEdge: (widget.reverse
568- ? scrollController.position.viewportDimension -
569- (itemOffset + box.size.width)
570- : itemOffset)
571- .round () /
572- scrollController.position.viewportDimension,
573- itemTrailingEdge: (widget.reverse
574- ? scrollController.position.viewportDimension -
575- itemOffset
576- : (itemOffset + box.size.width))
577- .round () /
578- scrollController.position.viewportDimension,
579- ));
595+ final viewportDimension =
596+ scrollController.position.viewportDimension;
597+ // Branch on the resolved axis direction so RTL is handled.
598+ final isRight = _axisDirection == AxisDirection .right;
599+ final leadingPx = isRight
600+ ? itemOffset
601+ : viewportDimension - (itemOffset + box.size.width);
602+ final trailingPx = isRight
603+ ? itemOffset + box.size.width
604+ : viewportDimension - itemOffset;
605+ positions.add (
606+ ItemPosition (
607+ index: key.index,
608+ itemLeadingEdge: leadingPx.round () / viewportDimension,
609+ itemTrailingEdge: trailingPx.round () / viewportDimension,
610+ ),
611+ );
580612 }
581613 } on TypeError catch (_) {
582614 // Specifically the null-check failure inside
0 commit comments