如何在图像上精确对齐许多容器小部件,以便在调整大小时完全作为图像的一部分

问题描述 投票:0回答:1

我有一个类似书籍的应用程序,可以在 PageView 小部件中显示书籍页面的图像, 我想在该图像 clickabe 的特定位置上添加一些短语 图像(左,右,宽度,高度),我尝试将堆栈小部件与定位容器一起使用 但我无法在图像上精确对齐短语坐标。问题是:如何制作 这些定位的容器在图像上具有绝对位置。 我为实现这一目标做了什么:

  • 为每个图像分配全局键。
  • 使用全局键检索图像尺寸。 像:keyList[index].globalPaintBounds.top(不工作)
  • 尝试 MediaQuery.of(context).size 来检索图像尺寸。 (没办法)
  • 尝试将位置属性分配给容器、图像、sizedbox(没有成功)。
  • 仍在挣扎,但需要一些帮助。

这是应用程序代码:

    import 'package:flutter/material.dart';
  class ImageSliderApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        // scrollBehavior: AppScrollBehavior(),
        home: ImageSliderScreen(),
      );
    }
  }
  class ImageSliderScreen extends StatefulWidget {
    @override
    _ImageSliderScreenState createState() => _ImageSliderScreenState();
  }
  class _ImageSliderScreenState extends State<ImageSliderScreen> {
    PageController _pageController = PageController();

    int _currentPage = 0;
    List<String> _images = [];
    bool isEditable = false;
    final List<GlobalObjectKey> keyList =
        List.generate(170, (index) => GlobalObjectKey(index));

  /* lights : sample data of the phrases [page, x , y] 
  width and hight generated dynamically.
  */
    List<List<dynamic>> lights = [
      [4, 96, 104],
      [4, 238, 144],
      [4, 128, 222],
      [4, 284, 342],
      [4, 153, 379],
      [4, 343, 497],
      [4, 303, 576],
      [4, 58, 616]
    ];

  /*
  loadAssets : to fill images list with images names
  */
    void loadAsset() async {
      for (int i = 3; i < 164; i++) {
        String ff = "assets/images/$i.png";
        _images.add(ff);
      }
    }
  /*
  calculatePosiion: function called to reassign the position of the highlighting rectangles
  relative to the image position when the viewport resized.
  */
    Rect calculatePosition(details) {
      double det_width =
          (details?.width != null) ? (details?.width) : 0; //(454,735)
      double det_height = (details?.height != null) ? (details?.height) : 0;
      double ret_width = det_width.round() / 454;
      double ret_height = det_height.round() / 735;
      Rect recto = new Rect.fromLTWH(45, 20, ret_width * 150, ret_height * 30);
      return recto;
    }

    @override
    void initState() {
      super.initState();
      loadAsset();
      _pageController.addListener(() {
        setState(() {
          _currentPage = _pageController.page!.round();
        });
      });
    }

    @override
    void dispose() {
      super.dispose();
      _pageController.dispose();
    }

    @override
    Widget build(BuildContext context) {
      return SafeArea(
        child: Scaffold(
          appBar: isEditable == true
              ? AppBar(
                  title: Text('Book Pages Slider'),
                  centerTitle: true,
                )
              : null,
          body: PageView.builder(
            controller: _pageController,
            scrollDirection: Axis.horizontal,
            padEnds: false,
            reverse: true,
            itemCount: _images.length,
            physics: BouncingScrollPhysics(),
            onPageChanged: (int) {},
            itemBuilder: (context, index) {
              return SingleChildScrollView(
                  child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Center(
                  child: Stack(
                    clipBehavior: Clip.none,
                    children: <Widget>[
                      Positioned(
                        child: SizedBox(
                          // height: (MediaQuery.of(context).size.height),
                          //height: 600,
                          // width: 200,
                          child: Image.asset(
                            width: (MediaQuery.of(context).size.width),
                            key: keyList[index],
                            _images[index],
                            fit: BoxFit.contain,
                          ),
                        ),
                      ),
                      Positioned(
                          top: keyList[index].globalPaintBounds?.top,
                          left: keyList[index].globalPaintBounds?.left,
                          //top: calculatePosition(yourKey.globalPaintBounds).top,
                          child: Container(
                            // width: calculatePosition(keyList[index].globalPaintBounds).width,
                            height: keyList[index].globalPaintBounds?.height,
                            width: (MediaQuery.of(context).size.width),
                            decoration:
                                BoxDecoration(color: Colors.red.withOpacity(.1)),
                            child: InkWell(
                                onTap: () {
                                  print(lights[4][5]);
                                  print(
                                      'coordinates on screen: ${keyList[index].globalPaintBounds}');
                                },
                                child: const Text('1')),
                          )),
                      /** Positioned WIdget **/
                    ],
                  ),
                ),
              ));
            },
          ),
        ),
      );
    }
  }

  extension GlobalKeyExtension on GlobalKey {
    Rect? get globalPaintBounds {
      final renderObject = currentContext?.findRenderObject();
      final translation = renderObject?.getTransformTo(null).getTranslation();
      if (translation != null && renderObject?.paintBounds != null) {
        final offset = Offset(translation.x, translation.y);
        return renderObject!.paintBounds.shift(offset);
      } else {
        return null;
      }
    }
  }
flutter dart widget stack
1个回答
0
投票

试试这个:

import 'package:flutter/material.dart';

final rects = [
  (const Rect.fromLTWH(31, 235, 100, 26), Colors.indigo.withOpacity(0.5), 'pantry'),
  (const Rect.fromLTWH(121, 341, 102, 70), Colors.green.withOpacity(0.5), 'bath'),
];

main() => runApp(
  MaterialApp(home: Scaffold(body: SizedBox.expand(
    child: FittedBox(
      child: Stack(
        children: [
          Image.network('https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Sample_Floorplan.jpg/640px-Sample_Floorplan.jpg'),
          ...rects.map((r) => Positioned.fromRect(
              rect: r.$1,
              child: Material(
                color: r.$2,
                child: InkWell(
                  splashColor: Colors.black,
                  onTap: () => print('onTap ${r.$3}'),
                ),
              ),
            ),
          ),
        ],
      ),
    ),
  )))
);

这里:

Rect.fromLTWH(31, 235, 100, 26)
Rect.fromLTWH(121, 341, 102, 70)

表示原始图像上的两个区域:第一个区域的位置为 31、235,大小为 100 x 25,第二个区域的位置为 121、341,大小为 102 x 70

它们与平面图上的“食品储藏室”和“浴室”相对应

© www.soinside.com 2019 - 2024. All rights reserved.