How to make copyable Text Widget in Flutter?

Viewed 62810

When long tab on Text widget, a tooltip show up with 'copy'. When click on the 'copy' the text content should copy to system clipboard.

The following will copy the text on long tap, but does not show up 'copy', so user will not know, the content is copied to the clipboard.

class CopyableText extends StatelessWidget {
  final String data;
  final TextStyle style;
  final TextAlign textAlign;
  final TextDirection textDirection;
  final bool softWrap;
  final TextOverflow overflow;
  final double textScaleFactor;
  final int maxLines;
  CopyableText(
    this.data, {
    this.style,
    this.textAlign,
    this.textDirection,
    this.softWrap,
    this.overflow,
    this.textScaleFactor,
    this.maxLines,
  });
  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      child: new Text(data,
          style: style,
          textAlign: textAlign,
          textDirection: textDirection,
          softWrap: softWrap,
          overflow: overflow,
          textScaleFactor: textScaleFactor,
          maxLines: maxLines),
      onLongPress: () {
        Clipboard.setData(new ClipboardData(text: data));
      },
    );
  }
}
7 Answers

Since Flutter 1.9 you can use

SelectableText("Lorem ipsum...")

When text is selected the "Copy" context button will appear.

enter image description here

There is also list of properties it in SelectableText to enable option copy, paste, selectAll, cut

        child: Center(
            child: SelectableText('Hello Flutter Developer',
                cursorColor: Colors.red,
                showCursor: true,
                toolbarOptions: ToolbarOptions(
                copy: true,
                selectAll: true,
                cut: false,
                paste: false
                ),
                style: Theme.of(context).textTheme.body2)
            ),

SelectableText widget

        const SelectableText(
            this.data, {
            Key key,
            this.focusNode,
            this.style,
            this.strutStyle,
            this.textAlign,
            this.textDirection,
            this.showCursor = false,
            this.autofocus = false,
            ToolbarOptions toolbarOptions,
            this.maxLines,
            this.cursorWidth = 2.0,
            this.cursorRadius,
            this.cursorColor,
            this.dragStartBehavior = DragStartBehavior.start,
            this.enableInteractiveSelection = true,
            this.onTap,
            this.scrollPhysics,
            this.textWidthBasis,
        })

enter image description here

SelectableText(
  "Copy me",
  onTap: () {
    // you can show toast to the user, like "Copied"
  },
)

If you want to have different styling for text, use

SelectableText.rich(
  TextSpan(
    children: [
      TextSpan(text: "Copy me", style: TextStyle(color: Colors.red)),
      TextSpan(text: " and leave me"),
    ],
  ),
)

enter image description here

I use Clipboard.setData inside function.

...
child: RaisedButton(
    onPressed: (){
        Clipboard.setData(ClipboardData(text: "$textcopy"));
},
    disabledColor: Colors.blue[400],
    child: Text("Copy", style: TextStyle(color: Colors.white),),
),

I created a helper class CopiableText to accomplish my job. Just copy the class from below and put it in your code.

Helper class

copiable_text_widget.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class CopiableText extends StatelessWidget {
  final String text;
  final String copyMessage;
  final Widget child;

  CopiableText(this.text, {this.copyMessage, this.child});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      child: InkWell(
        onTap: () {
          Scaffold.of(context).showSnackBar(SnackBar(
            content: Text(this.copyMessage ?? 'Copied to clipboard'),
          ));
          Clipboard.setData(new ClipboardData(text: this.text));
        },
        child: Align(
          alignment: Alignment.centerLeft,
          child: Padding(
            padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 2),
            child: this.child ??
                Text(
                  this.text,
                  style: TextStyle(color: Color(0xFF1E272E), fontSize: 14),
                ),
          ),
        ),
      ),
    );
  }
}

Use it in different ways

import 'package:chaincargo_courier/ui/widgets/copiable_text_widget.dart';
import 'package:flutter/material.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          // Just straightforward, click to copy
          CopiableText('You are awesome'),

          // Give a custom confirmation message
          CopiableText(
            'Asia, Nepal, Biratnagar',
            copyMessage: 'Address copied to clipboard',
          ),

          // Set custom child
          CopiableText(
            'Stunning view of mount everest',
            copyMessage: 'Caption copied to clipboard',
            child: Column(
              children: [
                Image.network(
                  'https://cdn.pixabay.com/photo/2010/11/29/mount-everest-413_960_720.jpg',
                  errorBuilder: (BuildContext context, Object exception,
                      StackTrace stackTrace) {
                    return Text('Cannot load picture');
                  },
                ),
                Text('Stunning view of mount everest')
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Just use SelectableText

 SelectableText(
                iosInfo.identifierForVendor.toString(),
              ),
Related