assetsGridBuilder method

  1. @override
Widget assetsGridBuilder(
  1. BuildContext context
)
override

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,
                    ],
                  );
                },
              ),
            ),
          );
        },
      );
    },
  );
}