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);
}
// Obtain the text direction from the correct context and apply to
// the grid item before it gets manipulated by the grid revert.
final textDirectionCorrection = Directionality.of(context);
Widget sliverGrid(
BuildContext context,
BoxConstraints constraints,
List<AssetEntity> assets,
bool onlyOneScreen,
) {
// Then we use the [totalCount] to calculate placeholders we need.
final placeholderCount = assetsGridItemPlaceholderCount(
context: context,
pathWrapper: wrapper,
onlyOneScreen: onlyOneScreen,
);
return SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, int index) {
if (placeholderCount > 0) {
if (index < placeholderCount) {
return const SizedBox.shrink();
}
index -= placeholderCount;
}
Widget child = assetGridItemBuilder(
context,
index,
assets,
specialItem: specialItem,
);
// Enables drag-to-select.
if (dragToSelect ??
!MediaQuery.accessibleNavigationOf(context)) {
child = GestureDetector(
excludeFromSemantics: true,
onHorizontalDragStart: (d) {
dragSelectCoordinator.onSelectionStart(
context: context,
globalPosition: d.globalPosition,
index: index,
asset: assets[index],
);
},
onHorizontalDragUpdate: (d) {
dragSelectCoordinator.onSelectionUpdate(
context: context,
globalPosition: d.globalPosition,
constraints: constraints,
);
},
onHorizontalDragCancel:
dragSelectCoordinator.resetDraggingStatus,
onHorizontalDragEnd: (d) {
dragSelectCoordinator.onDragEnd(
globalPosition: d.globalPosition,
);
},
onLongPressStart: (d) {
dragSelectCoordinator.onSelectionStart(
context: context,
globalPosition: d.globalPosition,
index: index,
asset: assets[index],
);
},
onLongPressMoveUpdate: (d) {
dragSelectCoordinator.onSelectionUpdate(
context: context,
globalPosition: d.globalPosition,
constraints: constraints,
);
},
onLongPressCancel:
dragSelectCoordinator.resetDraggingStatus,
onLongPressEnd: (d) {
dragSelectCoordinator.onDragEnd(
globalPosition: d.globalPosition,
);
},
onPanStart: (d) {
dragSelectCoordinator.onSelectionStart(
context: context,
globalPosition: d.globalPosition,
index: index,
asset: assets[index],
);
},
onPanUpdate: (d) {
dragSelectCoordinator.onSelectionUpdate(
context: context,
globalPosition: d.globalPosition,
constraints: constraints,
);
},
onPanCancel: dragSelectCoordinator.resetDraggingStatus,
onPanEnd: (d) {
dragSelectCoordinator.onDragEnd(
globalPosition: d.globalPosition,
);
},
child: child,
);
}
return MergeSemantics(
child: Directionality(
textDirection: textDirectionCorrection,
child: child,
),
);
},
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) {
// Calculate rows count.
final int row = (totalCount / gridCount).ceil();
final double itemSize = constraints.maxWidth / gridCount;
// Check whether all rows can be placed at the same time.
final bool onlyOneScreen =
row * (itemSize + itemSpacing) <= constraints.maxHeight;
// 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 = assetGridAnchor(
context: context,
constraints: constraints,
pathWrapper: wrapper,
);
final reverted = gridRevert && !onlyOneScreen;
return Directionality(
textDirection: reverted
? effectiveGridDirection(context)
: Directionality.of(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: anchor,
center:
gridRevert && !onlyOneScreen ? gridRevertKey : null,
slivers: <Widget>[
if (isAppleOS(context))
SliverGap.v(
context.topPadding + appBarPreferredSize!.height,
),
sliverGrid(context, constraints, assets, onlyOneScreen),
// Append the extra bottom padding for Apple OS.
if (anchor == 1 && isAppleOS(context)) bottomGap,
if (gridRevert && !onlyOneScreen)
SliverToBoxAdapter(
key: gridRevertKey,
child: const SizedBox.shrink(),
),
if (!gridRevert && isAppleOS(context)) bottomGap,
],
);
},
),
),
);
},
);
},
);
}