@@ -9,6 +9,7 @@ import 'dart:ui' as ui;
9
9
10
10
import 'package:flutter/material.dart' ;
11
11
import 'package:flutter/gestures.dart' ;
12
+ import 'package:flutter/scheduler.dart' ;
12
13
import 'package:flutter/services.dart' ;
13
14
14
15
import '../constants/constants.dart' ;
@@ -38,13 +39,18 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
38
39
this .specialItemBuilder,
39
40
this .loadingIndicatorBuilder,
40
41
this .allowSpecialItemWhenEmpty = false ,
42
+ this .keepScrollOffset = false ,
41
43
}) : assert (
42
44
pickerTheme == null || themeColor == null ,
43
45
'Theme and theme color cannot be set at the same time.' ,
44
46
),
45
47
themeColor =
46
48
pickerTheme? .colorScheme.secondary ?? themeColor ?? C .themeColor {
47
49
Constants .textDelegate = textDelegate ?? AssetsPickerTextDelegate ();
50
+ // Add the listener if [keepScrollOffset] is true.
51
+ if (keepScrollOffset) {
52
+ gridScrollController.addListener (keepScrollOffsetListener);
53
+ }
48
54
}
49
55
50
56
/// [ChangeNotifier] for asset picker.
@@ -89,6 +95,10 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
89
95
/// 当没有资源时是否显示自定义item
90
96
final bool allowSpecialItemWhenEmpty;
91
97
98
+ /// Whether the picker should save the scroll offset between pushes and pops.
99
+ /// 选择器是否可以从同样的位置开始选择
100
+ final bool keepScrollOffset;
101
+
92
102
/// The [ScrollController] for the preview grid.
93
103
final ScrollController gridScrollController = ScrollController ();
94
104
@@ -163,9 +173,24 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
163
173
/// 当前的权限是否为受限
164
174
bool get isPermissionLimited => permission.value == PermissionState .limited;
165
175
176
+ /// The listener to track the scroll position of the [gridScrollController]
177
+ /// if [keepScrollOffset] is true.
178
+ /// 当 [keepScrollOffset] 为 true 时,跟踪 [gridScrollController] 位置的监听。
179
+ void keepScrollOffsetListener () {
180
+ if (gridScrollController.hasClients) {
181
+ Constants .scrollPosition = gridScrollController.position;
182
+ }
183
+ }
184
+
166
185
/// Keep a dispose method to sync with [State] .
167
186
/// 保留一个 dispose 方法与 [State] 同步。
187
+ ///
188
+ /// Be aware that the method will do nothing when [keepScrollOffset] is true.
189
+ /// 注意当 [keepScrollOffset] 为 true 时方法不会进行释放。
168
190
void dispose () {
191
+ if (keepScrollOffset) {
192
+ return ;
193
+ }
169
194
gridScrollController.dispose ();
170
195
permission.dispose ();
171
196
permissionOverlayHidden.dispose ();
@@ -559,6 +584,15 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
559
584
/// Yes, the build method.
560
585
/// 没错,是它是它就是它,我们亲爱的 build 方法~
561
586
Widget build (BuildContext context) {
587
+ // Schedule the scroll position's restoration callback if this feature
588
+ // is enabled and offsets are different.
589
+ if (keepScrollOffset &&
590
+ Constants .scrollPosition != null &&
591
+ ! gridScrollController.hasClients) {
592
+ SchedulerBinding .instance! .addPostFrameCallback ((_) {
593
+ gridScrollController.jumpTo (Constants .scrollPosition! .pixels);
594
+ });
595
+ }
562
596
return AnnotatedRegion <SystemUiOverlayStyle >(
563
597
value: overlayStyle,
564
598
child: Theme (
@@ -594,6 +628,7 @@ class DefaultAssetPickerBuilderDelegate
594
628
WidgetBuilder ? specialItemBuilder,
595
629
IndicatorBuilder ? loadingIndicatorBuilder,
596
630
bool allowSpecialItemWhenEmpty = false ,
631
+ bool keepScrollOffset = false ,
597
632
this .gridThumbSize = Constants .defaultGridThumbSize,
598
633
this .previewThumbSize,
599
634
this .specialPickerType,
@@ -612,6 +647,7 @@ class DefaultAssetPickerBuilderDelegate
612
647
specialItemBuilder: specialItemBuilder,
613
648
loadingIndicatorBuilder: loadingIndicatorBuilder,
614
649
allowSpecialItemWhenEmpty: allowSpecialItemWhenEmpty,
650
+ keepScrollOffset: keepScrollOffset,
615
651
);
616
652
617
653
/// Thumbnail size in the grid.
@@ -1121,7 +1157,7 @@ class DefaultAssetPickerBuilderDelegate
1121
1157
),
1122
1158
onPressed: () {
1123
1159
if (provider.isSelectedNotEmpty) {
1124
- Navigator .of (context).pop (provider.selectedAssets);
1160
+ Navigator .of (context).maybePop (provider.selectedAssets);
1125
1161
}
1126
1162
},
1127
1163
materialTapTargetSize: MaterialTapTargetSize .shrinkWrap,
@@ -1512,7 +1548,7 @@ class DefaultAssetPickerBuilderDelegate
1512
1548
maxAssets: provider.maxAssets,
1513
1549
);
1514
1550
if (result != null ) {
1515
- Navigator .of (context).pop (result);
1551
+ Navigator .of (context).maybePop (result);
1516
1552
}
1517
1553
},
1518
1554
child: Selector <DefaultAssetPickerProvider , String >(
@@ -1599,7 +1635,7 @@ class DefaultAssetPickerBuilderDelegate
1599
1635
}
1600
1636
provider.selectAsset (asset);
1601
1637
if (isSingleAssetMode && ! isPreviewEnabled) {
1602
- Navigator .of (context).pop (provider.selectedAssets);
1638
+ Navigator .of (context).maybePop (provider.selectedAssets);
1603
1639
}
1604
1640
},
1605
1641
child: Container (
@@ -1680,7 +1716,7 @@ class DefaultAssetPickerBuilderDelegate
1680
1716
maxAssets: provider.maxAssets,
1681
1717
);
1682
1718
if (result != null ) {
1683
- Navigator .of (context).pop (result);
1719
+ Navigator .of (context).maybePop (result);
1684
1720
}
1685
1721
},
1686
1722
child: Selector <DefaultAssetPickerProvider , List <AssetEntity >>(
0 commit comments