daohoangson / flutter_widget_from_html

Flutter package to render html as widgets that supports hyperlink, image, audio, video, iframe and many other tags.
https://pub.dev/packages/flutter_widget_from_html
MIT License
645 stars 242 forks source link

Selectable text #1333

Closed albe-jj closed 1 month ago

albe-jj commented 2 months ago

Use case

It would be nice if the HtmlWidget would allow to specify if text should be selectable or not

Proposal

selectable text could be rendered with SelectableText.rich and TextSpa, or simply the SelectableText widget.

daohoangson commented 2 months ago

You can wrap HtmlWidget inside a SelectionArea to make it selectable.

gbulfon commented 1 month ago

You can wrap HtmlWidget inside a SelectionArea to make it selectable.

Tried as you suggested, but if I now long press on the html view area to start a selection, I get all these errors:

======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 1215 pos 14: '!_selectionStartsInScrollable': is not true.

Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.yml

When the exception was thrown, this was the stack: 
#2      _ScrollableSelectionContainerDelegate.handleSelectionEdgeUpdate (package:flutter/src/widgets/scrollable.dart:1215:14)
#3      MultiSelectableSelectionContainerDelegate.dispatchSelectionEvent (package:flutter/src/widgets/selectable_region.dart:2308:18)
#4      _SelectionContainerState.dispatchSelectionEvent (package:flutter/src/widgets/selection_container.dart:183:29)
#5      MultiSelectableSelectionContainerDelegate.dispatchSelectionEventToChild (package:flutter/src/widgets/selectable_region.dart:2356:23)
#6      _SelectableRegionContainerDelegate.dispatchSelectionEventToChild (package:flutter/src/widgets/selectable_region.dart:1576:18)
#7      MultiSelectableSelectionContainerDelegate._initSelection (package:flutter/src/widgets/selectable_region.dart:2377:43)
#8      MultiSelectableSelectionContainerDelegate.handleSelectionEdgeUpdate (package:flutter/src/widgets/selectable_region.dart:2289:47)
#9      _SelectableRegionContainerDelegate.handleSelectionEdgeUpdate (package:flutter/src/widgets/selectable_region.dart:1545:18)
#10     MultiSelectableSelectionContainerDelegate.dispatchSelectionEvent (package:flutter/src/widgets/selectable_region.dart:2308:18)
#11     _SelectionContainerState.dispatchSelectionEvent (package:flutter/src/widgets/selection_container.dart:183:29)
#12     SelectableRegionState._selectEndTo (package:flutter/src/widgets/selectable_region.dart:962:20)
#13     SelectableRegionState._handleTouchLongPressMoveUpdate (package:flutter/src/widgets/selectable_region.dart:582:5)
#14     LongPressGestureRecognizer._checkLongPressMoveUpdate.<anonymous closure> (package:flutter/src/gestures/long_press.dart:745:85)
#15     GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:315:24)
#16     LongPressGestureRecognizer._checkLongPressMoveUpdate (package:flutter/src/gestures/long_press.dart:745:11)
#17     LongPressGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/long_press.dart:644:9)
#18     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:670:9)
#19     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:98:12)
#20     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:143:9)
#21     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
#22     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:141:18)
#23     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:127:7)
#24     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:495:19)
#25     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:475:22)
#26     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:430:11)
#27     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:420:7)
#28     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:383:5)
#29     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:330:7)
#30     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:299:9)
#31     _invoke1 (dart:ui/hooks.dart:328:13)
#32     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:429:7)
#33     _dispatchPointerDataPacket (dart:ui/hooks.dart:262:31)
(elided 2 frames from class _AssertionError)
Handler: "onLongPressMoveUpdate"
Recognizer: LongPressGestureRecognizer#0ce7f
  debugOwner: SelectableRegionState#7481f
  state: possible
====================================================================================================
gbulfon commented 1 month ago

Found a workaround. The scroll view contained other widgets before the SelectionArea/HtmlWidget, I had to place all other widgets inside a SelectionContainer.disabled, like this:

SelectionContainer.disabled(
  child: GestureDetector(
     onLongPress: () {},
     child: ... //the unselecatble structure of children
   )
 ),
 SelectionArea(
   child: HtmlWidget(htmlData2)
 ) 
daohoangson commented 1 month ago

That is an interesting workaround for a previously unknown problem. Thank you for sharing @gbulfon.