我有一个类似书籍的应用程序,可以在 PageView 小部件中显示书籍页面的图像, 我想在该图像 clickabe 的特定位置上添加一些短语 图像(左,右,宽度,高度),我尝试将堆栈小部件与定位容器一起使用 但我无法在图像上精确对齐短语坐标。问题是:如何制作 这些定位的容器在图像上具有绝对位置。 我为实现这一目标做了什么:
这是应用程序代码:
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;
}
}
}
试试这个:
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
它们与平面图上的“食品储藏室”和“浴室”相对应