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