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-
Related
Actions fail to show.
And, they also fail to show with these downloaded notification demo apps
- LocalNotifications by Bart Jacobs
- RemindMe by Keith Harrison (Use Your Loaf)
- EatMoreVegetable by Brian Advent
Interestingly, I can make action button appear by doing this:
Step
1) In app, fire notification request
2) Leave app - go to Home screen
3) Notification appears without action button
4) Drag notification down causes action button to appear
Same results with simulator or device.
My demo app can be downloaded from here
https://github.com/tricarb/UNLocalDemo
func registerCategories() {
let center = UNUserNotificationCenter.current()
let actionID = Notify.actionID.rawValue
let categoryID = Notify.categoryId.rawValue
let action = UNNotificationAction(identifier: actionID, title: "Action Title", options: [.foreground])
let category = UNNotificationCategory(identifier: categoryID, actions: [action], intentIdentifiers: [])
center.setNotificationCategories([category])
}
func fireNotification() {
let content = UNMutableNotificationContent()
content.title = "Content Title"
content.body = "This is the content body"
content.categoryIdentifier = Notify.categoryId.rawValue
let timeInterval = TimeInterval(7)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
if let error = error {
print(error.localizedDescription)
} else {
print("Notification will fire in", timeInterval, "seconds")
}
}
}
To get action button to show you need to swipe the notification to the left (in notification center). There you'll see three buttons: "Manage", "View", "Clear".
Select "View" and you'll get the same behavior as you have when you drag down the notification that just appeared.
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
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
}
}
Since UIAlertView is deprecated I want to replace it by UIAlertController in my old libraries.
But it is not always obvious to do. For example I have those two functions, doing a very similar task.
showAlertViewMessageBox uses UIAlertView and showMessageBox uses UIAlertController:
func showAlertViewMessageBox(_ msg:String, title:String, caller:UIViewController) {
let userPopUp = UIAlertView()
userPopUp.delegate = caller
userPopUp.title = title
userPopUp.message = msg
userPopUp.addButton(withTitle: "OK")
userPopUp.show()
}
func showMessageBox(_ msg:String, title:String, caller:UIViewController) {
let attribMsg = NSAttributedString(string: msg,
attributes: [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 23.0)])
let userPopUp = UIAlertController(title:title,
message:nil, preferredStyle:UIAlertController.Style.alert)
userPopUp.setValue(attribMsg, forKey: "attributedMessage")
let alertAction = UIAlertAction(title:"OK", style:UIAlertAction.Style.default,
handler:{action in})
alertAction.setValue(UIColor.darkGray, forKey: "titleTextColor")
userPopUp.addAction(alertAction)
caller.present(userPopUp, animated: true, completion: nil)
}
I want to use showMessageBox as much as possible. But I have this unhappy situation:
In the following code:
//showMessageBox(usrMsg, title: popTitle, caller: self)
showAlertViewMessageBox(usrMsg, title: popTitle, caller: self)
quitViewController()
When using showAlertViewMessageBox, the message will pop up and stay there until I click the OK button.
(This is the behavior I want)
When using showMessageBox, the message will pop up as a blink and disappear without waiting for me to click the OK button.
(This is NOT the behavior I want)
How should I modify showMessageBox to get the behavior I want?
Assuming you are dismissing the viewController inside quitViewController() method, it is very natural that the message will pop up as a blink and disappear without waiting for me to click the OK button. As your quitViewController() method is executed without waiting for the OK button clicked.
One way, is adding a parameter to handle OK button clicking:
func showMessageBox(_ msg:String, title:String, caller:UIViewController, onOk: #escaping ()->Void) {
let attribMsg = NSAttributedString(string: msg,
attributes: [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 23.0)])
let userPopUp = UIAlertController(title:title,
message:nil, preferredStyle:UIAlertController.Style.alert)
userPopUp.setValue(attribMsg, forKey: "attributedMessage")
let alertAction = UIAlertAction(title:"OK", style:UIAlertAction.Style.default,
handler:{action in onOk()}) //<- Call the Ok handler
alertAction.setValue(UIColor.darkGray, forKey: "titleTextColor")
userPopUp.addAction(alertAction)
caller.present(userPopUp, animated: true, completion: nil)
}
Use it as:
showMessageBox(usrMsg, title: popTitle, caller: self) {
self.quitViewController()
}
By the way, attributedMessage of UIAlertController and titleTextColor of UIAlertAction are private properties, so using this code may risk your app to be rejected by using private APIs.
We have implemented Actionable Notification using Notification Extension Service. We receive push notifications and it shows the proper content for notification title, body, action buttons. We have defined 3 category say onebtn, twobtn, threebtn and all the unique actions for every category.
So, everything works fine for one notification but as we receive more than one notification in notification tray the recent notification action button's text replace to all other notification's action button's text. Ex. I have received notification for category threebtn then it will show me three buttons with three different texts say Now, Later and Cancel(These three button names will be the part of pay load received from push notification). Now I have received one more notification for category twobtn with button names, Reply & Mark as read and shown for that notification.
Now the issue is, it overwrites the button names of category twobtn to the notification which is received for threebtn notification. It means when I drag and open notification of category threebtn, its button names will be Reply, Mark as paid & Cancel (third default text defined while assigning action). So every notification will have name Reply & Mark as Paid.
Tried Solutions:
Set categories to plist as dictionary under NSNotification (previously we added categories at runtime)
Assigned unique action and category name.
I am stuck with this issue since a week but not finding any proper solution. Kindly provide me some hint so I can fix this.
Thanks.
class NotificationService: UNNotificationServiceExtension {
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
let (pushNotificationBean, _) = saveNotificationAppGroupDefault(saveNotificationUserInfo: request.content.userInfo)
registerNotificationCategory(pushNotificationBean: pushNotificationBean)
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
}
// MARK: - Register Notificaion Categories and Actions
func registerNotificationCategory(pushNotificationBean: PushNotificationBean) {
// Define Actions
if #available(iOS 10.0, *) {
// Define Action Yes
var singleBtnAction : UNNotificationAction
var trippleBtnYesAction : UNNotificationAction
var trippleBtnNoAction : UNNotificationAction
var trippleBtnPartialAction : UNNotificationAction
var doubleBtnYesAction : UNNotificationAction
var doubleBtNoAction : UNNotificationAction
// Positve Button Text
if let okActionText = pushNotificationBean.actionPositiveText, okActionText.count > 0{
// Single Button Action
singleBtnAction = UNNotificationAction(identifier: self.OkAction,
title: okActionText,
options: .foreground)
// Double Button Action
doubleBtnYesAction = UNNotificationAction(identifier: self.YesAction,
title: okActionText,
options: .foreground)
// Tripple Button Action
trippleBtnYesAction = UNNotificationAction(identifier: self.YesAction,
title: okActionText,
options: .foreground)
}else{
// Single Button Action
singleBtnAction = UNNotificationAction(identifier: self.OkAction,
title: self.OkAction,
options: .foreground)
// Double Button Action
doubleBtnYesAction = UNNotificationAction(identifier: self.YesAction,
title: self.YesAction,
options: .foreground)
// Tripple Button Action
trippleBtnYesAction = UNNotificationAction(identifier: self.YesAction,
title: self.YesAction,
options: .foreground)
}
// Negative Action Text
if let noActionText = pushNotificationBean.actionNegativeText, noActionText.count > 0{
// Double Button Action
doubleBtNoAction = UNNotificationAction(identifier: self.NoAction,
title: noActionText,
options: .foreground)
// Tripple Button Action
trippleBtnNoAction = UNNotificationAction(identifier: self.NoAction,
title: noActionText,
options: .foreground)
} else{
// Double Button Action
doubleBtNoAction = UNNotificationAction(identifier: self.NoAction,
title: self.NoAction,
options: .foreground)
// Tripple Button Action
trippleBtnNoAction = UNNotificationAction(identifier: self.NoAction,
title: self.NoAction,
options: .foreground)
}
// Partial Action Text
if let trippleBtnPartialActionText = pushNotificationBean.actionNeutralText, trippleBtnPartialActionText.count > 0{
// Tripple Button Action
trippleBtnPartialAction = UNNotificationAction(identifier: self.PartialAction,
title: trippleBtnPartialActionText,
options: .foreground)
}else{
// Tripple Button Action
trippleBtnPartialAction = UNNotificationAction(identifier: self.PartialAction,
title: self.PartialAction,
options: .foreground)
}
// Define Single Category
let singleButtonCategory = UNNotificationCategory(identifier: self.SingleButton,
actions: [singleBtnAction],
intentIdentifiers: [self.OkAction],
options: [])
// Define Double Category
let doubleButtonCategory = UNNotificationCategory(identifier: self.DoubleButton,
actions: [doubleBtnYesAction,doubleBtNoAction],
intentIdentifiers: [self.YesAction,self.NoAction],
options: [])
// Define Tripple Category
let tripleButtonCategory = UNNotificationCategory(identifier: self.TripleButton,
actions: [trippleBtnYesAction,trippleBtnNoAction,trippleBtnPartialAction],
intentIdentifiers: [self.YesAction,self.NoAction,self.PartialAction],
options: [])
UNUserNotificationCenter.current().setNotificationCategories([singleButtonCategory,doubleButtonCategory,tripleButtonCategory])
}
}
}