UIContextMenuActionProvider puts unwanted checkmark icons on items - ios

The problem
I was implementing UIContextMenuInteraction, and ended up with the behavior I can't explain or find fixes too. The issue as seen from the screen shot that menu items have checkmarks. This is not intended and those checkmarks added automatically. Ideally I'd like use SF Symbols, but any image I add ends up being this checkmark. Even if I set image to nil, it still adds this weird checkmark.
Additional steps taken: Reinstall SF Symbols and SF Pro, Clean build, Restart xCode / Simulator
Reproduced: Simulator iOS 13.3, iPhone 7 iOS 13.3
System: Catalina 10.15.1, xCode 11.3.1
Code:
import UIKit
class ViewController: UIViewController {
let sampleView = UIView(frame: CGRect(x: 50, y: 300, width: 300, height: 200))
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(sampleView)
sampleView.backgroundColor = .systemIndigo
let interaction = UIContextMenuInteraction(delegate: self)
sampleView.addInteraction(interaction)
}
}
extension ViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint
) -> UIContextMenuConfiguration? {
let actionProvider: UIContextMenuActionProvider = { [weak self] _ in
let like = UIAction(
title: "Like",
image: UIImage(systemName: "heart"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .on
) { _ in
}
let copy = UIAction(
title: "Copy",
image: nil,
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .on
) { _ in
}
let delete = UIAction(
title: "Delete",
image: UIImage(systemName: "trash"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [.destructive],
state: .on
) { _ in
}
return UIMenu(
title: "",
image: nil,
identifier: nil,
options: [],
children: [
like, copy, delete
]
)
}
let config = UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: actionProvider)
return config
}
}

You need to change UIAction.state from .on to .off to get rid of the checkmark.

Related

Change UIMenu title with multiple line (UIMenu with UIButton)

I added UIMenu to the UIButton.menu with long title, but menu show not full text. Is there anyway to change it to show full text ? thanks for help
let _: [()] = (0...100).map {
childdrens.append(UIAction(title: "This is a very very very very very very very very very long title \($0)", handler: { _ in
}))
}
longCapMenuButton = UIMenu(title: "", options: .displayInline, children: childdrens )
longCapMenuButton.showsMenuAsPrimaryAction = true
Screenshot Attached below-

ios 13 UIContextMenu shows shortened UIAction titles

I decided to addUIContextMenuInteraction to my UITableViewCell, it works fine, but the title that has 9+ letters (without image) or 6+ letters(with image) is getting shortened like this:
Implementation of delegate method:
extension MyCustomCell: UIContextMenuInteractionDelegate {
#available(iOS 13.0, *)
func contextMenuInteraction(_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ -> UIMenu in
let first = UIAction(title: "8Letters") { _ in
print("8 letters")
}
let second = UIAction(title: "9Letters+") { _ in
print("9 letters")
}
let third = UIAction(title: "Hello", image: UIImage(systemName: "square.and.arrow.up")) { _ in
print("5 letters + image")
}
let fourth = UIAction(title: "Hello+", image: UIImage(systemName: "square.and.arrow.up")) { _ in
print("6 letters + image")
}
return UIMenu(title: "", children: [first, second, third, fourth])
}
}
}
Check if any third party framework added to your project for customising the UITableViewCell is breaking the UI. In my case, the issue is caused by third party framework ( "SkeletonView") which I had added to give shimmer effect to UITableViewCell

iOS 13.0 UIMenu and UIAction for UIContextMenuConfiguration

I'm trying to use the new APIs introduced in iOS 13.0 Beta. I have downloaded Xcode 11.0 Beta 3 to be able to access these API.
Some of the code I found online does things like:
extension SingleViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
let configuration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { actions -> UIMenu<UIAction>? in
// Creating Save button
let save = UIAction(__title: "Save", image: UIImage(systemName: "tray.and.arrow.down.fill"), options: []) { action in
// Just showing some alert
self.showAlert(title: action.title)
}
// Creating Rotate button
let rotate = UIAction(__title: "Rotate", image: UIImage(systemName: "arrow.counterclockwise"), options: []) { action in
self.showAlert(title: action.title)
}
// Creating Delete button
let delete = UIAction(__title: "Delete", image: UIImage(systemName: "trash.fill"), options: .destructive) { action in
self.showAlert(title: action.title)
}
// Creating Edit, which will open Submenu
let edit = UIMenu<UIAction>.create(title: "Edit...", children: [rotate, delete])
// Creating main context menu
return UIMenu<UIAction>.create(title: "Menu", children: [save, edit])
}
return configuration
}
}
This seems fine but doesn't even compile in my Xcode. The errors I get are:
Cannot specialize non-generic type 'UIMenu' Replace '<UIAction>' with ''
on creating configuration constant.
Type of expression is ambiguous without more context
on creating save action.
and couple other similar errors.
I should also mention, I don't even have the constructors that are in this format:
UIAction(__title: "String", image: UIImage, options: Array)
UIMenu.create(...)
Why are these missing in Xcode-11 beta 3.0 ?
Well, it changed. It's a beta! And I would expect it to change again, but for now, in beta 3, the initializer for UIAction is
init(__title title: String, image: UIImage?, identifier: UIAction.Identifier?,
handler: #escaping UIActionHandler)
UIMenu is not generic, and its initializer is
init(__title title: String, image: UIImage?, identifier: UIMenu.Identifier?,
options: UIMenu.Options = [], children: [UIMenuElement])
So here's a rewrite of your code that does compile under beta 3:
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
let configuration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { actions -> UIMenu? in
let save = UIAction(__title: "Save", image: UIImage(systemName: "tray.and.arrow.down.fill"), identifier: nil) { action in
// whatever
}
let rotate = UIAction(__title: "Rotate", image: UIImage(systemName: "arrow.counterclockwise"), identifier: nil) { action in
// whatever
}
let delete = UIAction(__title: "Delete", image: UIImage(systemName: "trash.fill"), identifier: nil) { action in
// whatever
}
let edit = UIMenu(__title: "Edit", image: nil, identifier: nil, children:[rotate,delete])
return UIMenu(__title: "Menu", image: nil, identifier: nil, children:[save, edit])
}
return configuration
}
In Xcode 11.0 Beta 5, you can now write:
extension SingleViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
let configuration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { actions -> UIMenu? in
// Creating Save button
let save = UIAction(title: "Save", image: UIImage(systemName: "tray.and.arrow.down.fill")) { action in
// Just showing some alert
self.showAlert(title: action.title)
}
// Creating Rotate button
let rotate = UIAction(title: "Rotate", image: UIImage(systemName: "arrow.counterclockwise")) { action in
self.showAlert(title: action.title)
}
// Creating Delete button
let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash.fill"), attributes: .destructive) { action in
self.showAlert(title: action.title)
}
// Creating Edit, which will open Submenu
let edit = UIMenu(title: "Edit...", children: [rotate, delete])
// Creating main context menu
return UIMenu(title: "Menu", children: [save, edit])
}
return configuration
}
}
The classes are no longer generic e.g. UIMenu instead of UIMenu<UIAction>.
Comprehensive Swift initializers let you drop optional params, which have reasonable default values e.g. image, attributes and identifier.
No more UIMenu<UIAction>.create(...) or UIAction(__title:...). They're all real initializers now, yay!
On swift 5, this works:
extension ViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
let configuration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { actions -> UIMenu? in
// Creating Save button
let save = UIAction(title: "Save", image: UIImage(systemName: "tray.and.arrow.down.fill")) { action in
// Just showing some alert
self.showAlert(title: action.title)
}
// Creating Rotate button
let rotate = UIAction(title: "Rotate", image: UIImage(systemName: "arrow.counterclockwise")) { action in
self.showAlert(title: action.title)
}
// Creating Delete button
let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash.fill")) { action in
self.showAlert(title: action.title)
}
// Creating Edit, which will open Submenu
let edit = UIMenu(title: "Edit...", children: [rotate, delete])
// Creating main context menu
return UIMenu(title: "Menu", children: [save, edit])
}
return configuration
}
}

how to dismiss the alert programatically using swift?

Hi I am new for developing ios application.I have used some cocopods framework for doing the alert view. I have used alert view following mentioned sweetAlert. In that I have tried to dismiss the alert programmatically with out press the tab button in alert.Please any one help for fix the problem.
You can dismiss the alert by calling dismissViewControllerAnimated method on alertController object.
alertControllerObject?.dismissViewControllerAnimated(true, completion: nil)
I think you can use pressed(sender: UIButton!) method in SweetAlert class.
#IBAction func aBasicMessageAlert(sender: AnyObject) {
let sweetAlert = SweetAlert().showAlert("Here's a message!")
close(sweetAlert, after: 2.0)
}
func close(alert: SweetAlert, after seconds: Double) {
NSTimer.scheduledTimerWithTimeInterval(seconds,
target: self,
selector: #selector(closeAlert),
userInfo: ["alert": alert],
repeats: true)
}
func closeAlert(timer: NSTimer) {
let alert = timer.userInfo!["alert"] as! SweetAlert
let dummyCloseButton = UIButton()
dummyCloseButton.tag = 0
alert.pressed(dummyCloseButton)
}
Use this,
yourAlerView.dismiss(withClickedButtonIndex: 0, animated: true)
when you handle the return key.
ButtonIndex is index of button you want to click by default to hide alert.
Hope this will help you.
Try This
When you call Alert Method Also Called this, Inside the alert Method
NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "hideAlert:", userInfo: userInfo, repeats: true) //repeats: false
Called This outside the Alert Method
func hideAlert(){
isOtherButton == true// isOtherButton getting from your SweetAlert Demo
}
You need to add this method in SweetAlert, and call it.
func closeAlert(){
UIView.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in
self.view.alpha = 0.0
}) { (Bool) -> Void in
self.view.removeFromSuperview()
self.cleanUpAlert()
//Releasing strong refrence of itself.
self.strongSelf = nil
}
}
Implement alert like this
let alert = SweetAlert() // take this as global
func showAlert(){
alert.showAlert(title as String, subTitle: msg as String, style: style, buttonTitle:buttonOtherTitle as String, buttonColor:UIColor.redColor() , otherButtonTitle: buttonOkTitle as String, otherButtonColor: colors.KBlueTextColor!) { (isOtherButton) -> Void in
if isOtherButton
{
completionHandler(false)
}
else
{
completionHandler(true)
}
}
}
func CloseAlert(){
alert.closeAlert()
}

Launching App Store from App in Swift

I am creating an app, and I have a banner which promotes my other app. This is my code:
var barsButton : UIButton = UIButton(frame: CGRectMake((self.view.bounds.width / 2) - 51, self.view.bounds.height - 100, 102, 30))
barsButton.setImage(UIImage(named: "Bars Icon 2.png"), forState: .Normal)
barsButton.addTarget(self, action: "openBarsLink", forControlEvents: UIControlEvents.TouchUpInside)
func openBarsLink() {
var barsLink : String = "itms-apps:https://itunes.apple.com/app/bars/id706081574?mt=8"
UIApplication.sharedApplication().openURL(NSURL.URLWithString(barsLink))
}
However, when the user presses the button, it just takes them to the App Store, and not the specific page for my app. What am I doing wrong?
You have too many protocols in your URL. Get rid of https: so the URL reads
itms-apps://itunes.apple.com/app/bars/id706081574
Just by following older answers I couldn't make it work, so here I post my complete solution:
if let url = NSURL(string: "itms-apps://itunes.apple.com/app/id1234567890"),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.openURL(url)
}
}
Use just the short "itms://".
For Swift 3 this is the snippet:
UIApplication.shared.openURL(URL(string: "itms://itunes.apple.com/app/id" + appStoreAppID)!)
I hope this helps someone.
Cheers.
P.S. #Eric Aya was ahead of the time :)
I had this problem but this code just works on the phone not simulator. So check this code:
if let url = URL(string: "itms-apps://itunes.apple.com/app/id" + APP_ID ),
UIApplication.shared.canOpenURL(url){
UIApplication.shared.openURL(url)
}else{
//Just check it on phone not simulator!
print("Can not open")
}
As openURL is deprecated from iOS 10 use below code:
UIApplication.shared.open((URL(string: "itms://itunes.apple.com/app/" + appStoreAppID)!), options:[:], completionHandler: nil)
Simply you can use these functions in a utility struct to goto app page in app store also you can goto rate app view directly:
static func gotoApp(appID: String, completion: ((_ success: Bool)->())? = nil) {
let appUrl = "itms-apps://itunes.apple.com/app/id\(appID)"
gotoURL(string: appUrl, completion: completion)
}
static func rateApp(appId: String, completion: ((_ success: Bool)->())? = nil) {
//let appUrl = "itms-apps://itunes.apple.com/app/" + appId
let appUrl = "https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=\(appId)&pageNumber=0&sortOrdering=2&type=Purple+Software&mt=8"
//TODO: use &action=write-review for opening review directly
print("app review URL: ", appUrl)
gotoURL(string: appUrl, completion: completion)
}
static func gotoURL(string: String, completion: ((_ success: Bool)->())? = nil) {
print("gotoURL: ", string)
guard let url = URL(string: string) else {
print("gotoURL: invalid url", string)
completion?(false)
return
}
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:], completionHandler: completion)
} else {
completion?(UIApplication.shared.openURL(url))
}
}
Swift 3 - XCode 8.2.1
UIApplication.shared.openURL(URL(string: "itms-apps://itunes.apple.com/app/id" + appStoreAppID)!)
Link you are trying to open is not valid - remove https: schema from it (or itms: - but I suggest first option, to avoid redirects)
I use this and it works.
let locale: String = Locale.current.regionCode ?? "US"
UIApplication.shared.open(URL(string: "https://apps.apple.com/\(locale)/developer/{developer-name}/{idXXXXXXXXXX}")!, options: [:], completionHandler: nil)

Resources