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.currentPathEntity,
    builder: (_, AssetPathEntity? path, __) {
      // First, we need the count of the assets.
      int totalCount = path?.assetCount ?? 0;
      // If user chose a special item's position, add 1 count.
      if (specialItemPosition != SpecialItemPosition.none &&
          path?.isAll == true) {
        totalCount += 1;
      }
      // 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 ctx, List<AssetEntity> assets) {
        return SliverGrid(
          delegate: SliverChildBuilderDelegate(
            (_, int index) => Builder(
              builder: (BuildContext c) {
                if (effectiveShouldRevertGrid) {
                  if (index < placeholderCount) {
                    return const SizedBox.shrink();
                  }
                  index -= placeholderCount;
                }
                return Directionality(
                  textDirection: Directionality.of(context),
                  child: assetGridItemBuilder(c, index, assets),
                );
              },
            ),
            childCount: assetsGridItemCount(
              context: ctx,
              assets: assets,
              placeholderCount: placeholderCount,
            ),
            findChildIndexCallback: (Key? key) {
              if (key is ValueKey<String>) {
                return findChildIndexBuilder(
                  id: key.value,
                  assets: assets,
                  placeholderCount: placeholderCount,
                );
              }
              return null;
            },
          ),
          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,
                    ],
                  );
                },
              ),
            ),
          );
        },
      );
    },
  );
}