preface

I haven’t written more for a few weeks. Recently, I found a FastClip software in the IOS App that is quite useful, so I made a simple clipboard by imitating it and recorded and stomped in it some ideas of implementation. When EXPERIENCING FastClip, I found the following features in monitoring and pasting:

  • The application records only the most recent replication
  • If the copy paste board already exists data, the database will advance
  • There are also some automatic identification websites such as Zhihu, etc.

FastClipThe effect picture is as follows (interested students can download the experience by themselves — 1RMB is required) :

According to the above characteristics, the idea is clear, the main core idea is how to obtain the data of the paste board (call time is from the background into the application)

The following contents will be introduced in this paper:

  • How do I call a method when I enter an application in the background
  • How does ClipBoard implement the function of copy and paste
  • Get ClipBoard data when entering the application from the background
  • Render the data in the list to the page, copy it, and remove it

Front and back call methods (didChangeAppLifecycleState)

Here involves lifecycle callback didChangeAppLifecycleState method

In didChangeAppLifecycleState callback method, a parameter type for AppLifecycleState enumeration class, the enumeration class is a Flutter of App lifecycle state of encapsulation, Common states include inactive, paused, and resumed

  • inactive: is inactive and cannot process user responses
  • paused: Invisible and unable to respond to user input, but continuing in the background
  • resumed: visible and responsive to user input

The specific call process is as follows:

To use this callback method, we need to register the listener in initState and remove the listener in Dispose as follows

@override void initState() { // TODO: implement initState super.initState(); WidgetsBinding.instance! .addObserver(this); Override void dispose() {// TODO: implement Dispose WidgetsBinding. .removeObserver(this); // Dispose listener super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { // TODO: implement didChangeDependencies super.didChangeAppLifecycleState(state); If (state = = AppLifecycleState. Resumed) {/ / obtain clipboard data}}Copy the code

ClipBoardHow do I copy and paste

Copy and paste in ClipBoard is very simple, call setData method to copy, call getData method to paste, the specific code is as follows

Void getPasteData() async {ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); print('data content ${data? .text}'); Void setPasteData(text) {ClipboardData = ClipboardData(text: text); Clipboard.setData(clipboardData); }Copy the code

Obtained from the background when entering the applicationClipBoardThe data of

At this time, I thought it was very simple and I only needed to call the written method to get the stickboard data. However, when I ran it, I found that the data I got was null, which once made me confused. I tried to interrupt the point to check the data, but found that the following code was executed twice

 ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
Copy the code

At this time the data is obtained, I guess at that time with a delay should be able to process, but still Google (Baidu did not find, teasing: Lot of things, baidu search not search, Google came out, see article), and I guess that’s right, there are bosses this method has solved using delay (article, of course, there are many other solution, because I think the beginning also depend on delay to deal with, so I didn’t try other methods), the following is after the modification of code:

@override void didChangeAppLifecycleState(AppLifecycleState state) { // TODO: implement didChangeDependencies super.didChangeAppLifecycleState(state); / / the background into the application of the if (state = = AppLifecycleState. Resumed) {/ / obtain clipboard data Future. At this time of (Duration (milliseconds: 500)).then((_) =>getPasteData()); }}Copy the code

Render the data in the list to the page, copy it, and remove it

Encapsulate data

Get ClipBoard data and encapsulate it into a List collection

The following code

final List<PasteModel> pasteList = []; Void getPasteData() async {ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); print('data content ${data? .text}'); // Check whether the data is empty if (data! = null && data.text! .isNotEmpty) { int index = -1; PasteModel? tempPaste = null; for (int i = 0; i < pasteList.length; i++) { if (pasteList[i].content == data.text) { tempPaste = pasteList[i]; index = i; break; } } if (index > 0) { pasteList.remove(index); } else if (index == -1) { tempPaste = PasteModel(content: data.text! , show: false); } if (index ! = 0) { pasteList.insert(0, tempPaste!) ; setState(() { pasteList; }); }}}Copy the code

Related entity class

Class PasteModel {// Copy content final String content; Bool show; PasteModel({required this.content, this.show = false}); }Copy the code

List rendering + copy and paste and other functions

@override Widget build(BuildContext context) { return Scaffold( appBar: CommonBar( title: 'Fast Clip', ), body: Center( child: Column( children: [ Container( color: secondBgColor, padding: EdgeInsets.fromLTRB(12, 6, 12, 12), child: CommonSearch(hint: 'search record ', icon: icon (CupertinoIcons. Search), onTap: () => {// TODO access search},), Expanded(// color: secondBgColor, child: pasteList.length > 0 ? ListView( children: buildPasteList(), ) : Text('No Data'), ) ], ), )); } List<Widget> buildPasteList() { List<Widget> pasteWidget = []; pasteList.forEach((element) { pasteWidget.add(new Container( padding: EdgeInsets.fromLTRB(0, 12, 0, 12), child: new GestureDetector( onHorizontalDragEnd: (endDetails) { print(element.content.toString()); setState(() { element.show = ! element.show; }); }, child: Container(// height: 40.0, decoration: new BoxDecoration(border: new border (bottom: BorderSide(color: Colors. Amber, width: 0.5),)), child: new Row(children: element.show? [ Container( width: 250, padding: EdgeInsets.fromLTRB(12, 12, 12, 12), child: Text( element.content, style: TextStyle(color: primaryColor), )), Spacer(), new CommonButton( text: 'copy', radius: 0, onTap: () { setPasteData(element.content); }, ), new CommonButton( text: 'remove', gradient: LinearGradient( colors: [Color(0xffed2856), Colors.red]), radius: 0, onTap: () { pasteList.remove(element); setState(() { pasteList; }); }, ) ] : [ Container( width: 250, padding: EdgeInsets.fromLTRB(12, 12, 12, 12), child: Text( element.content, style: TextStyle(color: primaryColor), )) ]), ), ), )); }); return pasteWidget; }}Copy the code

The renderings are as follows:

Reference documents: github.com/flutter/flu…

conclusion

In fact, the principle of realizing the ClipBoard is very simple, that is, when switching between front and back, the data in the ClipBoard can be obtained and the relevant data can be processedCopy the code