assetsGridBuilder method

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

The main grid view builder for assets. 主要的资源查看网格部件

Implementation

@override
Widget assetsGridBuilder(BuildContext context) {
  return Selector<DefaultAssetPickerProvider, AssetPathEntity?>(
    selector: (_, DefaultAssetPickerProvider p) => p.currentPath,
    builder: (BuildContext context, AssetPathEntity? path, __) {
      // First, we need the count of the assets.
      int totalCount = path?.assetCount ?? 0;
      final Widget? specialItem;
      // If user chose a special item's position, add 1 count.
      if (specialItemPosition != SpecialItemPosition.none) {
        specialItem = specialItemBuilder?.call(
          context,
          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 (effectiveShouldRevertGrid && 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 + kToolbarHeight;

      Widget _sliverGrid(BuildContext context, List<AssetEntity> assets) {
        return SliverGrid(
          delegate: SliverChildBuilderDelegate(
            (_, int index) => Builder(
              builder: (BuildContext context) {
                if (effectiveShouldRevertGrid) {
                  if (index < placeholderCount) {
                    return const SizedBox.shrink();
                  }
                  index -= placeholderCount;
                }
                return MergeSemantics(
                  child: Directionality(
                    textDirection: Directionality.of(context),
                    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 c, 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: (_, List<AssetEntity> assets, __) {
                  final SliverGap bottomGap = SliverGap.v(
                    context.bottomPadding + bottomSectionHeight,
                  );
                  return CustomScrollView(
                    physics: const AlwaysScrollableScrollPhysics(),
                    controller: gridScrollController,
                    anchor: effectiveShouldRevertGrid ? anchor : 0,
                    center: effectiveShouldRevertGrid ? gridRevertKey : null,
                    slivers: <Widget>[
                      if (isAppleOS)
                        SliverGap.v(context.topPadding + kToolbarHeight),
                      _sliverGrid(_, assets),
                      // Ignore the gap when the [anchor] is not equal to 1.
                      if (effectiveShouldRevertGrid && anchor == 1) bottomGap,
                      if (effectiveShouldRevertGrid)
                        SliverToBoxAdapter(
                          key: gridRevertKey,
                          child: const SizedBox.shrink(),
                        ),
                      if (isAppleOS && !effectiveShouldRevertGrid) bottomGap,
                    ],
                  );
                },
              ),
            ),
          );
        },
      );
    },
  );
}