咆哮/吐司风格的iOS通知库

任何人都可以推荐一个库在iOS上实现咆哮或吐司风格的通知? 例如,用户保存configuration文件后,我想要通知淡入,逗留3秒,报告“configuration文件保存”,并淡出。 现在我有一个UIAlertView,用一个“确定”button来中断用户的工作stream程,而且我觉得这太过分了。

Android Toast类是我在iOS上寻找的一个例子。

谢谢!

我创build了一个我认为很有用的解决scheme: https : //github.com/scalessec/toast

它被写为一个obj-c类,基本上把makeToast方法添加到UIView的任何实例。 例如:

[self.view makeToast:@"Profile saved" duration:2.0 position:@"bottom"]; 

我这样解决了它:

  1. 在您的视图上创build通用标签。 把它全部放在屏幕上,给它一个你需要的大小,然后把文本放在里面。
  2. 将它的位置设置为“顶部” – 此标签必须低于控件列表中的所有控件。
  3. 将它添加到接口,属性,综合(我们称之为“toastLabel”那里)。
  4. 在您的XIB文件中将“toastLabel”
  5. 添加以下行到您的viewWillAppear隐藏标签开始:

     [toastLabel setHidden:TRUE]; 
  6. 在button单击(或其他事件)上添加以下代码:

     toastLabel.text = @"Our toast text"; [toastLabel setHidden:TRUE]; [toastLabel setAlpha:1.0]; CGPoint location; location.x = 160; location.y = 220; toastLabel.center = location; location.x = 160; location.y = 320; [toastLabel setHidden:FALSE]; [UIView animateWithDuration:0.9 animations:^{ toastLabel.alpha = 0.0; toastLabel.center = location; }]; 

这个标签将“倒下”,消失。

虽然有点晚,但我承认:

https://github.com/pcperini/PCToastMessage

你可以试试我的开源库TSMessages: https : //github.com/toursprung/TSMessages

在iOS 5/6和iOS 7上使用起来非常简单,看起来很漂亮。

我做了我自己的。 由克里斯南连接的类是丑陋的,没有正确旋转。

https://github.com/esilverberg/ios-toast

以下是它的样子: 在这里输入图像说明

我是这样做的:

 + (void)showToastMessage:(NSString *)message { UIAlertView *toast = [[UIAlertView alloc] initWithTitle:nil message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil]; [toast show]; // duration in seconds int duration = 2; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [toast dismissWithClickedButtonIndex:0 animated:YES]; }); 

}

更新iOS9 +的解决scheme:

 + (void)showToastMessage:(NSString *)message root:(id)view { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert]; // duration in seconds int duration = 2; [view presentViewController:alertController animated:YES completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [alertController dismissViewControllerAnimated:YES completion:nil]; }); } 

MBProgressHUD ?

嘿,你正在寻找这个。

https://github.com/PaulSolt/WEPopover#readme

这一个正是你想要的。 这是一个非常方便,因为它有一个完成块,请看看:) https://github.com/PrajeetShrestha/EkToast

Swift 2.0:

这个想法是解决CocoaPods上零依赖的Toast类。

参考: https //github.com/scalessec/Toast-Swift

创build一个空的Swift文件(文件 – 新build文件 – 清空Swift文件 – 将其命名为Toast。)

将下面的代码添加到它。

 // Toast.swift import UIKit import ObjectiveC enum ToastPosition { case Top case Center case Bottom } extension UIView { private struct ToastKeys { static var Timer = "CSToastTimerKey" static var Duration = "CSToastDurationKey" static var Position = "CSToastPositionKey" static var Completion = "CSToastCompletionKey" static var ActiveToast = "CSToastActiveToastKey" static var ActivityView = "CSToastActivityViewKey" static var Queue = "CSToastQueueKey" } private class ToastCompletionWrapper { var completion: ((Bool) -> Void)? init(_ completion: ((Bool) -> Void)?) { self.completion = completion } } private enum ToastError: ErrorType { case InsufficientData } private var queue: NSMutableArray { get { if let queue = objc_getAssociatedObject(self, &ToastKeys.Queue) as? NSMutableArray { return queue } else { let queue = NSMutableArray() objc_setAssociatedObject(self, &ToastKeys.Queue, queue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) return queue } } } // MARK: - Make Toast Methods func makeToast(message: String) { self.makeToast(message, duration: ToastManager.shared.duration, position: ToastManager.shared.position) } func makeToast(message: String, duration: NSTimeInterval, position: ToastPosition) { self.makeToast(message, duration: duration, position: position, style: nil) } func makeToast(message: String, duration: NSTimeInterval, position: CGPoint) { self.makeToast(message, duration: duration, position: position, style: nil) } func makeToast(message: String, duration: NSTimeInterval, position: ToastPosition, style: ToastStyle?) { self.makeToast(message, duration: duration, position: position, title: nil, image: nil, style: style, completion: nil) } func makeToast(message: String, duration: NSTimeInterval, position: CGPoint, style: ToastStyle?) { self.makeToast(message, duration: duration, position: position, title: nil, image: nil, style: style, completion: nil) } func makeToast(message: String?, duration: NSTimeInterval, position: ToastPosition, title: String?, image: UIImage?, style: ToastStyle?, completion: ((didTap: Bool) -> Void)?) { var toastStyle = ToastManager.shared.style if let style = style { toastStyle = style } do { let toast = try self.toastViewForMessage(message, title: title, image: image, style: toastStyle) self.showToast(toast, duration: duration, position: position, completion: completion) } catch ToastError.InsufficientData { print("Error: message, title, and image are all nil") } catch {} } func makeToast(message: String?, duration: NSTimeInterval, position: CGPoint, title: String?, image: UIImage?, style: ToastStyle?, completion: ((didTap: Bool) -> Void)?) { var toastStyle = ToastManager.shared.style if let style = style { toastStyle = style } do { let toast = try self.toastViewForMessage(message, title: title, image: image, style: toastStyle) self.showToast(toast, duration: duration, position: position, completion: completion) } catch ToastError.InsufficientData { print("Error: message, title, and image cannot all be nil") } catch {} } // MARK: - Show Toast Methods func showToast(toast: UIView) { self.showToast(toast, duration: ToastManager.shared.duration, position: ToastManager.shared.position, completion: nil) } func showToast(toast: UIView, duration: NSTimeInterval, position: ToastPosition, completion: ((didTap: Bool) -> Void)?) { let point = self.centerPointForPosition(position, toast: toast) self.showToast(toast, duration: duration, position: point, completion: completion) } func showToast(toast: UIView, duration: NSTimeInterval, position: CGPoint, completion: ((didTap: Bool) -> Void)?) { objc_setAssociatedObject(toast, &ToastKeys.Completion, ToastCompletionWrapper(completion), .OBJC_ASSOCIATION_RETAIN_NONATOMIC); if let _ = objc_getAssociatedObject(self, &ToastKeys.ActiveToast) as? UIView where ToastManager.shared.queueEnabled { objc_setAssociatedObject(toast, &ToastKeys.Duration, NSNumber(double: duration), .OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(toast, &ToastKeys.Position, NSValue(CGPoint: position), .OBJC_ASSOCIATION_RETAIN_NONATOMIC); self.queue.addObject(toast) } else { self.showToast(toast, duration: duration, position: position) } } // MARK: - Activity Methods func makeToastActivity(position: ToastPosition) { // sanity if let _ = objc_getAssociatedObject(self, &ToastKeys.ActiveToast) as? UIView { return } let toast = self.createToastActivityView() let point = self.centerPointForPosition(position, toast: toast) self.makeToastActivity(toast, position: point) } func makeToastActivity(position: CGPoint) { // sanity if let _ = objc_getAssociatedObject(self, &ToastKeys.ActiveToast) as? UIView { return } let toast = self.createToastActivityView() self.makeToastActivity(toast, position: position) } //Dismisses the active toast activity indicator view. func hideToastActivity() { if let toast = objc_getAssociatedObject(self, &ToastKeys.ActivityView) as? UIView { UIView.animateWithDuration(ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.CurveEaseIn, .BeginFromCurrentState], animations: { () -> Void in toast.alpha = 0.0 }, completion: { (finished: Bool) -> Void in toast.removeFromSuperview() objc_setAssociatedObject(self, &ToastKeys.ActivityView, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }) } } // MARK: - Private Activity Methods private func makeToastActivity(toast: UIView, position: CGPoint) { toast.alpha = 0.0 toast.center = position objc_setAssociatedObject(self, &ToastKeys.ActivityView, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) self.addSubview(toast) UIView.animateWithDuration(ToastManager.shared.style.fadeDuration, delay: 0.0, options: .CurveEaseOut, animations: { () -> Void in toast.alpha = 1.0 }, completion: nil) } private func createToastActivityView() -> UIView { let style = ToastManager.shared.style let activityView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: style.activitySize.width, height: style.activitySize.height)) activityView.backgroundColor = style.backgroundColor activityView.autoresizingMask = [.FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleTopMargin, .FlexibleBottomMargin] activityView.layer.cornerRadius = style.cornerRadius if style.displayShadow { activityView.layer.shadowColor = style.shadowColor.CGColor activityView.layer.shadowOpacity = style.shadowOpacity activityView.layer.shadowRadius = style.shadowRadius activityView.layer.shadowOffset = style.shadowOffset } let activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge) activityIndicatorView.center = CGPoint(x: activityView.bounds.size.width / 2.0, y: activityView.bounds.size.height / 2.0) activityView.addSubview(activityIndicatorView) activityIndicatorView.startAnimating() return activityView } // MARK: - Private Show/Hide Methods private func showToast(toast: UIView, duration: NSTimeInterval, position: CGPoint) { toast.center = position toast.alpha = 0.0 if ToastManager.shared.tapToDismissEnabled { let recognizer = UITapGestureRecognizer(target: self, action: "handleToastTapped:") toast.addGestureRecognizer(recognizer) toast.userInteractionEnabled = true toast.exclusiveTouch = true } objc_setAssociatedObject(self, &ToastKeys.ActiveToast, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC); self.addSubview(toast) UIView.animateWithDuration(ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.CurveEaseOut, .AllowUserInteraction], animations: { () -> Void in toast.alpha = 1.0 }) { (Bool finished) -> Void in let timer = NSTimer(timeInterval: duration, target: self, selector: "toastTimerDidFinish:", userInfo: toast, repeats: false) NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes) objc_setAssociatedObject(toast, &ToastKeys.Timer, timer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } private func hideToast(toast: UIView) { self.hideToast(toast, fromTap: false) } private func hideToast(toast: UIView, fromTap: Bool) { UIView.animateWithDuration(ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.CurveEaseIn, .BeginFromCurrentState], animations: { () -> Void in toast.alpha = 0.0 }) { (didFinish: Bool) -> Void in toast.removeFromSuperview() objc_setAssociatedObject(self, &ToastKeys.ActiveToast, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC); if let wrapper = objc_getAssociatedObject(toast, &ToastKeys.Completion) as? ToastCompletionWrapper, completion = wrapper.completion { completion(fromTap) } if let nextToast = self.queue.firstObject as? UIView, duration = objc_getAssociatedObject(nextToast, &ToastKeys.Duration) as? NSNumber, position = objc_getAssociatedObject(nextToast, &ToastKeys.Position) as? NSValue { self.queue.removeObjectAtIndex(0) self.showToast(nextToast, duration: duration.doubleValue, position: position.CGPointValue()) } } } // MARK: - Events func handleToastTapped(recognizer: UITapGestureRecognizer) { if let toast = recognizer.view, timer = objc_getAssociatedObject(toast, &ToastKeys.Timer) as? NSTimer { timer.invalidate() self.hideToast(toast, fromTap: true) } } func toastTimerDidFinish(timer: NSTimer) { if let toast = timer.userInfo as? UIView { self.hideToast(toast) } } // MARK: - Toast Construction func toastViewForMessage(message: String?, title: String?, image: UIImage?, style: ToastStyle) throws -> UIView { // sanity if message == nil && title == nil && image == nil { throw ToastError.InsufficientData } var messageLabel: UILabel? var titleLabel: UILabel? var imageView: UIImageView? let wrapperView = UIView() wrapperView.backgroundColor = style.backgroundColor wrapperView.autoresizingMask = [.FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleTopMargin, .FlexibleBottomMargin] wrapperView.layer.cornerRadius = style.cornerRadius if style.displayShadow { wrapperView.layer.shadowColor = UIColor.blackColor().CGColor wrapperView.layer.shadowOpacity = style.shadowOpacity wrapperView.layer.shadowRadius = style.shadowRadius wrapperView.layer.shadowOffset = style.shadowOffset } if let image = image { imageView = UIImageView(image: image) imageView?.contentMode = .ScaleAspectFit imageView?.frame = CGRect(x: style.horizontalPadding, y: style.verticalPadding, width: style.imageSize.width, height: style.imageSize.height) } var imageRect = CGRectZero if let imageView = imageView { imageRect.origin.x = style.horizontalPadding imageRect.origin.y = style.verticalPadding imageRect.size.width = imageView.bounds.size.width imageRect.size.height = imageView.bounds.size.height } if let title = title { titleLabel = UILabel() titleLabel?.numberOfLines = style.titleNumberOfLines titleLabel?.font = style.titleFont titleLabel?.textAlignment = style.titleAlignment titleLabel?.lineBreakMode = .ByTruncatingTail titleLabel?.textColor = style.titleColor titleLabel?.backgroundColor = UIColor.clearColor(); titleLabel?.text = title; let maxTitleSize = CGSize(width: (self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, height: self.bounds.size.height * style.maxHeightPercentage) let titleSize = titleLabel?.sizeThatFits(maxTitleSize) if let titleSize = titleSize { titleLabel?.frame = CGRect(x: 0.0, y: 0.0, width: titleSize.width, height: titleSize.height) } } if let message = message { messageLabel = UILabel() messageLabel?.text = message messageLabel?.numberOfLines = style.messageNumberOfLines messageLabel?.font = style.messageFont messageLabel?.textAlignment = style.messageAlignment messageLabel?.lineBreakMode = .ByTruncatingTail; messageLabel?.textColor = style.messageColor messageLabel?.backgroundColor = UIColor.clearColor() let maxMessageSize = CGSize(width: (self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, height: self.bounds.size.height * style.maxHeightPercentage) let messageSize = messageLabel?.sizeThatFits(maxMessageSize) if let messageSize = messageSize { messageLabel?.frame = CGRect(x: 0.0, y: 0.0, width: messageSize.width, height: messageSize.height) } } var titleRect = CGRectZero if let titleLabel = titleLabel { titleRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding titleRect.origin.y = style.verticalPadding titleRect.size.width = titleLabel.bounds.size.width titleRect.size.height = titleLabel.bounds.size.height } var messageRect = CGRectZero if let messageLabel = messageLabel { messageRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding messageRect.origin.y = titleRect.origin.y + titleRect.size.height + style.verticalPadding messageRect.size.width = messageLabel.bounds.size.width messageRect.size.height = messageLabel.bounds.size.height } let longerWidth = max(titleRect.size.width, messageRect.size.width) let longerX = max(titleRect.origin.x, messageRect.origin.x) let wrapperWidth = max((imageRect.size.width + (style.horizontalPadding * 2.0)), (longerX + longerWidth + style.horizontalPadding)) let wrapperHeight = max((messageRect.origin.y + messageRect.size.height + style.verticalPadding), (imageRect.size.height + (style.verticalPadding * 2.0))) wrapperView.frame = CGRect(x: 0.0, y: 0.0, width: wrapperWidth, height: wrapperHeight) if let titleLabel = titleLabel { titleLabel.frame = titleRect wrapperView.addSubview(titleLabel) } if let messageLabel = messageLabel { messageLabel.frame = messageRect wrapperView.addSubview(messageLabel) } if let imageView = imageView { wrapperView.addSubview(imageView) } return wrapperView } // MARK: - Helpers private func centerPointForPosition(position: ToastPosition, toast: UIView) -> CGPoint { let padding: CGFloat = ToastManager.shared.style.verticalPadding switch(position) { case .Top: return CGPoint(x: self.bounds.size.width / 2.0, y: (toast.frame.size.height / 2.0) + padding) case .Center: return CGPoint(x: self.bounds.size.width / 2.0, y: self.bounds.size.height / 2.0) case .Bottom: return CGPoint(x: self.bounds.size.width / 2.0, y: (self.bounds.size.height - (toast.frame.size.height / 2.0)) - padding) } } } // MARK: - Toast Style struct ToastStyle { var backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.8) var titleColor = UIColor.whiteColor() var messageColor = UIColor.whiteColor() var maxWidthPercentage: CGFloat = 0.8 { didSet { maxWidthPercentage = max(min(maxWidthPercentage, 1.0), 0.0) } } var maxHeightPercentage: CGFloat = 0.8 { didSet { maxHeightPercentage = max(min(maxHeightPercentage, 1.0), 0.0) } } var horizontalPadding: CGFloat = 10.0 var verticalPadding: CGFloat = 10.0 var cornerRadius: CGFloat = 10.0; var titleFont = UIFont.boldSystemFontOfSize(16.0) var messageFont = UIFont.systemFontOfSize(16.0) var titleAlignment = NSTextAlignment.Left var messageAlignment = NSTextAlignment.Left var titleNumberOfLines = 0; var messageNumberOfLines = 0; var displayShadow = false; var shadowColor = UIColor.blackColor() var shadowOpacity: Float = 0.8 { didSet { shadowOpacity = max(min(shadowOpacity, 1.0), 0.0) } } var shadowRadius: CGFloat = 6.0 var shadowOffset = CGSize(width: 4.0, height: 4.0) var imageSize = CGSize(width: 80.0, height: 80.0) var activitySize = CGSize(width: 100.0, height: 100.0) var fadeDuration: NSTimeInterval = 0.2 } // MARK: - Toast Manager class ToastManager { static let shared = ToastManager() var style = ToastStyle() var tapToDismissEnabled = true var queueEnabled = true var duration: NSTimeInterval = 3.0 var position = ToastPosition.Bottom } 

使用Toast.swift:

 // basic usage self.view.makeToast("Sample Toast") // toast with a specific duration and position self.view.makeToast("Sample Toast", duration: 3.0, position: .Top) // toast with all possible options self.view.makeToast("Sample Toast", duration: 2.0, position: CGPoint(x: 110.0, y: 110.0), title: "Toast Title", image: UIImage(named: "ic_120x120.png"), style:nil) { (didTap: Bool) -> Void in if didTap { print("completion from tap") } else { print("completion without tap") } } //display toast with an activity spinner self.view.makeToastActivity(.Center) // display any view as toast let sampleView = UIView(frame: CGRectMake(100,100,200,200)) sampleView.backgroundColor = UIColor(patternImage: UIImage(named: "ic_120x120")!) self.view.showToast(sampleView) self.view.showToast(sampleView, duration: 3.0, position: .Top, completion: nil) 

您可以从https://github.com/alvinreuben/ToastSample下载示例项目

这是你需要的东西。 创build大量的animation选项,屏幕位置和持续时间。 即使你可以提供自己的时间。 看看下面。

https://github.com/avistyles/AVIToast

Swift 3

已经很快乐地使用了Rannie / Toast-Swift for Swift 3,并且可以推荐它用于类似“类似Android”的体验。 它的实现非常简单,不需要另外一个吊舱,并根据您的需求定制。

十分简单

 view.makeToastActivity() view.hideToastActivity() 
Interesting Posts