iOS UIMenuController UIMenuItem Part 2 With Examples

This is the second part in the series of tutorials on UIMenuController. In this tutorial, we’ll be implementing the UIMenuController on a Label and UITextField. We’ll see how can switch from one to the other. Also, we’ll be implementing Custom Copy Paste using UIPasteboard on a UIMenuItem in our iOS Application.

UIMenuController and UIMenuItem

In the previous tutorial, we saw how to add a UIMenuController on a UITextField.
Now a UITextField by default has events to detect touch events and is the first responder as well.

In order to show a UIMenuController on a UILabel, we need to do the following things:

  • Override canBecomeFirstResponder property and return true.
  • Execute becomeFirstResponder() method on the UILabel.

How do we set touch events on a UILabel?Answer: UIGestureRecogniser

Now, using a UIGestureRecogniser we can set a long press on the UILabel. Doing so, we will show the UIMenuController over the UILabel.

How is it positioned over the label?

By passing the UILabel reference in the setTargetRect method as we had discussed in the previous tutorial.

How will we set the UIResponder back to the UITextField when it is clicked again?

In order to do this, we must override the textFieldDidBeginEditing and textFieldDidEndEditing.
The first would get triggered when the UITextField is clicked. Here we will set the becomeFirstResponder() on the UITextField instance.

In the textFieldDidEndEditing, we will call resignFirstResponder.

We must create a subclass of UILabel inside which we will override the canPerformAction method. Here we will enable the UIMenuItems for the UIlabel only.

Now since we need to use UILabel and UITextField together with the UIMenuController, we should subclass the UITextField as well and implement the canPerformAction of it separately. This way the canPerformAction of each of the subclasses would be independent of one another.

To add/remove a UIMenuItem to/from an Array, we do:

The first method appends a UIMenuItem to the end of the array and second removes the UIMenuItem from an index passed.

We have two more variants for adding and removing UIMenuItems:

The second method, removes all UIMenuItems which matches the Predicate.
Example to remove all Menu Items with the title “Menu JD” we do:

Updating the Menu
Once you modify a UIMenuController and change any of the UIMenuItem, you must call update() on the UIMenuController for updating the Menu with the new appearance. Otherwise, the UIMenuController, would still show the previous Menu.

Let’s talk code in the next section with our sample iOS Application.

Code

Let’s write the subclass for UITextField first:

JDTextField.swift

In the above code, we have the implementation of the 4 UIMenuItem actions.
When Menu 3 is clicked, we remove it and add Menu 4 and vice-versa.
Inside the customPaste action, we are pasting the string from the UIPasteBoard.

Let’s next look at the implementation of JDLabel.swift

In the above code, sharedInit() is where we set isUserInteractionEnabled to true and add the gesture recognizer.
showLabelMenu() is where we initialise the UIMenuController
When the long press Gestture happens, we call the function firstResponder. Here we set the UILabel to becomeFirstResponder in order to display the UIMenuController when the Label is clicked.
Besides the three actions, we have implemented the copy action as well in the Menu.
Inside the copy function, we use UIPasteBoard class to copy the label text. This is eventually pasted in the UITextField.

Our Main.storyboard looks like this:

ios-uimenucontroller-uipasteboard-storyboard

Make sure that you’ve set the subclass in the Attributes Inspector for each of them.

The code for the ViewController.swift is given below:

A lot is happening above:

  • menuControllerForTextField() is called when the textFieldDidBeginEditing gets triggered(on focusing UITextField).
  • Inside menuControllerForTextField() we create the UIMenuController for the UITextField with 4 UIMenuItems.
  • Actions for each of them were defined in the JDTextField.swift class.
  • Note: we’ve declared UIMenuController instance outside the class to use it globally.
  • touchesBegan gets triggered when the user clicks anywhere on the View outside of the UITextField. In this case, the endEditing call triggers the textFieldDidBeginEditing as well inside which we remove the responder from the UITextField
  • textFieldShouldReturn is called when the return key is pressed on the keyboard. Here also we resign the responder in order to dismiss the keyboard.

The output of the application in action is given below:

ios-uimenucontroller uipasteboard final output

So in the above output, we were able to implement copy paste as well as adding and removing menu items in our UIMenuController. When you click on any of the Menu Items, you’ll notice that the methods defined in their respective subclass are executed.

This brings an end to this tutorial. We used UIPasteboard along with UIMenuController. You can download the project from the link below

By admin

Leave a Reply

%d bloggers like this: