Skip to content

Commit 8f9faec

Browse files
authored
♻️ Split AssetGridItemBuilder to solve the rebuild issue (#128)
1 parent f270f91 commit 8f9faec

File tree

6 files changed

+179
-103
lines changed

6 files changed

+179
-103
lines changed

example/lib/constants/picker_method.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ class PickMethod {
178178
requestType: RequestType.common,
179179
specialItemPosition: SpecialItemPosition.prepend,
180180
specialItemBuilder: (BuildContext context) {
181-
return const Center(child: Text('Custom Widget'));
181+
return const Center(
182+
child: Text('Custom Widget', textAlign: TextAlign.center),
183+
);
182184
},
183185
);
184186
},

lib/src/delegates/asset_picker_builder_delegate.dart

Lines changed: 97 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import 'dart:ui' as ui;
99

1010
import 'package:flutter/material.dart';
1111
import 'package:flutter/services.dart';
12-
import 'package:extended_image/extended_image.dart';
1312

1413
import '../constants/constants.dart';
14+
import '../widget/builder/asset_entity_grid_item_builder.dart';
1515

1616
typedef IndicatorBuilder = Widget Function(
1717
BuildContext context,
@@ -257,25 +257,41 @@ abstract class AssetPickerBuilderDelegate<A, P> {
257257
child: Selector<AssetPickerProvider<A, P>, List<A>>(
258258
selector: (_, AssetPickerProvider<A, P> provider) =>
259259
provider.currentAssets,
260-
builder: (_, List<A> currentAssets, __) => GridView.builder(
261-
controller: gridScrollController,
262-
padding: isAppleOS
263-
? EdgeInsetsDirectional.only(
260+
builder: (_, List<A> currentAssets, __) => CustomScrollView(
261+
slivers: <Widget>[
262+
if (isAppleOS)
263+
SliverPadding(
264+
padding: EdgeInsetsDirectional.only(
264265
top: Screens.topSafeHeight + kToolbarHeight,
266+
),
267+
),
268+
SliverGrid(
269+
delegate: SliverChildBuilderDelegate(
270+
(_, int index) => Builder(
271+
key: ValueKey<int>(index),
272+
builder: (BuildContext c) => assetGridItemBuilder(
273+
c,
274+
index,
275+
currentAssets,
276+
),
277+
),
278+
childCount: assetsGridItemCount(_, currentAssets),
279+
findChildIndexCallback: (Key? key) =>
280+
(key as ValueKey<int>?)?.value,
281+
),
282+
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
283+
crossAxisCount: gridCount,
284+
mainAxisSpacing: itemSpacing,
285+
crossAxisSpacing: itemSpacing,
286+
),
287+
),
288+
if (isAppleOS)
289+
SliverPadding(
290+
padding: EdgeInsetsDirectional.only(
265291
bottom: bottomActionBarHeight,
266-
)
267-
: EdgeInsets.zero,
268-
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
269-
crossAxisCount: gridCount,
270-
mainAxisSpacing: itemSpacing,
271-
crossAxisSpacing: itemSpacing,
272-
),
273-
itemCount: assetsGridItemCount(_, currentAssets),
274-
itemBuilder: (BuildContext c, int index) => assetGridItemBuilder(
275-
c,
276-
index,
277-
currentAssets,
278-
),
292+
),
293+
),
294+
],
279295
),
280296
),
281297
);
@@ -619,7 +635,9 @@ class DefaultAssetPickerBuilderDelegate
619635
List<AssetEntity> currentAssets,
620636
) {
621637
final AssetPathEntity? currentPathEntity =
622-
context.read<DefaultAssetPickerProvider>().currentPathEntity;
638+
context.select<DefaultAssetPickerProvider, AssetPathEntity?>(
639+
(DefaultAssetPickerProvider p) => p.currentPathEntity,
640+
);
623641

624642
int currentIndex;
625643
switch (specialItemPosition) {
@@ -641,10 +659,11 @@ class DefaultAssetPickerBuilderDelegate
641659
return const SizedBox.shrink();
642660
}
643661

662+
final int _length = currentAssets.length;
644663
if (currentPathEntity.isAll &&
645664
specialItemPosition != SpecialItemPosition.none) {
646665
if ((index == 0 && specialItemPosition == SpecialItemPosition.prepend) ||
647-
(index == currentAssets.length &&
666+
(index == _length &&
648667
specialItemPosition == SpecialItemPosition.append)) {
649668
return specialItemBuilder!(context);
650669
}
@@ -654,8 +673,10 @@ class DefaultAssetPickerBuilderDelegate
654673
currentIndex = index;
655674
}
656675

657-
if (index == currentAssets.length - gridCount * 3 &&
658-
context.read<DefaultAssetPickerProvider>().hasMoreToLoad) {
676+
if (index == _length - gridCount * 3 &&
677+
context.select<DefaultAssetPickerProvider, bool>(
678+
(DefaultAssetPickerProvider p) => p.hasMoreToLoad,
679+
)) {
659680
provider.loadMoreAssets();
660681
}
661682

@@ -688,7 +709,9 @@ class DefaultAssetPickerBuilderDelegate
688709
List<AssetEntity> currentAssets,
689710
) {
690711
final AssetPathEntity? currentPathEntity =
691-
context.read<DefaultAssetPickerProvider>().currentPathEntity;
712+
context.select<DefaultAssetPickerProvider, AssetPathEntity?>(
713+
(DefaultAssetPickerProvider p) => p.currentPathEntity,
714+
);
692715

693716
if (currentPathEntity == null &&
694717
specialItemPosition != SpecialItemPosition.none) {
@@ -697,20 +720,17 @@ class DefaultAssetPickerBuilderDelegate
697720

698721
/// Return actual length if current path is all.
699722
/// 如果当前目录是全部内容,则返回实际的内容数量。
723+
final int _length = currentAssets.length;
700724
if (!currentPathEntity!.isAll) {
701-
return currentAssets.length;
725+
return _length;
702726
}
703-
int length;
704727
switch (specialItemPosition) {
705728
case SpecialItemPosition.none:
706-
length = currentAssets.length;
707-
break;
729+
return _length;
708730
case SpecialItemPosition.prepend:
709731
case SpecialItemPosition.append:
710-
length = currentAssets.length + 1;
711-
break;
732+
return _length + 1;
712733
}
713-
return length;
714734
}
715735

716736
@override
@@ -771,7 +791,7 @@ class DefaultAssetPickerBuilderDelegate
771791
}
772792

773793
/// It'll pop with [AssetPickerProvider.selectedAssets]
774-
/// when there're any assets chosen.
794+
/// when there are any assets were chosen.
775795
/// 当有资源已选时,点击按钮将把已选资源通过路由返回。
776796
@override
777797
Widget confirmButton(BuildContext context) {
@@ -820,46 +840,28 @@ class DefaultAssetPickerBuilderDelegate
820840
isOriginal: false,
821841
thumbSize: <int>[gridThumbSize, gridThumbSize],
822842
);
823-
return RepaintBoundary(
824-
child: ExtendedImage(
825-
image: imageProvider,
826-
fit: BoxFit.cover,
827-
loadStateChanged: (ExtendedImageState state) {
828-
Widget loader = const SizedBox.shrink();
829-
switch (state.extendedImageLoadState) {
830-
case LoadState.loading:
831-
loader = const ColoredBox(color: Color(0x10ffffff));
832-
break;
833-
case LoadState.completed:
834-
SpecialImageType? type;
835-
if (imageProvider.imageFileType == ImageFileType.gif) {
836-
type = SpecialImageType.gif;
837-
} else if (imageProvider.imageFileType == ImageFileType.heic) {
838-
type = SpecialImageType.heic;
839-
}
840-
final AssetEntity asset = provider.currentAssets.elementAt(index);
841-
loader = Stack(
842-
fit: StackFit.expand,
843-
children: <Widget>[
844-
Positioned.fill(
845-
child: RepaintBoundary(child: state.completedWidget),
846-
),
847-
selectedBackdrop(context, index, asset),
848-
if (type == SpecialImageType.gif) // 如果为GIF则显示标识
849-
gifIndicator(context, asset),
850-
if (asset.type == AssetType.video) // 如果为视频则显示标识
851-
videoIndicator(context, asset),
852-
],
853-
);
854-
loader = FadeImageBuilder(child: loader);
855-
break;
856-
case LoadState.failed:
857-
loader = failedItemBuilder(context);
858-
break;
859-
}
860-
return loader;
861-
},
862-
),
843+
SpecialImageType? type;
844+
if (imageProvider.imageFileType == ImageFileType.gif) {
845+
type = SpecialImageType.gif;
846+
} else if (imageProvider.imageFileType == ImageFileType.heic) {
847+
type = SpecialImageType.heic;
848+
}
849+
return Stack(
850+
children: <Widget>[
851+
Positioned.fill(
852+
child: RepaintBoundary(
853+
child: AssetEntityGridItemBuilder(
854+
image: imageProvider,
855+
failedItemBuilder: failedItemBuilder,
856+
),
857+
),
858+
),
859+
selectedBackdrop(context, index, asset),
860+
if (type == SpecialImageType.gif) // 如果为GIF则显示标识
861+
gifIndicator(context, asset),
862+
if (asset.type == AssetType.video) // 如果为视频则显示标识
863+
videoIndicator(context, asset),
864+
],
863865
);
864866
}
865867

@@ -894,10 +896,7 @@ class DefaultAssetPickerBuilderDelegate
894896
return IgnorePointer(
895897
ignoring: !isSwitchingPath,
896898
child: GestureDetector(
897-
onTap: () {
898-
context.read<DefaultAssetPickerProvider>().isSwitchingPath =
899-
false;
900-
},
899+
onTap: () => provider.isSwitchingPath = false,
901900
child: AnimatedOpacity(
902901
duration: switchingPathDuration,
903902
opacity: isSwitchingPath ? 1.0 : 0.0,
@@ -913,9 +912,8 @@ class DefaultAssetPickerBuilderDelegate
913912
Widget pathEntityListWidget(BuildContext context) {
914913
final double appBarHeight = kToolbarHeight + Screens.topSafeHeight;
915914
final double maxHeight = Screens.height * 0.825;
916-
final bool isAudio =
917-
context.read<DefaultAssetPickerProvider>().requestType ==
918-
RequestType.audio;
915+
final bool isAudio = (provider as DefaultAssetPickerProvider).requestType ==
916+
RequestType.audio;
919917
return Selector<DefaultAssetPickerProvider, bool>(
920918
selector: (_, DefaultAssetPickerProvider p) => p.isSwitchingPath,
921919
builder: (_, bool isSwitchingPath, Widget? w) =>
@@ -946,25 +944,27 @@ class DefaultAssetPickerBuilderDelegate
946944
),
947945
child: Selector<DefaultAssetPickerProvider, int>(
948946
selector: (_, DefaultAssetPickerProvider p) => p.validPathThumbCount,
949-
builder: (BuildContext c, int count, __) {
950-
final Map<AssetPathEntity, Uint8List?> list =
951-
c.watch<DefaultAssetPickerProvider>().pathEntityList;
952-
return ListView.separated(
953-
padding: const EdgeInsetsDirectional.only(top: 1.0),
954-
itemCount: list.length,
955-
itemBuilder: (_, int index) => pathEntityWidget(
956-
context: c,
957-
list: list,
958-
index: index,
959-
isAudio: isAudio,
960-
),
961-
separatorBuilder: (BuildContext _, int __) => Container(
962-
margin: const EdgeInsetsDirectional.only(start: 60.0),
963-
height: 1.0,
964-
color: theme.canvasColor,
965-
),
966-
);
967-
},
947+
builder: (_, int count, __) => Selector<DefaultAssetPickerProvider,
948+
Map<AssetPathEntity, Uint8List?>>(
949+
selector: (_, DefaultAssetPickerProvider p) => p.pathEntityList,
950+
builder: (BuildContext c, Map<AssetPathEntity, Uint8List?> list, __) {
951+
return ListView.separated(
952+
padding: const EdgeInsetsDirectional.only(top: 1.0),
953+
itemCount: list.length,
954+
itemBuilder: (_, int index) => pathEntityWidget(
955+
context: c,
956+
list: list,
957+
index: index,
958+
isAudio: isAudio,
959+
),
960+
separatorBuilder: (BuildContext _, int __) => Container(
961+
margin: const EdgeInsetsDirectional.only(start: 60.0),
962+
height: 1.0,
963+
color: theme.canvasColor,
964+
),
965+
);
966+
},
967+
),
968968
),
969969
);
970970
}

lib/src/delegates/asset_picker_viewer_builder_delegate.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,8 +579,8 @@ class DefaultAssetPickerViewerBuilderDelegate
579579
);
580580
}
581581

582-
/// It'll pop with [AssetPickerProvider.selectedAssets] when there're any
583-
/// assets chosen. The [PhotoSelector] will recognize and pop too.
582+
/// It'll pop with [AssetPickerProvider.selectedAssets] when there are
583+
/// any assets were chosen. Then, the assets picker will pop too.
584584
/// 当有资源已选时,点击按钮将把已选资源通过路由返回。
585585
/// 资源选择器将识别并一同返回。
586586
@override

lib/src/provider/asset_picker_provider.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ abstract class AssetPickerProvider<A, P> extends ChangeNotifier {
5353
super.dispose();
5454
}
5555

56-
/// Whether there're any assets on the devices.
56+
/// Whether there are assets on the devices.
5757
/// 设备上是否有资源文件
5858
bool _isAssetsEmpty = false;
5959

@@ -67,7 +67,7 @@ abstract class AssetPickerProvider<A, P> extends ChangeNotifier {
6767
notifyListeners();
6868
}
6969

70-
/// Whether there're any assets that can be displayed.
70+
/// Whether there are any assets can be displayed.
7171
/// 是否有资源可供显示
7272
bool _hasAssetsToDisplay = false;
7373

@@ -81,7 +81,7 @@ abstract class AssetPickerProvider<A, P> extends ChangeNotifier {
8181
notifyListeners();
8282
}
8383

84-
/// Whether there're more assets waiting for load.
84+
/// Whether more assets are waiting for a load.
8585
/// 是否还有更多资源可以加载
8686
bool get hasMoreToLoad => _currentAssets.length < _totalAssetsCount;
8787

0 commit comments

Comments
 (0)