@@ -758,26 +758,39 @@ class DefaultAssetPickerBuilderDelegate
758
758
@override
759
759
Widget assetsGridBuilder (BuildContext context) {
760
760
// First, we need the count of the assets.
761
- final int totalCount = provider.currentPathEntity! .assetCount;
762
- // Then we use the total count to calculate how many placeholders we need.
763
- final int _placeholderCount;
764
- if (isAppleOS) {
765
- _placeholderCount =
766
- totalCount % gridCount == 0 ? 0 : gridCount - totalCount % gridCount;
761
+ int totalCount = provider.currentPathEntity! .assetCount;
762
+ // If user chose a special item's position, add 1 count.
763
+ if (specialItemPosition != SpecialItemPosition .none) {
764
+ totalCount += 1 ;
765
+ }
766
+ // Then we use the [totalCount] to calculate how many placeholders we need.
767
+ final int placeholderCount;
768
+ if (isAppleOS && totalCount % gridCount != 0 ) {
769
+ // When there are left items that not filled into one row, filled the row
770
+ // with placeholders.
771
+ placeholderCount = gridCount - totalCount % gridCount;
767
772
} else {
768
- _placeholderCount = 0 ;
773
+ // Otherwise, we don't need placeholders.
774
+ placeholderCount = 0 ;
769
775
}
770
-
771
- Widget _sliverGrid (BuildContext c, List <AssetEntity > assets) {
776
+ // Calculate rows count.
777
+ final int row = (totalCount + placeholderCount) ~ / gridCount;
778
+ // Here we got a magic calculation. [itemSpacing] needs to be divided by
779
+ // [gridCount] since every grid item is squeezed by the [itemSpacing],
780
+ // and it's actual size is reduced with [itemSpacing / gridCount].
781
+ final double dividedSpacing = itemSpacing / gridCount;
782
+ final double topPadding = context.mediaQuery.padding.top + kToolbarHeight;
783
+
784
+ Widget _sliverGrid (BuildContext ctx, List <AssetEntity > assets) {
772
785
return SliverGrid (
773
786
delegate: SliverChildBuilderDelegate (
774
787
(_, int index) => Builder (
775
788
builder: (BuildContext c) {
776
789
if (isAppleOS) {
777
- if (index < _placeholderCount ) {
790
+ if (index < placeholderCount ) {
778
791
return const SizedBox .shrink ();
779
792
}
780
- index -= _placeholderCount ;
793
+ index -= placeholderCount ;
781
794
}
782
795
return Directionality (
783
796
textDirection: Directionality .of (context),
@@ -786,16 +799,16 @@ class DefaultAssetPickerBuilderDelegate
786
799
},
787
800
),
788
801
childCount: assetsGridItemCount (
789
- context: c ,
802
+ context: ctx ,
790
803
assets: assets,
791
- placeholderCount: _placeholderCount ,
804
+ placeholderCount: placeholderCount ,
792
805
),
793
806
findChildIndexCallback: (Key ? key) {
794
807
if (key is ValueKey <String >) {
795
808
return findChildIndexBuilder (
796
809
id: key.value,
797
810
assets: assets,
798
- placeholderCount: _placeholderCount ,
811
+ placeholderCount: placeholderCount ,
799
812
);
800
813
}
801
814
return null ;
@@ -811,24 +824,16 @@ class DefaultAssetPickerBuilderDelegate
811
824
812
825
return LayoutBuilder (
813
826
builder: (BuildContext c, BoxConstraints constraints) {
814
- final double topPadding = c.mediaQuery.padding.top + kToolbarHeight;
815
- final double bottomPadding =
816
- c.mediaQuery.padding.bottom + bottomActionBarHeight;
817
- final double verticalPadding = topPadding + bottomPadding;
818
-
819
- final int _count = totalCount + _placeholderCount;
820
- final double _wWidth = constraints.maxWidth;
821
- final double _wHeight = constraints.maxHeight - topPadding;
822
- final double _itemSize = _wWidth / gridCount;
823
- final double anchor;
824
- if (_count <= gridCount) {
825
- anchor = verticalPadding / _wHeight;
826
- } else {
827
- anchor = math.min (
828
- _count ~ / gridCount * _itemSize / _wHeight,
829
- 1 ,
830
- );
831
- }
827
+ final double _itemSize = constraints.maxWidth / gridCount;
828
+ // Use [ScrollView.anchor] to determine where is the first place of
829
+ // the [SliverGrid]. Each row needs [dividedSpacing] to calculate,
830
+ // then minus one times of [itemSpacing] because spacing's count in the
831
+ // cross axis is always less than the rows.
832
+ final double anchor = math.min (
833
+ (row * (_itemSize + dividedSpacing) + topPadding - itemSpacing) /
834
+ constraints.maxHeight,
835
+ 1 ,
836
+ );
832
837
833
838
return Directionality (
834
839
textDirection: effectiveGridDirection (context),
@@ -837,29 +842,29 @@ class DefaultAssetPickerBuilderDelegate
837
842
child: Selector <DefaultAssetPickerProvider , List <AssetEntity >>(
838
843
selector: (_, DefaultAssetPickerProvider provider) =>
839
844
provider.currentAssets,
840
- builder: (BuildContext c , List <AssetEntity > assets, __) {
841
- return CustomScrollView (
842
- physics : const AlwaysScrollableScrollPhysics () ,
843
- controller : gridScrollController ,
844
- anchor : isAppleOS ? anchor : 0 ,
845
- center : isAppleOS ? _gridRevertKey : null ,
846
- slivers : < Widget > [
847
- if (isAppleOS)
848
- SliverToBoxAdapter (
849
- child : SizedBox (
850
- height :
851
- context.mediaQuery.padding.top + kToolbarHeight,
852
- ),
853
- ),
854
- _sliverGrid (c, assets) ,
855
- if (isAppleOS)
856
- SliverToBoxAdapter (
857
- key : _gridRevertKey,
858
- child : const SizedBox . shrink () ,
859
- ),
860
- ] ,
861
- );
862
- } ,
845
+ builder: (_ , List <AssetEntity > assets, __) => CustomScrollView (
846
+ physics : const AlwaysScrollableScrollPhysics (),
847
+ controller : gridScrollController ,
848
+ anchor : isAppleOS ? anchor : 0 ,
849
+ center : isAppleOS ? _gridRevertKey : null ,
850
+ slivers : < Widget > [
851
+ if (isAppleOS)
852
+ SliverGap . v (
853
+ context.mediaQuery.padding.top + kToolbarHeight,
854
+ ),
855
+ _sliverGrid (_, assets),
856
+ // Ignore the gap when the [anchor] is not equal to 1.
857
+ if (isAppleOS && anchor == 1 )
858
+ SliverGap . v (
859
+ context.mediaQuery.padding.bottom + bottomActionBarHeight ,
860
+ ),
861
+ if (isAppleOS)
862
+ SliverToBoxAdapter (
863
+ key : _gridRevertKey ,
864
+ child : const SizedBox . shrink ( ),
865
+ ) ,
866
+ ],
867
+ ) ,
863
868
),
864
869
),
865
870
);
0 commit comments