scan_view.dart 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. part of fqreader;
  2. class ScanView extends StatefulWidget {
  3. /**
  4. * 扫描事件
  5. */
  6. final ScanEvent onScan;
  7. /**
  8. * 扫描区域大小
  9. */
  10. final Size scanSize;
  11. /**
  12. * 图片大小
  13. */
  14. final Size pictureSize;
  15. /**
  16. * ScanView控件大小
  17. */
  18. final Size viewSize;
  19. /**
  20. * 扫描框的位置(位于图片)
  21. */
  22. final Alignment scanAilgn;
  23. /**
  24. * view的位置(位于图片)
  25. */
  26. final Alignment viewAilgn;
  27. /**
  28. * 屏幕分辨率
  29. */
  30. final double devicePixelRatio;
  31. /**
  32. * 是否立即扫描
  33. */
  34. final bool autoScan;
  35. /**
  36. * 是否连续扫描
  37. */
  38. final bool continuityScan;
  39. /**
  40. * 连续扫描间隔
  41. */
  42. final Duration scanInterval;
  43. /**
  44. * 扫描的条码类型
  45. */
  46. final List<ScanType> scanType;
  47. const ScanView(
  48. {Key key,
  49. this.onScan,
  50. @required this.viewSize,
  51. @required this.pictureSize,
  52. @required this.scanSize,
  53. this.scanAilgn = Alignment.topLeft,
  54. this.viewAilgn = Alignment.topLeft,
  55. @required this.devicePixelRatio,
  56. this.scanType = const [ScanType.ALL],
  57. this.autoScan = true,
  58. this.continuityScan = false,
  59. this.scanInterval = const Duration(milliseconds: 500)})
  60. : super(key: key);
  61. @override
  62. State<StatefulWidget> createState() => ScanViewState();
  63. }
  64. class ScanViewState extends State<ScanView> {
  65. int _textureId;
  66. StreamSubscription _readySubscription;
  67. Size _cameraSize;
  68. @override
  69. void initState() {
  70. // TODO: implement initState
  71. super.initState();
  72. if(widget.autoScan){
  73. this.startScan();
  74. }
  75. }
  76. @override
  77. Widget build(BuildContext context) {
  78. return _textureId != null
  79. ? new _ScanViewTexture(
  80. textureId: _textureId,
  81. cameraSize: _cameraSize,
  82. viewRect: _getViewRect(_cameraSize, widget.viewSize, widget.viewAilgn),
  83. )
  84. : new Container();
  85. }
  86. Rect _getViewRect(Size cameraSize, Size viewSize, Alignment alignment)
  87. {
  88. var offset = cameraSize - viewSize;
  89. return alignment.alongOffset(offset) & viewSize;
  90. }
  91. @override
  92. void deactivate() {
  93. // TODO: implement deactivate
  94. super.deactivate();
  95. _readySubscription.cancel();
  96. Fqreader._release();
  97. }
  98. /**
  99. * 开始扫描
  100. */
  101. Future startScan() async {
  102. if (this._textureId == null) {
  103. var initResult = await Fqreader._initView(
  104. viewSize: widget.pictureSize,
  105. devicePixelRatio: widget.devicePixelRatio,
  106. scanType: widget.scanType);
  107. _cameraSize = initResult.cameraSize;
  108. _textureId = initResult.textureID;
  109. Fqreader._setScanRect(_getViewRect(_cameraSize, widget.scanSize, widget.scanAilgn), widget.devicePixelRatio);
  110. _readySubscription = new EventChannel('fqreader/scanEvents$_textureId')
  111. .receiveBroadcastStream()
  112. .listen(_listener);
  113. setState(() {
  114. });
  115. }
  116. await Fqreader._startScan();
  117. }
  118. /**
  119. * 暂停扫描
  120. */
  121. Future stopScan() async {
  122. await Fqreader._stopScan();
  123. }
  124. /**
  125. * 开灯
  126. */
  127. Future turnOn() async {
  128. await Fqreader._turnOn();
  129. }
  130. /**
  131. * 关灯
  132. */
  133. Future turnOff() async {
  134. await Fqreader._turnOff();
  135. }
  136. Future release() async {
  137. this._textureId = null;
  138. Fqreader._release();
  139. }
  140. void _listener(dynamic value) {
  141. if (widget != null) {
  142. if (!widget.continuityScan) //是否连续扫描
  143. {
  144. Fqreader._stopScan();
  145. }
  146. var result = ScanResult(
  147. scanType: _parseScanType(value['scanType']),
  148. data: value['data'],
  149. );
  150. widget.onScan(result).then((result) {
  151. if (widget.continuityScan && result) {
  152. Future.delayed(widget.scanInterval, () {
  153. Fqreader._startScan();
  154. });
  155. } else {
  156. Fqreader._stopScan();
  157. }
  158. });
  159. }
  160. }
  161. }
  162. class _ScanViewTexture extends LeafRenderObjectWidget {
  163. final Size cameraSize;
  164. final Rect viewRect;
  165. /// Creates a widget backed by the texture identified by [textureId].
  166. const _ScanViewTexture({
  167. Key key,
  168. @required this.cameraSize,
  169. @required this.viewRect,
  170. @required this.textureId,
  171. }) : assert(textureId != null),
  172. super(key: key);
  173. /// The identity of the backend texture.
  174. final int textureId;
  175. @override
  176. _ScanViewTextureBox createRenderObject(BuildContext context) =>
  177. _ScanViewTextureBox(textureId: textureId, cameraSize: cameraSize, viewRect: viewRect);
  178. @override
  179. void updateRenderObject(
  180. BuildContext context, _ScanViewTextureBox renderObject) {
  181. renderObject.textureId = textureId;
  182. renderObject.cameraSize = cameraSize;
  183. renderObject.viewRect = viewRect;
  184. }
  185. }
  186. class _ScanViewTextureBox extends RenderBox {
  187. /// Creates a box backed by the texture identified by [textureId].
  188. _ScanViewTextureBox({@required int textureId, @required Size cameraSize,@required Rect viewRect})
  189. : assert(textureId != null),
  190. assert(viewRect != null),
  191. assert(cameraSize != null),
  192. _textureId = textureId,
  193. _cameraSize = cameraSize,
  194. _viewRect = viewRect;
  195. /// The identity of the backend texture.
  196. int get textureId => _textureId;
  197. int _textureId;
  198. set textureId(int value) {
  199. assert(value != null);
  200. if (value != _textureId) {
  201. _textureId = value;
  202. markNeedsPaint();
  203. }
  204. }
  205. Size get cameraSize => _cameraSize;
  206. Size _cameraSize;
  207. set cameraSize(Size value) {
  208. assert(value != null);
  209. if (value != _cameraSize) {
  210. _cameraSize = value;
  211. markNeedsPaint();
  212. }
  213. }
  214. Rect get viewRect => _viewRect;
  215. Rect _viewRect;
  216. set viewRect(Rect value) {
  217. assert(value != null);
  218. if (value != _viewRect) {
  219. _viewRect = value;
  220. markNeedsPaint();
  221. }
  222. }
  223. @override
  224. bool get sizedByParent => true;
  225. @override
  226. bool get alwaysNeedsCompositing => true;
  227. @override
  228. bool get isRepaintBoundary => true;
  229. @override
  230. void performResize() {
  231. size = viewRect.size;
  232. }
  233. @override
  234. bool hitTestSelf(Offset position) => true;
  235. @override
  236. void paint(PaintingContext context, Offset offset) {
  237. if (_textureId == null) return;
  238. // context.addLayer(TextureLayer(
  239. // rect: Rect.fromLTWH(offset.dx, offset.dy, _viewSize.width, _viewSize.height),
  240. // textureId: _textureId,
  241. // ));
  242. print(_cameraSize);
  243. context.pushClipRect(
  244. needsCompositing, offset, viewRect,
  245. (PaintingContext context, Offset offset) {
  246. context.addLayer(TextureLayer(
  247. rect: Rect.fromLTWH(
  248. offset.dx, offset.dy, _cameraSize.width, _cameraSize.height),
  249. textureId: _textureId,
  250. ));
  251. });
  252. }
  253. }