---------- 方案一 ------------------
https://github.com/xglofter/MyIOSCodes/tree/master/TGCToastView
由于 swift 版本更新 ,附上 新版本
// // ToastView.swift // // Created by xglofter. // Copyright © 2016年 guang xu. All rights reserved. // import UIKit let TGCToastHorizontalMargin: CGFloat = 12 let TGCToastVerticalMargin: CGFloat = 20 let TGCToastHorizontalMaxPer: CGFloat = 0.4 // 40% parent view width let TGCToastVerticalMaxPer: CGFloat = 0.5 // 50% parent view height let TGCToastImageWidth: CGFloat = 30 let TGCToastImageHeight: CGFloat = 30 let TGCToastSpaceBetweenTextAndImage: CGFloat = 14 let TGCToastErrorHeight: CGFloat = 25 let TGCToastErrorHorizontalMargin: CGFloat = 10 let TGCToastErrorVerticalMagin: CGFloat = 5 let TGCToastLayerCornerRadius: CGFloat = 12 let TGCToastLayerColor: UIColor = UIColor.black let TGCToastLayerUseShadow: Bool = true let TGCToastLayerShadowOpacity: CGFloat = 0.8 let TGCToastLayerShadowRadius: CGFloat = 5.0 let TGCToastLayerShadowOffset: CGSize = CGSize(width:3.0, height:3.0) let TGCToastErrorLayerColor: UIColor = UIColor(red: 244/255, green: 81/255, blue: 78/255, alpha: 1) let TGCToastTextColor: UIColor = UIColor.white let TGCToastErrorTextColor: UIColor = UIColor.white let TGCToastFadeInTime: Double = 0.5 let TGCToastFadeOutTime: Double = 0.4 let TGCToastDefaultTime: Double = 3 let TGCToastErrorMoveInTime: Double = 0.3 let TGCToastErrorMoveOutTime: Double = 0.2 var TGCTimer: UnsafePointer<Timer>? = nil var TGCToastView: UnsafePointer<UIView>? = nil var TGCErrorTimer: UnsafePointer<Timer>? = nil var TGCErrorToastView: UnsafePointer<UIView>? = nil var TGCErrorViewOriginBottomY: UnsafePointer<CGFloat>? = nil extension UIView { /** make a toast (only text) - parameter message: message text - parameter duration: toast showing time(default is 3 seconds) */ func tgc_makeToast(message: String, duration: Double = TGCToastDefaultTime) { tgc_toMakeToast(message: message, duration: duration, image: nil) } /** make a toast (image with text) - parameter message: message text - parameter image: image - parameter duration: toast showing time(default is 3 seconds) */ func tgc_makeToast(message: String, image: UIImage, duration: Double = TGCToastDefaultTime) { tgc_toMakeToast(message: message, duration: duration, image: image) } /** make a toast (only image) - parameter image: image - parameter duration: toast showing time(default is 3 seconds) */ func tgc_makeToastImage(image: UIImage, duration: Double = TGCToastDefaultTime) { tgc_toMakeToast(message: nil, duration: duration, image: image) } /** make a error toast view - parameter message: error information - parameter duration: showing time(default is 3 seconds) */ func tgc_makeErrorToast(message: String, originBottomPosY posY: CGFloat = 0, duration: Double = TGCToastDefaultTime) { objc_setAssociatedObject(self, &TGCErrorViewOriginBottomY, posY, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) if let errorView = objc_getAssociatedObject(self, &TGCErrorToastView) { if let timer = objc_getAssociatedObject(errorView, &TGCErrorTimer) { (timer as AnyObject).invalidate() } tgc_hideErrorView(view: errorView as! UIView, force: true) } let toast = tgc_errorView(message: message) self.addSubview(toast) objc_setAssociatedObject(self, &TGCErrorToastView, toast, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) tgc_showErrorView(view: toast, duration: duration) } private func tgc_toMakeToast(message: String?, duration: Double, image: UIImage?) { if let toastView = objc_getAssociatedObject(self, &TGCToastView) { if let timer = objc_getAssociatedObject(toastView, &TGCTimer) { (timer as AnyObject).invalidate() } tgc_hideWrapperView(view: toastView as! UIView, force: true) } let toast = tgc_wrapperView(msg: message, image: image) self.addSubview(toast) objc_setAssociatedObject(self, &TGCToastView, toast, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) tgc_showWrapperView(view: toast, duration: duration) } private func tgc_wrapperView(msg: String?, image: UIImage?) -> UIView { let wrapperView = UIView() wrapperView.layer.cornerRadius = TGCToastLayerCornerRadius wrapperView.backgroundColor = TGCToastLayerColor.withAlphaComponent(0.9) wrapperView.alpha = 0.0 if TGCToastLayerUseShadow { wrapperView.layer.shadowColor = TGCToastLayerColor.cgColor wrapperView.layer.shadowOpacity = Float(TGCToastLayerShadowOpacity) wrapperView.layer.shadowRadius = TGCToastLayerShadowRadius wrapperView.layer.shadowOffset = TGCToastLayerShadowOffset } var imageView: UIImageView! var msgLabel: UILabel! let parentSize = self.bounds.size if image != nil { imageView = UIImageView(image: image) imageView.contentMode = .scaleAspectFill imageView.frame.size = CGSize(width:TGCToastImageWidth, height:TGCToastImageHeight) wrapperView.addSubview(imageView) } if msg != nil { msgLabel = UILabel() msgLabel.text = msg msgLabel.textColor = TGCToastTextColor msgLabel.font = UIFont.systemFont(ofSize: 14) msgLabel.lineBreakMode = .byWordWrapping msgLabel.numberOfLines = 0 msgLabel.textAlignment = .center wrapperView.addSubview(msgLabel) let maxMsgWidth = parentSize.width * TGCToastHorizontalMaxPer - TGCToastHorizontalMargin * 2 let maxMsgHeight = tgc_heightForLabel(textLabel: msgLabel, width: maxMsgWidth) msgLabel.frame.size = CGSize(width:maxMsgWidth, height:maxMsgHeight) } let imageHeight = (imageView != nil) ? imageView.frame.size.height + ((msgLabel != nil) ? TGCToastSpaceBetweenTextAndImage : 0) : 0 let textHeight = (msgLabel != nil) ? msgLabel.frame.size.height : 0 let wrapperWidth = parentSize.width * TGCToastHorizontalMaxPer let wrapperHeight = min(imageHeight + textHeight + TGCToastVerticalMargin * 2, parentSize.height * TGCToastVerticalMaxPer) wrapperView.frame.size = CGSize(width:wrapperWidth, height:wrapperHeight) wrapperView.center = CGPoint(x: parentSize.width * 0.5, y: parentSize.height * 0.5) if imageView != nil { imageView!.center = CGPoint(x:wrapperWidth * 0.5, y:TGCToastVerticalMargin + imageView!.frame.size.height * 0.5) } if msgLabel != nil { msgLabel!.center = CGPoint(x:wrapperWidth * 0.5, y:wrapperHeight - msgLabel!.frame.size.height * 0.5 - TGCToastVerticalMargin) } return wrapperView } private func tgc_errorView(message: String) -> UIView { let errorView = UIView() errorView.backgroundColor = TGCToastErrorLayerColor let textLabel = UILabel() textLabel.text = message textLabel.lineBreakMode = .byWordWrapping textLabel.numberOfLines = 0 textLabel.textAlignment = .center textLabel.font = UIFont.systemFont(ofSize: 14) textLabel.textColor = TGCToastErrorTextColor errorView.addSubview(textLabel) let parentSize = self.bounds.size let maxTextWidth = parentSize.width - TGCToastErrorHorizontalMargin * 2 let maxTextHeight = tgc_heightForLabel(textLabel: textLabel, width: maxTextWidth) textLabel.frame.size = CGSize(width:maxTextWidth, height:maxTextHeight) errorView.frame.size = CGSize(width:parentSize.width, height:maxTextHeight+TGCToastErrorVerticalMagin*2) textLabel.center = CGPoint(x:errorView.frame.size.width * 0.5, y:errorView.frame.size.height * 0.5) let posY = objc_getAssociatedObject(self, &TGCErrorViewOriginBottomY) as! CGFloat errorView.center = CGPoint(x:parentSize.width * 0.5, y:posY - errorView.frame.size.height * 0.5) return errorView } private func tgc_hideWrapperView(view: UIView, force: Bool) { func clearProperty() { view.removeFromSuperview() objc_setAssociatedObject(self, &TGCToastView, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) objc_setAssociatedObject(self, &TGCTimer, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } if force { clearProperty() } else { UIView.animate(withDuration: TGCToastFadeOutTime, delay: 0.0, options: [.curveEaseIn], animations: { view.alpha = 0.0 }) { (over: Bool) in clearProperty() } } } private func tgc_showWrapperView(view: UIView, duration: Double) { UIView.animate(withDuration: TGCToastFadeInTime, delay: 0, options: [.curveEaseOut], animations: { view.alpha = 1.0 }) { (over: Bool) in let timer = Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(self.tgc_onToHideToastView), userInfo: view, repeats: false) objc_setAssociatedObject(view, &TGCTimer, timer, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } private func tgc_hideErrorView(view: UIView, force: Bool) { func clearProperty() { view.removeFromSuperview() objc_setAssociatedObject(self, &TGCErrorToastView, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) objc_setAssociatedObject(self, &TGCErrorTimer, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } if force { clearProperty() } else { UIView.animate(withDuration: TGCToastErrorMoveOutTime, delay: 0.0, options: [.curveEaseIn], animations: { let posY = objc_getAssociatedObject(self, &TGCErrorViewOriginBottomY) as! CGFloat view.frame.origin.y = posY - view.frame.size.height }) { (over: Bool) in clearProperty() } } } private func tgc_showErrorView(view: UIView, duration: Double) { UIView.animate(withDuration: TGCToastErrorMoveInTime, delay: 0, options: [.curveEaseOut], animations: { view.frame.origin.y += view.frame.size.height }) { (over: Bool) in let timer = Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(self.tgc_onToHideErrorToastView), userInfo: view, repeats: false) objc_setAssociatedObject(view, &TGCErrorTimer, timer, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } func tgc_onToHideToastView(timer: Timer) { self.tgc_hideWrapperView(view: timer.userInfo as! UIView, force: false) } func tgc_onToHideErrorToastView(timer: Timer) { self.tgc_hideErrorView(view: timer.userInfo as! UIView, force: false) } /** get a UILabel's max height, with UILabel's width - parameter textLabel: the text label - parameter width: the text label's width - returns: get the label max height */ func tgc_heightForLabel(textLabel: UILabel, width: CGFloat) -> CGFloat { let attributes = [NSFontAttributeName: textLabel.font!] let rect = (textLabel.text! as NSString).boundingRect(with: CGSize(width:width, height:0), options: .usesLineFragmentOrigin, attributes: attributes, context: nil) return rect.height } }
--------- 方案二 ----------
参考: https://github.com/Rannie/Toast-Swift
1 : UIView.hr_setToastThemeColor(color: UIColor.blueColor());
view.makeToast(message: "s是的发送到");
2: self.view.makeToastActivity();
消失使用 self.view.hideToastActivity();
var timer: NSTimer!;
timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: #selector(self.timerAction), userInfo: nil, repeats: false);//第一次参数1表示重复执行间隔秒,初始化定时,timerAction=要执行的函数
func timerAction(){
print("do hide");
self.view.hideToastActivity();
}
3: self.view.makeToastActivityWithMessage(message: "加载中..");
消失 使用 2 里面的消失方法
HRToast+UIView.swift:
// // HRToast + UIView.swift // ToastDemo // // Created by Rannie on 14/7/6. // Copyright (c) 2014年 Rannie. All rights reserved. // https://github.com/Rannie/Toast-Swift // import UIKit /* * Infix overload method */ func /(lhs: CGFloat, rhs: Int) -> CGFloat { return lhs / CGFloat(rhs) } /* * Toast Config */ let HRToastDefaultDuration = 2.0 let HRToastFadeDuration = 0.2 let HRToastHorizontalMargin : CGFloat = 10.0 let HRToastVerticalMargin : CGFloat = 10.0 let HRToastPositionDefault = "bottom" let HRToastPositionTop = "top" let HRToastPositionCenter = "center" // activity let HRToastActivityWidth : CGFloat = 100.0 let HRToastActivityHeight : CGFloat = 100.0 let HRToastActivityPositionDefault = "center" // image size let HRToastImageViewWidth : CGFloat = 80.0 let HRToastImageViewHeight: CGFloat = 80.0 // label setting let HRToastMaxWidth : CGFloat = 0.8; // 80% of parent view width let HRToastMaxHeight : CGFloat = 0.8; let HRToastFontSize : CGFloat = 16.0 let HRToastMaxTitleLines = 0 let HRToastMaxMessageLines = 0 // shadow appearance let HRToastShadowOpacity : CGFloat = 0.8 let HRToastShadowRadius : CGFloat = 6.0 let HRToastShadowOffset : CGSize = CGSizeMake(CGFloat(4.0), CGFloat(4.0)) let HRToastOpacity : CGFloat = 0.9 let HRToastCornerRadius : CGFloat = 10.0 var HRToastActivityView: UnsafePointer<UIView> = nil var HRToastTimer: UnsafePointer<NSTimer> = nil var HRToastView: UnsafePointer<UIView> = nil var HRToastThemeColor : UnsafePointer<UIColor> = nil var HRToastTitleFontName: UnsafePointer<String> = nil var HRToastFontName: UnsafePointer<String> = nil var HRToastFontColor: UnsafePointer<UIColor> = nil /* * Custom Config */ let HRToastHidesOnTap = true let HRToastDisplayShadow = true //HRToast (UIView + Toast using Swift) extension UIView { /* * public methods */ class func hr_setToastThemeColor(color color: UIColor) { objc_setAssociatedObject(self, &HRToastThemeColor, color, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } class func hr_toastThemeColor() -> UIColor { var color = objc_getAssociatedObject(self, &HRToastThemeColor) as! UIColor? if color == nil { color = UIColor.blackColor() UIView.hr_setToastThemeColor(color: color!) } return color! } class func hr_setToastTitleFontName(fontName fontName: String) { objc_setAssociatedObject(self, &HRToastTitleFontName, fontName, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } class func hr_toastTitleFontName() -> String { var name = objc_getAssociatedObject(self, &HRToastTitleFontName) as! String? if name == nil { let font = UIFont.systemFontOfSize(12.0) name = font.fontName UIView.hr_setToastTitleFontName(fontName: name!) } return name! } class func hr_setToastFontName(fontName fontName: String) { objc_setAssociatedObject(self, &HRToastFontName, fontName, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } class func hr_toastFontName() -> String { var name = objc_getAssociatedObject(self, &HRToastFontName) as! String? if name == nil { let font = UIFont.systemFontOfSize(12.0) name = font.fontName UIView.hr_setToastFontName(fontName: name!) } return name! } class func hr_setToastFontColor(color color: UIColor) { objc_setAssociatedObject(self, &HRToastFontColor, color, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } class func hr_toastFontColor() -> UIColor { var color = objc_getAssociatedObject(self, &HRToastFontColor) as! UIColor? if color == nil { color = UIColor.whiteColor() UIView.hr_setToastFontColor(color: color!) } return color! } func makeToastActivityWithMessage(message msg: String){ self.makeToastActivity(position: HRToastActivityPositionDefault, message: msg) } func makeToast(message msg: String) { self.makeToast(message: msg, duration: HRToastDefaultDuration, position: HRToastPositionDefault) } func makeToast(message msg: String, duration: Double, position: AnyObject) { let toast = self.viewForMessage(msg, title: nil, image: nil) self.showToast(toast: toast!, duration: duration, position: position) } func makeToast(message msg: String, duration: Double, position: AnyObject, title: String) { let toast = self.viewForMessage(msg, title: title, image: nil) self.showToast(toast: toast!, duration: duration, position: position) } func makeToast(message msg: String, duration: Double, position: AnyObject, image: UIImage) { let toast = self.viewForMessage(msg, title: nil, image: image) self.showToast(toast: toast!, duration: duration, position: position) } func makeToast(message msg: String, duration: Double, position: AnyObject, title: String, image: UIImage) { let toast = self.viewForMessage(msg, title: title, image: image) self.showToast(toast: toast!, duration: duration, position: position) } func showToast(toast toast: UIView) { self.showToast(toast: toast, duration: HRToastDefaultDuration, position: HRToastPositionDefault) } private func showToast(toast toast: UIView, duration: Double, position: AnyObject) { let existToast = objc_getAssociatedObject(self, &HRToastView) as! UIView? if existToast != nil { if let timer: NSTimer = objc_getAssociatedObject(existToast, &HRToastTimer) as? NSTimer { timer.invalidate(); } self.hideToast(toast: existToast!, force: false); } toast.center = self.centerPointForPosition(position, toast: toast) toast.alpha = 0.0 if HRToastHidesOnTap { let tapRecognizer = UITapGestureRecognizer(target: toast, action: #selector(UIView.handleToastTapped(_:))) toast.addGestureRecognizer(tapRecognizer) toast.userInteractionEnabled = true; toast.exclusiveTouch = true; } self.addSubview(toast) objc_setAssociatedObject(self, &HRToastView, toast, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) UIView.animateWithDuration(HRToastFadeDuration, delay: 0.0, options: ([.CurveEaseOut, .AllowUserInteraction]), animations: { toast.alpha = 1.0 }, completion: { (finished: Bool) in let timer = NSTimer.scheduledTimerWithTimeInterval(duration, target: self, selector: #selector(UIView.toastTimerDidFinish(_:)), userInfo: toast, repeats: false) objc_setAssociatedObject(toast, &HRToastTimer, timer, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) }) } func makeToastActivity() { self.makeToastActivity(position: HRToastActivityPositionDefault) } func makeToastActivity(message msg: String){ self.makeToastActivity(position: HRToastActivityPositionDefault, message: msg) } private func makeToastActivity(position pos: AnyObject, message msg: String = "") { let existingActivityView: UIView? = objc_getAssociatedObject(self, &HRToastActivityView) as? UIView if existingActivityView != nil { return } let activityView = UIView(frame: CGRectMake(0, 0, HRToastActivityWidth, HRToastActivityHeight)) activityView.center = self.centerPointForPosition(pos, toast: activityView) activityView.backgroundColor = UIView.hr_toastThemeColor().colorWithAlphaComponent(HRToastOpacity) activityView.alpha = 0.0 activityView.autoresizingMask = ([.FlexibleLeftMargin, .FlexibleTopMargin, .FlexibleRightMargin, .FlexibleBottomMargin]) activityView.layer.cornerRadius = HRToastCornerRadius if HRToastDisplayShadow { activityView.layer.shadowColor = UIView.hr_toastThemeColor().CGColor activityView.layer.shadowOpacity = Float(HRToastShadowOpacity) activityView.layer.shadowRadius = HRToastShadowRadius activityView.layer.shadowOffset = HRToastShadowOffset } let activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge) activityIndicatorView.center = CGPointMake(activityView.bounds.size.width / 2, activityView.bounds.size.height / 2) activityView.addSubview(activityIndicatorView) activityIndicatorView.startAnimating() if (!msg.isEmpty){ activityIndicatorView.frame.origin.y -= 10 let activityMessageLabel = UILabel(frame: CGRectMake(activityView.bounds.origin.x, (activityIndicatorView.frame.origin.y + activityIndicatorView.frame.size.height + 10), activityView.bounds.size.width, 20)) activityMessageLabel.textColor = UIView.hr_toastFontColor() activityMessageLabel.font = (msg.characters.count<=10) ? UIFont(name:UIView.hr_toastFontName(), size: 16) : UIFont(name:UIView.hr_toastFontName(), size: 13) activityMessageLabel.textAlignment = .Center activityMessageLabel.text = msg activityView.addSubview(activityMessageLabel) } self.addSubview(activityView) // associate activity view with self objc_setAssociatedObject(self, &HRToastActivityView, activityView, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) UIView.animateWithDuration(HRToastFadeDuration, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { activityView.alpha = 1.0 }, completion: nil) } func hideToastActivity() { let existingActivityView = objc_getAssociatedObject(self, &HRToastActivityView) as! UIView? if existingActivityView == nil { return } UIView.animateWithDuration(HRToastFadeDuration, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { existingActivityView!.alpha = 0.0 }, completion: { (finished: Bool) in existingActivityView!.removeFromSuperview() objc_setAssociatedObject(self, &HRToastActivityView, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) }) } /* * private methods (helper) */ func hideToast(toast toast: UIView) { self.hideToast(toast: toast, force: false); } func hideToast(toast toast: UIView, force: Bool) { let completeClosure = { (finish: Bool) -> () in toast.removeFromSuperview() objc_setAssociatedObject(self, &HRToastTimer, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } if force { completeClosure(true) } else { UIView.animateWithDuration(HRToastFadeDuration, delay: 0.0, options: ([.CurveEaseIn, .BeginFromCurrentState]), animations: { toast.alpha = 0.0 }, completion:completeClosure) } } func toastTimerDidFinish(timer: NSTimer) { self.hideToast(toast: timer.userInfo as! UIView) } func handleToastTapped(recognizer: UITapGestureRecognizer) { let timer = objc_getAssociatedObject(self, &HRToastTimer) as! NSTimer timer.invalidate() self.hideToast(toast: recognizer.view!) } private func centerPointForPosition(position: AnyObject, toast: UIView) -> CGPoint { if position is String { let toastSize = toast.bounds.size let viewSize = self.bounds.size if position.lowercaseString == HRToastPositionTop { return CGPointMake(viewSize.width/2, toastSize.height/2 + HRToastVerticalMargin) } else if position.lowercaseString == HRToastPositionDefault { return CGPointMake(viewSize.width/2, viewSize.height - toastSize.height/2 - HRToastVerticalMargin) } else if position.lowercaseString == HRToastPositionCenter { return CGPointMake(viewSize.width/2, viewSize.height/2) } } else if position is NSValue { return position.CGPointValue } print("Warning: Invalid position for toast.") return self.centerPointForPosition(HRToastPositionDefault, toast: toast) } private func viewForMessage(msg: String?, title: String?, image: UIImage?) -> UIView? { if msg == nil && title == nil && image == nil { return nil } var msgLabel: UILabel? var titleLabel: UILabel? var imageView: UIImageView? let wrapperView = UIView() wrapperView.autoresizingMask = ([.FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleTopMargin, .FlexibleBottomMargin]) wrapperView.layer.cornerRadius = HRToastCornerRadius wrapperView.backgroundColor = UIView.hr_toastThemeColor().colorWithAlphaComponent(HRToastOpacity) if HRToastDisplayShadow { wrapperView.layer.shadowColor = UIView.hr_toastThemeColor().CGColor wrapperView.layer.shadowOpacity = Float(HRToastShadowOpacity) wrapperView.layer.shadowRadius = HRToastShadowRadius wrapperView.layer.shadowOffset = HRToastShadowOffset } if image != nil { imageView = UIImageView(image: image) imageView!.contentMode = .ScaleAspectFit imageView!.frame = CGRectMake(HRToastHorizontalMargin, HRToastVerticalMargin, CGFloat(HRToastImageViewWidth), CGFloat(HRToastImageViewHeight)) } var imageWidth: CGFloat, imageHeight: CGFloat, imageLeft: CGFloat if imageView != nil { imageWidth = imageView!.bounds.size.width imageHeight = imageView!.bounds.size.height imageLeft = HRToastHorizontalMargin } else { imageWidth = 0.0; imageHeight = 0.0; imageLeft = 0.0 } if title != nil { titleLabel = UILabel() titleLabel!.numberOfLines = HRToastMaxTitleLines titleLabel!.font = UIFont(name: UIView.hr_toastFontName(), size: HRToastFontSize) titleLabel!.textAlignment = .Center titleLabel!.lineBreakMode = .ByWordWrapping titleLabel!.textColor = UIView.hr_toastFontColor() titleLabel!.backgroundColor = UIColor.clearColor() titleLabel!.alpha = 1.0 titleLabel!.text = title // size the title label according to the length of the text let maxSizeTitle = CGSizeMake((self.bounds.size.width * HRToastMaxWidth) - imageWidth, self.bounds.size.height * HRToastMaxHeight); let expectedHeight = title!.stringHeightWithFontSize(HRToastFontSize, width: maxSizeTitle.width) titleLabel!.frame = CGRectMake(0.0, 0.0, maxSizeTitle.width, expectedHeight) } if msg != nil { msgLabel = UILabel(); msgLabel!.numberOfLines = HRToastMaxMessageLines msgLabel!.font = UIFont(name: UIView.hr_toastFontName(), size: HRToastFontSize) msgLabel!.lineBreakMode = .ByWordWrapping msgLabel!.textAlignment = .Center msgLabel!.textColor = UIView.hr_toastFontColor() msgLabel!.backgroundColor = UIColor.clearColor() msgLabel!.alpha = 1.0 msgLabel!.text = msg let maxSizeMessage = CGSizeMake((self.bounds.size.width * HRToastMaxWidth) - imageWidth, self.bounds.size.height * HRToastMaxHeight) let expectedHeight = msg!.stringHeightWithFontSize(HRToastFontSize, width: maxSizeMessage.width) msgLabel!.frame = CGRectMake(0.0, 0.0, maxSizeMessage.width, expectedHeight) } var titleWidth: CGFloat, titleHeight: CGFloat, titleTop: CGFloat, titleLeft: CGFloat if titleLabel != nil { titleWidth = titleLabel!.bounds.size.width titleHeight = titleLabel!.bounds.size.height titleTop = HRToastVerticalMargin titleLeft = imageLeft + imageWidth + HRToastHorizontalMargin } else { titleWidth = 0.0; titleHeight = 0.0; titleTop = 0.0; titleLeft = 0.0 } var msgWidth: CGFloat, msgHeight: CGFloat, msgTop: CGFloat, msgLeft: CGFloat if msgLabel != nil { msgWidth = msgLabel!.bounds.size.width msgHeight = msgLabel!.bounds.size.height msgTop = titleTop + titleHeight + HRToastVerticalMargin msgLeft = imageLeft + imageWidth + HRToastHorizontalMargin } else { msgWidth = 0.0; msgHeight = 0.0; msgTop = 0.0; msgLeft = 0.0 } let largerWidth = max(titleWidth, msgWidth) let largerLeft = max(titleLeft, msgLeft) // set wrapper view's frame let wrapperWidth = max(imageWidth + HRToastHorizontalMargin * 2, largerLeft + largerWidth + HRToastHorizontalMargin) let wrapperHeight = max(msgTop + msgHeight + HRToastVerticalMargin, imageHeight + HRToastVerticalMargin * 2) wrapperView.frame = CGRectMake(0.0, 0.0, wrapperWidth, wrapperHeight) // add subviews if titleLabel != nil { titleLabel!.frame = CGRectMake(titleLeft, titleTop, titleWidth, titleHeight) wrapperView.addSubview(titleLabel!) } if msgLabel != nil { msgLabel!.frame = CGRectMake(msgLeft, msgTop, msgWidth, msgHeight) wrapperView.addSubview(msgLabel!) } if imageView != nil { wrapperView.addSubview(imageView!) } return wrapperView } } extension String { func stringHeightWithFontSize(fontSize: CGFloat,width: CGFloat) -> CGFloat { let font = UIFont(name: UIView.hr_toastFontName(), size: HRToastFontSize) let size = CGSizeMake(width, CGFloat.max) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .ByWordWrapping; let attributes = [NSFontAttributeName:font!, NSParagraphStyleAttributeName:paragraphStyle.copy()] let text = self as NSString let rect = text.boundingRectWithSize(size, options:.UsesLineFragmentOrigin, attributes: attributes, context:nil) return rect.size.height } }