Skip to content

Commit e3ba6c7

Browse files
authored
🐛 Fix grid count calculate issue when switching between folders (#179)
1 parent 07e22d6 commit e3ba6c7

File tree

1 file changed

+121
-114
lines changed

1 file changed

+121
-114
lines changed

lib/src/delegates/asset_picker_builder_delegate.dart

Lines changed: 121 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -804,125 +804,132 @@ class DefaultAssetPickerBuilderDelegate
804804

805805
@override
806806
Widget assetsGridBuilder(BuildContext context) {
807-
// First, we need the count of the assets.
808-
int totalCount = provider.currentPathEntity!.assetCount;
809-
// If user chose a special item's position, add 1 count.
810-
if (specialItemPosition != SpecialItemPosition.none) {
811-
totalCount += 1;
812-
}
813-
// Then we use the [totalCount] to calculate how many placeholders we need.
814-
final int placeholderCount;
815-
if (isAppleOS && totalCount % gridCount != 0) {
816-
// When there are left items that not filled into one row, filled the row
817-
// with placeholders.
818-
placeholderCount = gridCount - totalCount % gridCount;
819-
} else {
820-
// Otherwise, we don't need placeholders.
821-
placeholderCount = 0;
822-
}
823-
// Calculate rows count.
824-
final int row = (totalCount + placeholderCount) ~/ gridCount;
825-
// Here we got a magic calculation. [itemSpacing] needs to be divided by
826-
// [gridCount] since every grid item is squeezed by the [itemSpacing],
827-
// and it's actual size is reduced with [itemSpacing / gridCount].
828-
final double dividedSpacing = itemSpacing / gridCount;
829-
final double topPadding = context.topPadding + kToolbarHeight;
830-
831-
Widget _sliverGrid(BuildContext ctx, List<AssetEntity> assets) {
832-
return SliverGrid(
833-
delegate: SliverChildBuilderDelegate(
834-
(_, int index) => Builder(
835-
builder: (BuildContext c) {
836-
if (isAppleOS) {
837-
if (index < placeholderCount) {
838-
return const SizedBox.shrink();
839-
}
840-
index -= placeholderCount;
841-
}
842-
return Directionality(
843-
textDirection: Directionality.of(context),
844-
child: assetGridItemBuilder(c, index, assets),
845-
);
846-
},
847-
),
848-
childCount: assetsGridItemCount(
849-
context: ctx,
850-
assets: assets,
851-
placeholderCount: placeholderCount,
852-
),
853-
findChildIndexCallback: (Key? key) {
854-
if (key is ValueKey<String>) {
855-
return findChildIndexBuilder(
856-
id: key.value,
807+
return Selector<DefaultAssetPickerProvider, AssetPathEntity?>(
808+
selector: (_, DefaultAssetPickerProvider p) => p.currentPathEntity,
809+
builder: (_, AssetPathEntity? path, __) {
810+
// First, we need the count of the assets.
811+
int totalCount = provider.currentPathEntity!.assetCount;
812+
// If user chose a special item's position, add 1 count.
813+
if (specialItemPosition != SpecialItemPosition.none) {
814+
totalCount += 1;
815+
}
816+
// Then we use the [totalCount] to calculate how many placeholders we need.
817+
final int placeholderCount;
818+
if (isAppleOS && totalCount % gridCount != 0) {
819+
// When there are left items that not filled into one row, filled the row
820+
// with placeholders.
821+
placeholderCount = gridCount - totalCount % gridCount;
822+
} else {
823+
// Otherwise, we don't need placeholders.
824+
placeholderCount = 0;
825+
}
826+
// Calculate rows count.
827+
final int row = (totalCount + placeholderCount) ~/ gridCount;
828+
// Here we got a magic calculation. [itemSpacing] needs to be divided by
829+
// [gridCount] since every grid item is squeezed by the [itemSpacing],
830+
// and it's actual size is reduced with [itemSpacing / gridCount].
831+
final double dividedSpacing = itemSpacing / gridCount;
832+
final double topPadding = context.topPadding + kToolbarHeight;
833+
834+
Widget _sliverGrid(BuildContext ctx, List<AssetEntity> assets) {
835+
return SliverGrid(
836+
delegate: SliverChildBuilderDelegate(
837+
(_, int index) => Builder(
838+
builder: (BuildContext c) {
839+
if (isAppleOS) {
840+
if (index < placeholderCount) {
841+
return const SizedBox.shrink();
842+
}
843+
index -= placeholderCount;
844+
}
845+
return Directionality(
846+
textDirection: Directionality.of(context),
847+
child: assetGridItemBuilder(c, index, assets),
848+
);
849+
},
850+
),
851+
childCount: assetsGridItemCount(
852+
context: ctx,
857853
assets: assets,
858854
placeholderCount: placeholderCount,
859-
);
860-
}
861-
return null;
862-
},
863-
),
864-
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
865-
crossAxisCount: gridCount,
866-
mainAxisSpacing: itemSpacing,
867-
crossAxisSpacing: itemSpacing,
868-
),
869-
);
870-
}
871-
872-
return LayoutBuilder(
873-
builder: (BuildContext c, BoxConstraints constraints) {
874-
final double itemSize = constraints.maxWidth / gridCount;
875-
// Check whether all rows can be placed at the same time.
876-
final bool onlyOneScreen = row * itemSize <=
877-
constraints.maxHeight -
878-
context.bottomPadding -
879-
topPadding -
880-
permissionLimitedBarHeight;
881-
final double height;
882-
if (onlyOneScreen) {
883-
height = constraints.maxHeight;
884-
} else {
885-
// Reduce [permissionLimitedBarHeight] for the final height.
886-
height = constraints.maxHeight - permissionLimitedBarHeight;
855+
),
856+
findChildIndexCallback: (Key? key) {
857+
if (key is ValueKey<String>) {
858+
return findChildIndexBuilder(
859+
id: key.value,
860+
assets: assets,
861+
placeholderCount: placeholderCount,
862+
);
863+
}
864+
return null;
865+
},
866+
),
867+
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
868+
crossAxisCount: gridCount,
869+
mainAxisSpacing: itemSpacing,
870+
crossAxisSpacing: itemSpacing,
871+
),
872+
);
887873
}
888-
// Use [ScrollView.anchor] to determine where is the first place of
889-
// the [SliverGrid]. Each row needs [dividedSpacing] to calculate,
890-
// then minus one times of [itemSpacing] because spacing's count in the
891-
// cross axis is always less than the rows.
892-
final double anchor = math.min(
893-
(row * (itemSize + dividedSpacing) + topPadding - itemSpacing) /
894-
height,
895-
1,
896-
);
897874

898-
return Directionality(
899-
textDirection: effectiveGridDirection(context),
900-
child: ColoredBox(
901-
color: theme.canvasColor,
902-
child: Selector<DefaultAssetPickerProvider, List<AssetEntity>>(
903-
selector: (_, DefaultAssetPickerProvider provider) =>
904-
provider.currentAssets,
905-
builder: (_, List<AssetEntity> assets, __) => CustomScrollView(
906-
physics: const AlwaysScrollableScrollPhysics(),
907-
controller: gridScrollController,
908-
anchor: isAppleOS ? anchor : 0,
909-
center: isAppleOS ? gridRevertKey : null,
910-
slivers: <Widget>[
911-
if (isAppleOS)
912-
SliverGap.v(context.topPadding + kToolbarHeight),
913-
_sliverGrid(_, assets),
914-
// Ignore the gap when the [anchor] is not equal to 1.
915-
if (isAppleOS && anchor == 1)
916-
SliverGap.v(context.bottomPadding + bottomSectionHeight),
917-
if (isAppleOS)
918-
SliverToBoxAdapter(
919-
key: gridRevertKey,
920-
child: const SizedBox.shrink(),
921-
),
922-
],
875+
return LayoutBuilder(
876+
builder: (BuildContext c, BoxConstraints constraints) {
877+
final double itemSize = constraints.maxWidth / gridCount;
878+
// Check whether all rows can be placed at the same time.
879+
final bool onlyOneScreen = row * itemSize <=
880+
constraints.maxHeight -
881+
context.bottomPadding -
882+
topPadding -
883+
permissionLimitedBarHeight;
884+
final double height;
885+
if (onlyOneScreen) {
886+
height = constraints.maxHeight;
887+
} else {
888+
// Reduce [permissionLimitedBarHeight] for the final height.
889+
height = constraints.maxHeight - permissionLimitedBarHeight;
890+
}
891+
// Use [ScrollView.anchor] to determine where is the first place of
892+
// the [SliverGrid]. Each row needs [dividedSpacing] to calculate,
893+
// then minus one times of [itemSpacing] because spacing's count in the
894+
// cross axis is always less than the rows.
895+
final double anchor = math.min(
896+
(row * (itemSize + dividedSpacing) + topPadding - itemSpacing) /
897+
height,
898+
1,
899+
);
900+
901+
return Directionality(
902+
textDirection: effectiveGridDirection(context),
903+
child: ColoredBox(
904+
color: theme.canvasColor,
905+
child: Selector<DefaultAssetPickerProvider, List<AssetEntity>>(
906+
selector: (_, DefaultAssetPickerProvider provider) =>
907+
provider.currentAssets,
908+
builder: (_, List<AssetEntity> assets, __) =>
909+
CustomScrollView(
910+
physics: const AlwaysScrollableScrollPhysics(),
911+
controller: gridScrollController,
912+
anchor: isAppleOS ? anchor : 0,
913+
center: isAppleOS ? gridRevertKey : null,
914+
slivers: <Widget>[
915+
if (isAppleOS)
916+
SliverGap.v(context.topPadding + kToolbarHeight),
917+
_sliverGrid(_, assets),
918+
// Ignore the gap when the [anchor] is not equal to 1.
919+
if (isAppleOS && anchor == 1)
920+
SliverGap.v(
921+
context.bottomPadding + bottomSectionHeight),
922+
if (isAppleOS)
923+
SliverToBoxAdapter(
924+
key: gridRevertKey,
925+
child: const SizedBox.shrink(),
926+
),
927+
],
928+
),
929+
),
923930
),
924-
),
925-
),
931+
);
932+
},
926933
);
927934
},
928935
);

0 commit comments

Comments
 (0)