2000calories / flutter_easy_rich_text

The EasyRichText widget provides an easy way to use RichText.
https://pub.dev/packages/easy_rich_text
MIT License
79 stars 34 forks source link

Deselect selectable text when clicking #25

Closed caleb654 closed 2 years ago

caleb654 commented 2 years ago

Just want to say I love the package, it's awesome! One thing I noticed though is that text doesn't deselect. If I have it selected and then I click outside it or on another EasyRichText widget. It would be great if it could deselect to mimic the behavior that's typically expected on the web.

Let me know if you need any more details.

2000calories commented 2 years ago

Hi Caleb, thank you for your appreciation. Since deselect involves state change, it should be done through state management but not the widget itself.

Here is an example for your reference.

  deselectText(context, {thisIndex}) {
    for (var i = 0; i < 2; i++) {
      if (thisIndex != i) {
        setState(() {
          selectableTextKeys[i] = UniqueKey();
        });
      }
    }
  }

  List<UniqueKey> selectableTextKeys = List.generate(2, (i) => UniqueKey());
GestureDetector(
    //when click outside EasyRichText widget.
    onTap: () => deselectText(context),
    child: Container(
      child: Center(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              SelectableText.rich(
                TextSpan(text: "test1 test1"),
                key: ValueKey(selectableTextKeys[0]),
                //deselect other EasyRichText widgets
                onTap: () => deselectText(context, thisIndex: 0),
                autofocus: true,
              ),
              SelectableText.rich(
                TextSpan(text: "test2 test2"),
                key: ValueKey(selectableTextKeys[1]),
                onTap: () => deselectText(context, thisIndex: 1),
                autofocus: true,
              ),
            ],
          ),
        ),
      ),
    ),
  ),
2000calories commented 2 years ago

By the way, If you find this package useful, please give me a star on Github or a like on pub.dev

caleb654 commented 2 years ago

Ok thanks! This is how I ended up doing it using your advice on handling it with state. Not sure if it's the best way, but it works.

class CustomSelectableText extends StatefulWidget {
  const CustomSelectableText({Key? key}) : super(key: key);

  @override
  _CustomSelectableTextState createState() => _CustomSelectableTextState();
}

class _CustomSelectableTextState extends State<CustomSelectableText> {
  bool selectable = true;

  @override
  Widget build(BuildContext context) {
    return Focus(
      onFocusChange: (focus) async {
        // This will fire if I click on another widget that takes the focus
        if (!focus) {
          setState(() => selectable = false);
          await Future.delayed(Duration(milliseconds: 100));
          setState(() => selectable = true);
        }
      },
      child: EasyRichText(
        "This paragraph is selectable...",
        selectable: selectable,
        patternList: [
          EasyRichTextPattern(
            targetString: 'paragraph',
            style: TextStyle(color: Colors.blue),
          ),
        ],
      ),
    );
  }
}