assetsGridBuilder method
The main grid view builder for assets. 主要的资源查看网格部件
Implementation
@override
Widget assetsGridBuilder(BuildContext context) {
appBarPreferredSize ??= appBar(context).preferredSize;
final bool gridRevert = effectiveShouldRevertGrid(context);
return Selector<DefaultAssetPickerProvider, PathWrapper<AssetPathEntity>?>(
selector: (_, DefaultAssetPickerProvider p) => p.currentPath,
builder: (context, wrapper, _) {
// First, we need the count of the assets.
int totalCount = wrapper?.assetCount ?? 0;
final Widget? specialItem;
// If user chose a special item's position, add 1 count.
if (specialItemPosition != SpecialItemPosition.none) {
specialItem = specialItemBuilder?.call(
context,
wrapper?.path,
totalCount,
);
if (specialItem != null) {
totalCount += 1;
}
} else {
specialItem = null;
}
if (totalCount == 0 && specialItem == null) {
return loadingIndicator(context);
}
// Then we use the [totalCount] to calculate placeholders we need.
final int placeholderCount;
if (gridRevert && totalCount % gridCount != 0) {
// When there are left items that not filled into one row,
// filled the row with placeholders.
placeholderCount = gridCount - totalCount % gridCount;
} else {
// Otherwise, we don't need placeholders.
placeholderCount = 0;
}
// Calculate rows count.
final int row = (totalCount + placeholderCount) ~/ gridCount;
// Here we got a magic calculation. [itemSpacing] needs to be divided by
// [gridCount] since every grid item is squeezed by the [itemSpacing],
// and it's actual size is reduced with [itemSpacing / gridCount].
final double dividedSpacing = itemSpacing / gridCount;
final double topPadding =
context.topPadding + appBarPreferredSize!.height;
final textDirection = Directionality.of(context);
Widget sliverGrid(BuildContext context, List<AssetEntity> assets) {
return SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, int index) {
if (gridRevert) {
if (index < placeholderCount) {
return const SizedBox.shrink();
}
index -= placeholderCount;
}
return MergeSemantics(
child: Directionality(
textDirection: textDirection,
child: assetGridItemBuilder(
context,
index,
assets,
specialItem: specialItem,
),
),
);
},
childCount: assetsGridItemCount(
context: context,
assets: assets,
placeholderCount: placeholderCount,
specialItem: specialItem,
),
findChildIndexCallback: (Key? key) {
if (key is ValueKey<String>) {
return findChildIndexBuilder(
id: key.value,
assets: assets,
placeholderCount: placeholderCount,
);
}
return null;
},
// Explicitly disable semantic indexes for custom usage.
addSemanticIndexes: false,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: gridCount,
mainAxisSpacing: itemSpacing,
crossAxisSpacing: itemSpacing,
),
);
}
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final double itemSize = constraints.maxWidth / gridCount;
// Check whether all rows can be placed at the same time.
final bool onlyOneScreen = row * itemSize <=
constraints.maxHeight -
context.bottomPadding -
topPadding -
permissionLimitedBarHeight;
final double height;
if (onlyOneScreen) {
height = constraints.maxHeight;
} else {
// Reduce [permissionLimitedBarHeight] for the final height.
height = constraints.maxHeight - permissionLimitedBarHeight;
}
// Use [ScrollView.anchor] to determine where is the first place of
// the [SliverGrid]. Each row needs [dividedSpacing] to calculate,
// then minus one times of [itemSpacing] because spacing's count in the
// cross axis is always less than the rows.
final double anchor = math.min(
(row * (itemSize + dividedSpacing) + topPadding - itemSpacing) /
height,
1,
);
return Directionality(
textDirection: effectiveGridDirection(context),
child: ColoredBox(
color: theme.canvasColor,
child: Selector<DefaultAssetPickerProvider, List<AssetEntity>>(
selector: (_, DefaultAssetPickerProvider p) =>
p.currentAssets,
builder: (BuildContext context, List<AssetEntity> assets, _) {
final SliverGap bottomGap = SliverGap.v(
context.bottomPadding + bottomSectionHeight,
);
appBarPreferredSize ??= appBar(context).preferredSize;
return CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
controller: gridScrollController,
anchor: gridRevert ? anchor : 0,
center: gridRevert ? gridRevertKey : null,
slivers: <Widget>[
if (isAppleOS(context))
SliverGap.v(
context.topPadding + appBarPreferredSize!.height,
),
sliverGrid(context, assets),
// Ignore the gap when the [anchor] is not equal to 1.
if (gridRevert && anchor == 1) bottomGap,
if (gridRevert)
SliverToBoxAdapter(
key: gridRevertKey,
child: const SizedBox.shrink(),
),
if (isAppleOS(context) && !gridRevert) bottomGap,
],
);
},
),
),
);
},
);
},
);
}