Android 颤振:如何防止重建整个可重排序Listview?
目前,我正在使用颤振软件包“Reorderables”来显示一个包含多个图像的可重排序列表视图。这些图像可以通过一个按钮从列表视图中删除,一切正常。但每次删除图像时,listview都会重新生成。我正在使用一个名为“ReorderableListviewManager”的类和ChangeNotifier来更新图像,并使用Android 颤振:如何防止重建整个可重排序Listview?,android,flutter,dart,flutter-dependencies,dart-pub,Android,Flutter,Dart,Flutter Dependencies,Dart Pub,目前,我正在使用颤振软件包“Reorderables”来显示一个包含多个图像的可重排序列表视图。这些图像可以通过一个按钮从列表视图中删除,一切正常。但每次删除图像时,listview都会重新生成。我正在使用一个名为“ReorderableListviewManager”的类和ChangeNotifier来更新图像,并使用Provider.of(context)来获取最新图像。现在的问题是使用Provider.of(context)使得每次删除图像时都调用build()。我知道我 可以使用cons
Provider.of(context)
来获取最新图像。现在的问题是使用Provider.of(context)
使得每次删除图像时都调用build()。我知道我
可以使用consumer只重建小部件树的一部分,但似乎没有地方将consumer放入此Listview的子项中。有没有办法只重建图像而不重建整个ReorderableListview?非常感谢
下面是我的代码:
class NotePicturesEditScreen extends StatefulWidget {
final List<Page> notePictures;
final NotePicturesEditBloc bloc;
NotePicturesEditScreen({@required this.notePictures, @required this.bloc});
static Widget create(BuildContext context, List<Page> notePictures) {
return Provider<NotePicturesEditBloc>(
create: (context) => NotePicturesEditBloc(),
child: Consumer<NotePicturesEditBloc>(
builder: (context, bloc, _) =>
ChangeNotifierProvider<ReorderableListviewManager>(
create: (context) => ReorderableListviewManager(),
child: NotePicturesEditScreen(
bloc: bloc,
notePictures: notePictures,
),
)),
dispose: (context, bloc) => bloc.dispose(),
);
}
@override
_NotePicturesEditScreenState createState() => _NotePicturesEditScreenState();
}
class _NotePicturesEditScreenState extends State<NotePicturesEditScreen> {
PreloadPageController _pageController;
ScrollController _reorderableScrollController;
List<Page> notePicturesCopy;
int longPressIndex;
List<double> smallImagesWidth;
double scrollOffset = 0;
_reorderableScrollListener() {
scrollOffset = _reorderableScrollController.offset;
}
@override
void initState() {
Provider.of<ReorderableListviewManager>(context, listen: false)
.notePictures = widget.notePictures;
notePicturesCopy = widget.notePictures;
_reorderableScrollController = ScrollController();
_pageController = PreloadPageController();
_reorderableScrollController.addListener(_reorderableScrollListener);
Provider.of<ReorderableListviewManager>(context, listen: false)
.getSmallImagesWidth(notePicturesCopy, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
super.initState();
}
@override
void dispose() {
_pageController.dispose();
_reorderableScrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
ReorderableListviewManager reorderableManager =
Provider.of<ReorderableListviewManager>(context, listen: false);
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
shape: Border(bottom: BorderSide(color: Colors.black12)),
iconTheme: IconThemeData(color: Colors.black87),
elevation: 0,
automaticallyImplyLeading: false,
titleSpacing: 0,
centerTitle: true,
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
child: IconButton(
padding: EdgeInsets.only(left: 20, right: 12),
onPressed: () => Navigator.of(context).pop(),
icon: Icon(Icons.close),
),
),
Text('編輯',
style: TextStyle(color: Colors.black87, fontSize: 18))
],
),
actions: <Widget>[
FlatButton(
onPressed: () {},
child: Text(
'下一步',
),
)
],
),
backgroundColor: Color(0xffeeeeee),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Spacer(),
StreamBuilder<List<Page>>(
initialData: widget.notePictures,
stream: widget.bloc.notePicturesStream,
builder: (context, snapshot) {
notePicturesCopy = snapshot.data;
return Container(
margin: EdgeInsets.symmetric(horizontal: 20),
height: MediaQuery.of(context).size.height * 0.65,
child: PreloadPageView.builder(
preloadPagesCount: snapshot.data.length,
controller: _pageController,
itemCount: snapshot.data.length,
onPageChanged: (index) {
reorderableManager.updateCurrentIndex(index);
reorderableManager.scrollToCenter(
smallImagesWidth,
index,
scrollOffset,
_reorderableScrollController,
context);
},
itemBuilder: (context, index) {
return Container(
child: Image.memory(
File.fromUri(
snapshot.data[index].polygon.isNotEmpty
? snapshot.data[index]
.documentPreviewImageFileUri
: snapshot.data[index]
.originalPreviewImageFileUri)
.readAsBytesSync(),
gaplessPlayback: true,
alignment: Alignment.center,
),
);
}),
);
},
),
Spacer(),
Container(
height: MediaQuery.of(context).size.height * 0.1,
margin: EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ReorderableRow(
scrollController: _reorderableScrollController,
buildDraggableFeedback: (context, constraints, __) =>
Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
child: Image.memory(File.fromUri(
notePicturesCopy[longPressIndex]
.polygon
.isNotEmpty
? notePicturesCopy[longPressIndex]
.documentPreviewImageFileUri
: notePicturesCopy[longPressIndex]
.originalPreviewImageFileUri)
.readAsBytesSync()),
),
onReorder: (oldIndex, newIndex) async {
List<Page> result = await widget.bloc.reorderPictures(
oldIndex,
newIndex,
reorderableManager.notePictures);
_pageController.jumpToPage(newIndex);
reorderableManager.updateNotePictures(result);
reorderableManager
.getSmallImagesWidth(result, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
},
footer: Container(
width: 32,
height: 32,
margin: EdgeInsets.only(left: 16),
child: SizedBox(
child: FloatingActionButton(
backgroundColor: Colors.white,
elevation: 1,
disabledElevation: 0,
highlightElevation: 1,
child: Icon(Icons.add, color: Colors.blueAccent),
onPressed: notePicturesCopy.length >= 20
? () {
Scaffold.of(context)
.showSnackBar(SnackBar(
content: Text('筆記上限為20頁 !'),
));
}
: () async {
List<Page> notePictures =
await widget.bloc.addPicture(
reorderableManager.notePictures);
List<double> imagesWidth =
await reorderableManager
.getSmallImagesWidth(
notePictures, context);
smallImagesWidth = imagesWidth;
reorderableManager.updateCurrentIndex(
notePictures.length - 1);
reorderableManager
.updateNotePictures(notePictures);
_pageController
.jumpToPage(notePictures.length - 1);
},
),
),
),
children: Provider.of<ReorderableListviewManager>(
context)
.notePictures
.asMap()
.map((index, page) {
return MapEntry(
index,
Consumer<ReorderableListviewManager>(
key: ValueKey('value$index'),
builder: (context, manager, _) =>
GestureDetector(
onTapDown: (_) {
longPressIndex = index;
},
onTap: () {
reorderableManager.scrollToCenter(
smallImagesWidth,
index,
scrollOffset,
_reorderableScrollController,
context);
_pageController.jumpToPage(index);
},
child: Container(
margin: EdgeInsets.only(
left: index == 0 ? 0 : 12),
decoration: BoxDecoration(
border: Border.all(
width: 1.5,
color: index ==
manager
.getCurrentIndex
? Colors.blueAccent
: Colors.transparent)),
child: index + 1 <=
manager.notePictures.length
? Image.memory(
File.fromUri(manager
.notePictures[
index]
.polygon
.isNotEmpty
? manager
.notePictures[
index]
.documentPreviewImageFileUri
: manager
.notePictures[
index]
.originalPreviewImageFileUri)
.readAsBytesSync(),
gaplessPlayback: true,
)
: null),
),
));
})
.values
.toList()),
)),
Spacer(),
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border(top: BorderSide(color: Colors.black12))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton(
onPressed: () async => await widget.bloc
.cropNotePicture(reorderableManager.notePictures,
_pageController.page.round())
.then((notePictures) {
reorderableManager.updateNotePictures(notePictures);
reorderableManager
.getSmallImagesWidth(notePictures, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
}),
child: Column(
children: <Widget>[
Icon(
Icons.crop,
color: Colors.blueAccent,
),
Container(
margin: EdgeInsets.only(top: 1),
child: Text(
'裁切',
style: TextStyle(color: Colors.blueAccent),
),
)
],
),
),
FlatButton(
onPressed: () {
int deleteIndex = _pageController.page.round();
widget.bloc
.deletePicture(
reorderableManager.notePictures, deleteIndex)
.then((notePictures) {
if (deleteIndex == notePictures.length) {
reorderableManager
.updateCurrentIndex(notePictures.length - 1);
}
reorderableManager.updateNotePictures(notePictures);
reorderableManager
.getSmallImagesWidth(notePictures, context)
.then((imagesWidth) {
smallImagesWidth = imagesWidth;
});
if (reorderableManager.notePictures.length == 0) {
Navigator.pop(context);
}
});
},
child: Column(
children: <Widget>[
Icon(
Icons.delete_outline,
color: Colors.blueAccent,
),
Container(
margin: EdgeInsets.only(top: 1),
child: Text(
'刪除',
style: TextStyle(color: Colors.blueAccent),
),
),
],
),
)
],
),
)
],
)),
);
}
}
class NotePicturesEditScreen扩展StatefulWidget{
最后的图片列表;
最后说明图片编辑集团;
NotePicturesEditScreen({@required this.notePictures,@required this.bloc});
静态小部件创建(BuildContext上下文、列表notePictures){
返回提供者(
create:(context)=>NotePicturesEditBloc(),
儿童:消费者(
构建者:(上下文、集团)=>
变更通知提供者(
创建:(上下文)=>ReorderableListviewManager(),
孩子:NotePicturesEditScreen(
集团:集团,,
notePictures:notePictures,
),
)),
dispose:(上下文,bloc)=>bloc.dispose(),
);
}
@凌驾
_NotePicturesEditScreenState createState()=>\u NotePicturesEditScreenState();
}
类_NotePicturesEditScreenState扩展状态{
Preload pageController _pageController;
ScrollController ReorderableCollController;
列表说明图片复制;
int-longPressIndex;
列出smallImagesWidth;
双滚动偏移=0;
_reorderableScrollListener(){
scrollOffset=\u reorderableScrollController.offset;
}
@凌驾
void initState(){
Provider.of(上下文,侦听:false)
.notePictures=widget.notePictures;
notePicturesCopy=widget.notePictures;
_reorderableScrollController=ScrollController();
_pageController=预加载pageController();
_redorederableScrollController.addListener(_redorederableScrollListener);
Provider.of(上下文,侦听:false)
.getSmallImagesWidth(注意图片复制,上下文)
.然后((imagesWidth){
smallImagesWidth=imagesWidth;
});
super.initState();
}
@凌驾
无效处置(){
_pageController.dispose();
_reorderableScrollController.dispose();
super.dispose();
}
@凌驾
小部件构建(构建上下文){
ReorderableListviewManager reorderableManager=
Provider.of(上下文,listen:false);
返回安全区(
孩子:脚手架(
appBar:appBar(
背景颜色:Colors.white,
形状:边框(底部:BorderSide(颜色:Colors.black12)),
iconTheme:IconThemeData(颜色:Colors.black87),
海拔:0,
自动嵌入:false,
标题间距:0,
标题:对,
标题:世界其他地区(
mainAxisAlignment:mainAxisAlignment.start,
crossAxisAlignment:crossAxisAlignment.center,
儿童:[
容器(
孩子:我的钮扣(
填充:仅限边缘设置(左:20,右:12),
onPressed:()=>Navigator.of(context.pop(),
图标:图标(Icons.close),
),
),
文本('編輯',
样式:TextStyle(颜色:Colors.black87,字体大小:18))
],
),
行动:[
扁平按钮(
按下:(){},
子:文本(
'下一步',
),
)
],
),
背景颜色:颜色(0xffeeee),
正文:专栏(
mainAxisAlignment:mainAxisAlignment.start,
crossAxisAlignment:crossAxisAlignment.start,
儿童:[
垫片(),
StreamBuilder(
initialData:widget.notePictures,
流:widget.bloc.NotePictureStream,
生成器:(上下文,快照){
notePicturesCopy=snapshot.data;
返回容器(
边缘:边缘组。对称(水平:20),
高度:MediaQuery.of(上下文).size.height*0.65,
子项:Preload PageView.builder(
Preload PageScont:snapshot.data.length,
控制器:_pageController,
itemCount:snapshot.data.length,
onPageChanged:(索引){
reorderableManager.updateCurrentIndex(索引);
reorderableManager.scrollToCenter(
smallImagesWidth,
指数
滚动偏移,
_可再减额滚动控制器,
上下文);
},
itemBuilder:(上下文,索引){
返回容器(
孩子:图像。记忆(
File.fromUri(
snapshot.data[index].polygon.isNotEmpty
?快照数据[索引]
.documentPreviewImageFileUri
:snapshot.data[索引]
.originalPreviewImageFileUri)
.readAsBytesSync(),
无间隙