Flutter: Как предотвратить восстановление всего Reorderable Listview? - PullRequest
0 голосов
/ 27 января 2020

В настоящее время я использую флаттерный пакет 'Reorderables', чтобы показать переупорядочиваемый просмотр списка, который содержит несколько изображений. Эти изображения можно удалить из списка через кнопку, все работает нормально. Но просмотр списка перестраивается каждый раз, когда я удаляю изображение. Я использую класс ReorderableListviewManager с ChangeNotifier для обновления изображений и Provider.of<ReorderableListviewManager>(context) для получения последних изображений. Проблема в том, что при использовании Provider.of<ReorderableListviewManager>(context) каждый раз, когда я удаляю изображение, вызывается build(), поэтому просмотр списка повторяется. Я могу использовать Потребителя только для того, чтобы перестроить часть дерева виджетов, но кажется, что нет места, чтобы поместить потребителя в children этого списка. Есть ли способ перестроить только изображение, но не весь 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),
                            ),
                          ),
                        ],
                      ),
                    )
                  ],
                ),
              )
            ],
          )),
    );
  }
}
...