ios - the - ¿Cómo brindar por el mensaje en Swift?
the swift programming language pdf (17)
¿Hay alguna manera de brindar mensajes de forma rápida?
Lo intenté en el objetivo c pero no pude encontrar una solución rápida.
[self.view makeToast:@"Account created Successfully"
duration:0.5
position:@"bottom"];
Código @ mr-bean actualizado a la última versión de Swift (3.x)
let toastLabel =
UILabel(frame:
CGRect(x: self.view.frame.size.width/2 - 150,
y: self.view.frame.size.height-100,
width: 300,
height: 35))
toastLabel.backgroundColor = UIColor.black
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = NSTextAlignment.center
self.view.addSubview(toastLabel)
toastLabel.text = message
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
UIView.animate(withDuration: 4.0, animations: {
toastLabel.alpha = 0.0
})
En lugar de usar
UILabel
usar
UITextView
obtiene mejores resultados.
func showToast(message: String) {
let toastLabel = UITextView(frame: CGRect(x: self.view.frame.size.width/16, y: self.view.frame.size.height-150, width: self.view.frame.size.width * 7/8, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.text = " /(message) "
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
toastLabel.font = UIFont(name: (toastLabel.font?.fontName)!, size: 16)
toastLabel.layoutEdgeInsets.left = 8
toastLabel.layoutEdgeInsets.right = 8
toastLabel.center.x = self.view.frame.size.width/2
self.view.addSubview(toastLabel)
UIView.animate(withDuration: 5.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
}
Se agrega espacio con el mensaje para proporcionar un buen espacio en ambos extremos para que se vea bien. Versión modificada de la respuesta de
Esto te ayudará a hacer el brindis en el centro con el relleno adecuado
func showToast(message:String,view:UIView){
let toastLabel = PaddingLabel()
toastLabel.frame = CGRect(x:0, y: view.frame.size.height-100, width: view.frame.width-50, height: 0)
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
toastLabel.text = message
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
toastLabel.sizeToFit()
toastLabel.frame.origin.x=(view.frame.width/2)-(toastLabel.frame.width/2)
view.addSubview(toastLabel)
UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
}
Y agregue este archivo PaddingLabel para el relleno de etiquetas
import Foundation
import UIKit
class PaddingLabel: UILabel {
let padding=UIEdgeInsetsMake(5, 10, 5,10)
override func drawText(in rect: CGRect) {
super.drawText(in: UIEdgeInsetsInsetRect(rect, padding))
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
let superSizeThatFits=super.sizeThatFits(size)
let width=superSizeThatFits.width+padding.left+padding.right
let height=superSizeThatFits.height+padding.top+padding.bottom
return CGSize(width: width, height: height)
}
}
Hay una biblioteca de terceros que admite notificaciones de brindis personalizables con una sola línea de código. Aquí hay un ejemplo simple de esto:
import Toast_Swift
...
// basic usage
self.view.makeToast("This is a piece of toast")
// toast with a specific duration and position
self.view.makeToast("This is a piece of toast", duration: 3.0, position: .top)
https://github.com/scalessec/Toast-Swift
(Actualizado para Swift 3/4 +)
He estado usando esta extensión cuando alguna vez necesito un mensaje tostado como Android. Simplemente copie la extensión a su proyecto y luego en su clase UIViewController, llame a la función como
self.toastMessage("Downloading...")
// Extention is below
extension UIViewController {
func toastMessage(_ message: String){
guard let window = UIApplication.shared.keyWindow else {return}
let messageLbl = UILabel()
messageLbl.text = message
messageLbl.textAlignment = .center
messageLbl.font = UIFont.systemFont(ofSize: 12)
messageLbl.textColor = .white
messageLbl.backgroundColor = UIColor(white: 0, alpha: 0.5)
let textSize:CGSize = messageLbl.intrinsicContentSize
let labelWidth = min(textSize.width, window.frame.width - 40)
messageLbl.frame = CGRect(x: 20, y: window.frame.height - 90, width: labelWidth + 30, height: textSize.height + 20)
messageLbl.center.x = window.center.x
messageLbl.layer.cornerRadius = messageLbl.frame.height/2
messageLbl.layer.masksToBounds = true
window.addSubview(messageLbl)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
UIView.animate(withDuration: 1, animations: {
messageLbl.alpha = 0
}) { (_) in
messageLbl.removeFromSuperview()
}
}
}}
Lo que necesita exactamente es https://github.com/Rannie/Toast-Swift/blob/master/SwiftToastDemo/Toast/HRToast%2BUIView.swift .
Descargue la clase HRToast + UIView.swift y arrastre y suelte para proyectar. Asegúrese de marcar ''copiar elementos si es necesario'' en el cuadro de diálogo.
//Usage:
self.view.makeToast(message: "Simple Toast")
self.view.makeToast(message: "Simple Toast", duration: 2.0, position:HRToastPositionTop)
self.view.makeToast(message: "Simple Toast", duration: 2.0, position: HRToastPositionCenter, image: UIImage(named: "ic_120x120")!)
self.view.makeToast(message: "It is just awesome", duration: 2.0, position: HRToastPositionDefault, title: "Simple Toast")
self.view.makeToast(message: "It is just awesome", duration: 2.0, position: HRToastPositionCenter, title: "Simple Toast", image: UIImage(named: "ic_120x120")!)
self.view.makeToastActivity()
self.view.makeToastActivity(position: HRToastPositionCenter)
self.view.makeToastActivity(position: HRToastPositionDefault, message: "Loading")
self.view.makeToastActivityWithMessage(message: "Loading")
Para Swift 4
Mi versión de un Toast que usa restricciones de diseño, con la ventaja de que funciona para cualquier tamaño de texto, tal como está (según la respuesta de Tony Franzis):
Simplemente llame:
Toast.show(message: "My message", myViewControllerName)
class Toast {
static func show(message: String, controller: UIViewController) {
let toastContainer = UIView(frame: CGRect())
toastContainer.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastContainer.alpha = 0.0
toastContainer.layer.cornerRadius = 25;
toastContainer.clipsToBounds = true
let toastLabel = UILabel(frame: CGRect())
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font.withSize(12.0)
toastLabel.text = message
toastLabel.clipsToBounds = true
toastLabel.numberOfLines = 0
toastContainer.addSubview(toastLabel)
controller.view.addSubview(toastContainer)
toastLabel.translatesAutoresizingMaskIntoConstraints = false
toastContainer.translatesAutoresizingMaskIntoConstraints = false
let a1 = NSLayoutConstraint(item: toastLabel, attribute: .leading, relatedBy: .equal, toItem: toastContainer, attribute: .leading, multiplier: 1, constant: 15)
let a2 = NSLayoutConstraint(item: toastLabel, attribute: .trailing, relatedBy: .equal, toItem: toastContainer, attribute: .trailing, multiplier: 1, constant: -15)
let a3 = NSLayoutConstraint(item: toastLabel, attribute: .bottom, relatedBy: .equal, toItem: toastContainer, attribute: .bottom, multiplier: 1, constant: -15)
let a4 = NSLayoutConstraint(item: toastLabel, attribute: .top, relatedBy: .equal, toItem: toastContainer, attribute: .top, multiplier: 1, constant: 15)
toastContainer.addConstraints([a1, a2, a3, a4])
let c1 = NSLayoutConstraint(item: toastContainer, attribute: .leading, relatedBy: .equal, toItem: controller.view, attribute: .leading, multiplier: 1, constant: 65)
let c2 = NSLayoutConstraint(item: toastContainer, attribute: .trailing, relatedBy: .equal, toItem: controller.view, attribute: .trailing, multiplier: 1, constant: -65)
let c3 = NSLayoutConstraint(item: toastContainer, attribute: .bottom, relatedBy: .equal, toItem: controller.view, attribute: .bottom, multiplier: 1, constant: -75)
controller.view.addConstraints([c1, c2, c3])
UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseIn, animations: {
toastContainer.alpha = 1.0
}, completion: { _ in
UIView.animate(withDuration: 0.5, delay: 1.5, options: .curveEaseOut, animations: {
toastContainer.alpha = 0.0
}, completion: {_ in
toastContainer.removeFromSuperview()
})
})
}
}
Permítanme agregar esto a esta cadena de respuestas: esta biblioteca hace lo que necesita DCToastView lo que le permite proporcionar mensajes brindis desde el lado superior o inferior de la pantalla:
Solo tendrá que agregar el pod
pod ''DCToastView''
Importarlo donde quieras usarlo.
import DCToastView
Y úsalo
ToastPresenter.shared.show(in: self.view, message: "This is a toast")
Puede pasar las siguientes propiedades al método show:
- vista : la vista en la que se presentará el brindis
- mensaje : el mensaje que mostrará la tostada
- toastPlace : el lugar que puede ser .down o .up
- backgroundColor : el color de fondo de la tostada; predeterminado a negro
- textColor : el color del texto del mensaje; predeterminado a blanco
- timeOut : la cantidad de segundos para que la tostada se descarte si no se proporciona, significa que la tostada estará pegajosa (permanecerá hasta que se toque); el valor predeterminado es nulo
- redondez : Cuán redonda será la tostada: .none, .low, .mid, .high; el valor predeterminado es .mid
Sé que hay respuestas aceptadas, pero todas parecen tener un gran defecto: si muestra varias tostadas en un corto período de tiempo, se mostrarán una encima de la otra. Aquí está mi implementación que tiene en cuenta este problema:
class Toast: UILabel {
private let BOTTOM_MARGIN: CGFloat = 16
private let SIDE_MARGIN: CGFloat = 16
private let HEIGHT: CGFloat = 35
private let SHOW_TIME_SECONDS = TimeInterval(3)
private let BACKGROUND_COLOR = UIColor.darkGray.withAlphaComponent(0.7).cgColor
private let TEXT_COLOR = UIColor.white
private let ANIMATION_DURATION_SEC = 0.33
private static var queue: [ToastHolder] = []
private static var showing: Toast?
init(_ text: String) {
super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
self.text = text
self.textColor = TEXT_COLOR
textAlignment = .center
self.layer.backgroundColor = BACKGROUND_COLOR
self.layer.cornerRadius = 5
}
public func show(_ parent: UIViewController) {
frame = CGRect(x: SIDE_MARGIN, y: UIScreen.main.bounds.height - BOTTOM_MARGIN - HEIGHT, width: UIScreen.main.bounds.width - 2 * SIDE_MARGIN, height: HEIGHT)
if Toast.showing == nil {
Log.d("showing /(String(describing: text))")
Toast.showing = self
alpha = 0
parent.view.addSubview(self)
UIView.animate(withDuration: ANIMATION_DURATION_SEC, animations: {
self.alpha = 1
}, completion: { (completed) in
Timer.scheduledTimer(timeInterval: self.SHOW_TIME_SECONDS, target: self, selector: #selector(self.onTimeout), userInfo: nil, repeats: false)
})
} else {
Toast.queue.append(ToastHolder(self, parent))
}
}
@objc func onTimeout() {
UIView.animate(withDuration: ANIMATION_DURATION_SEC, animations: {
self.alpha = 0
}, completion: { (completed) in
Toast.showing = nil
self.removeFromSuperview()
if !Toast.queue.isEmpty {
let holder = Toast.queue.removeFirst()
holder.toast.show(holder.parent)
}
})
}
required init?(coder aDecoder: NSCoder) {
fatalError("this initializer is not supported")
}
private class ToastHolder {
let toast: Toast
let parent: UIViewController
init(_ t: Toast, _ p: UIViewController) {
toast = t
parent = p
}
}
}
Uso:
Toast("my message").show(self)
Espero que ayude a alguien.
Si la necesidad es un simple mensaje Toast sin una personalización elegante de la fuente, la alineación, el color del texto, etc., entonces lo siguiente estaría bien
let messageVC = UIAlertController(title: "Message Title", message: "Account Created successfully" , preferredStyle: .actionSheet)
present(messageVC, animated: true) {
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { (_) in
messageVC.dismiss(animated: true, completion: nil)})}
.actionSheet
presenta la alerta desde la parte inferior de la pantalla y el temporizador se encarga de la duración de la pantalla.
Puede agregar esto como una extensión a UIViewController y luego llamarlo desde cualquier lugar.
Simplemente agregue el siguiente método. Esto mostrará el mensaje en diferentes colores con animación (mensaje que aparece de izquierda a derecha y desaparece).
Swift 3.0 -
class Toast
{
class private func showAlert(backgroundColor:UIColor, textColor:UIColor, message:String)
{
let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
let label = UILabel(frame: CGRect.zero)
label.textAlignment = NSTextAlignment.center
label.text = message
label.font = UIFont(name: "", size: 15)
label.adjustsFontSizeToFitWidth = true
label.backgroundColor = backgroundColor //UIColor.whiteColor()
label.textColor = textColor //TEXT COLOR
label.sizeToFit()
label.numberOfLines = 4
label.layer.shadowColor = UIColor.gray.cgColor
label.layer.shadowOffset = CGSize(width: 4, height: 3)
label.layer.shadowOpacity = 0.3
label.frame = CGRect(x: appDelegate.window!.frame.size.width, y: 64, width: appDelegate.window!.frame.size.width, height: 44)
label.alpha = 1
appDelegate.window!.addSubview(label)
var basketTopFrame: CGRect = label.frame;
basketTopFrame.origin.x = 0;
UIView.animate(withDuration
:2.0, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.1, options: UIViewAnimationOptions.curveEaseOut, animations: { () -> Void in
label.frame = basketTopFrame
}, completion: {
(value: Bool) in
UIView.animate(withDuration:2.0, delay: 2.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.1, options: UIViewAnimationOptions.curveEaseIn, animations: { () -> Void in
label.alpha = 0
}, completion: {
(value: Bool) in
label.removeFromSuperview()
})
})
}
class func showPositiveMessage(message:String)
{
showAlert(backgroundColor: UIColor.green, textColor: UIColor.white, message: message)
}
class func showNegativeMessage(message:String)
{
showAlert(backgroundColor: UIColor.red, textColor: UIColor.white, message: message)
}
}
Swift 4.2 Muy fácil y super manera
let toastLabel = UILabel()
toastLabel.lineBreakMode = .byWordWrapping
toastLabel.numberOfLines = 0
toastLabel.text = "Type your message you want to show in toast"
toastLabel.sizeToFit()
//MARK Resize the Label Frame
toastLabel.frame = CGRect(x: toastLabel.frame.origin.x, y: toastLabel.frame.origin.y, width: toastLabel.frame.size.width + 40, height: toastLabel.frame.size.height + 40)
self.view.addSubview(toastLabel)
Tengo dos soluciones más en Swift 5:
La mejor solución (en mi opinión)
Ventaja:
- Funciona correctamente al girar la pantalla.
- Las restricciones se utilizan para el posicionamiento.
- Funciona correctamente con SafeArea.
Desventajas
-
Se requiere extender la clase
UILabel
para agregar sangrías. Uno podría prescindir de esto colocando elUILabel
en elUIVIew
.
Código:
class ToastLabel: UILabel {
var textInsets = UIEdgeInsets.zero {
didSet { invalidateIntrinsicContentSize() }
}
override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
let insetRect = bounds.inset(by: textInsets)
let textRect = super.textRect(forBounds: insetRect, limitedToNumberOfLines: numberOfLines)
let invertedInsets = UIEdgeInsets(top: -textInsets.top, left: -textInsets.left, bottom: -textInsets.bottom, right: -textInsets.right)
return textRect.inset(by: invertedInsets)
}
override func drawText(in rect: CGRect) {
super.drawText(in: rect.inset(by: textInsets))
}
}
extension UIViewController {
static let DELAY_SHORT = 1.5
static let DELAY_LONG = 3.0
func showToast(_ text: String, delay: TimeInterval = DELAY_LONG) {
let label = ToastLabel()
label.backgroundColor = UIColor(white: 0, alpha: 0.5)
label.textColor = .white
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 15)
label.alpha = 0
label.text = text
label.clipsToBounds = true
label.layer.cornerRadius = 20
label.numberOfLines = 0
label.textInsets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15)
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
let saveArea = view.safeAreaLayoutGuide
label.centerXAnchor.constraint(equalTo: saveArea.centerXAnchor, constant: 0).isActive = true
label.leadingAnchor.constraint(greaterThanOrEqualTo: saveArea.leadingAnchor, constant: 15).isActive = true
label.trailingAnchor.constraint(lessThanOrEqualTo: saveArea.trailingAnchor, constant: -15).isActive = true
label.bottomAnchor.constraint(equalTo: saveArea.bottomAnchor, constant: -30).isActive = true
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: {
label.alpha = 1
}, completion: { _ in
UIView.animate(withDuration: 0.5, delay: delay, options: .curveEaseOut, animations: {
label.alpha = 0
}, completion: {_ in
label.removeFromSuperview()
})
})
}
}
Cómo utilizar:
class MyController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
showToast("Message")
}
}
Otra solucion
Ventaja:
-
En esta versión, no uso un enlace a
UIViewController
Desventajas
- Después de la rotación de la pantalla, la etiqueta no se mueve.
- No funciona correctamente con cadenas de varias líneas.
Código:
class Helper {
static let DELAY_SHORT = 1.5
static let DELAY_LONG = 3.0
static func showToast(_ text: String, delay: TimeInterval = DELAY_LONG) {
guard let window = UIApplication.shared.keyWindow else {
return
}
let label = BaseLabel()
label.backgroundColor = UIColor(white: 0, alpha: 0.5)
label.textColor = .white
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 15)
label.alpha = 0
label.text = text
label.numberOfLines = 0
var vertical: CGFloat = 0
var size = label.intrinsicContentSize
var width = min(size.width, window.frame.width - 60)
if width != size.width {
vertical = 10
label.textAlignment = .justified
}
label.textInsets = UIEdgeInsets(top: vertical, left: 15, bottom: vertical, right: 15)
size = label.intrinsicContentSize
width = min(size.width, window.frame.width - 60)
label.frame = CGRect(x: 20, y: window.frame.height - 90, width: width, height: size.height + 20)
label.center.x = window.center.x
label.layer.cornerRadius = min(label.frame.height/2, 25)
label.layer.masksToBounds = true
window.addSubview(label)
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: {
label.alpha = 1
}, completion: { _ in
UIView.animate(withDuration: 0.5, delay: delay, options: .curveEaseOut, animations: {
label.alpha = 0
}, completion: {_ in
label.removeFromSuperview()
})
})
}
}
Cómo utilizar:
Helper.showToast("Message")
si
makeToast:duration:position:
se define en el objetivo-c y se puede llamar, entonces el código rápido será
self.view.makeToast("Acount created Successfully", duration: 0.5, position: "bottom")
Sin embargo, es posible que deba usar un encabezado de puente para obtener acceso a esos métodos en su código rápido.
Swift 4
func showToast(message : String) {
let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75, y: self.view.frame.size.height-100, width: 150, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
toastLabel.text = message
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
self.view.addSubview(toastLabel)
UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
}
Llama a la función como
self.showToast(message: "Data Save.")
extension UIViewController {
func showToast(message : String, font: UIFont) {
let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75, y: self.view.frame.size.height-100, width: 150, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.font = font
toastLabel.textAlignment = .center;
toastLabel.text = message
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
self.view.addSubview(toastLabel)
UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
} }
static func popUp(context ctx: UIViewController, msg: String) {
let toast = UILabel(frame:
CGRect(x: 16, y: ctx.view.frame.size.height / 2,
width: ctx.view.frame.size.width - 32, height: 100))
toast.backgroundColor = UIColor.lightGray
toast.textColor = UIColor.white
toast.textAlignment = .center;
toast.numberOfLines = 3
toast.font = UIFont.systemFont(ofSize: 20)
toast.layer.cornerRadius = 12;
toast.clipsToBounds = true
toast.text = msg
ctx.view.addSubview(toast)
UIView.animate(withDuration: 5.0, delay: 0.2,
options: .curveEaseOut, animations: {
toast.alpha = 0.0
}, completion: {(isCompleted) in
toast.removeFromSuperview()
})
}
Entonces solo llámalo desde UIViewController
popUp(context: self, msg: "Your message")