Swift 扩展示例
Posted
技术标签:
【中文标题】Swift 扩展示例【英文标题】:Swift extension example 【发布时间】:2016-02-29 18:37:51 【问题描述】:我本来想知道怎么做这样的东西
UIColor.myCustomGreen
这样我就可以定义自己的颜色并在整个应用程序中使用它们。
我之前研究过扩展,我认为我可能可以使用它们来解决我的问题,但我不记得具体如何设置扩展。在撰写本文时,在 Google 上搜索“Swift 扩展”导致出现 documentation、several long tutorials,以及一个相当无用的 Stack Overflow question。
所以答案就在那里,但需要深入研究文档和教程。我决定写下这个问题和下面的答案,以向 Stack Overflow 添加一些更好的搜索关键字,并快速复习如何设置扩展。
我特别想知道:
扩展位于何处(文件和命名约定)? 什么是扩展语法? 有哪些简单的常用示例?【问题讨论】:
【参考方案1】:创建扩展
使用 File > New > File...> iOS > Source > Swift File 添加一个新的 swift 文件。你可以随心所欲地称呼它。
一般的命名约定是叫它TypeName+NewFunctionality.swift。
示例 1 - Double
Double+Conversions.swift
import Swift // or Foundation
extension Double
func celsiusToFahrenheit() -> Double
return self * 9 / 5 + 32
func fahrenheitToCelsius() -> Double
return (self - 32) * 5 / 9
用法:
let boilingPointCelsius = 100.0
let boilingPointFarenheit = boilingPointCelsius.celsiusToFahrenheit()
print(boilingPointFarenheit) // 212.0
示例 2 - String
String+Shortcuts.swift
import Swift // or Foundation
extension String
func replace(target: String, withString: String) -> String
return self.replacingOccurrences(of: target, with: withString)
用法:
let newString = "the old bike".replace(target: "old", withString: "new")
print(newString) // "the new bike"
Here 是一些更常见的String
扩展。
示例 3 - UIColor
UIColor+CustomColor.swift
import UIKit
extension UIColor
class var customGreen: UIColor
let darkGreen = 0x008110
return UIColor.rgb(fromHex: darkGreen)
class func rgb(fromHex: Int) -> UIColor
let red = CGFloat((fromHex & 0xFF0000) >> 16) / 0xFF
let green = CGFloat((fromHex & 0x00FF00) >> 8) / 0xFF
let blue = CGFloat(fromHex & 0x0000FF) / 0xFF
let alpha = CGFloat(1.0)
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
另见here。
用法:
view.backgroundColor = UIColor.customGreen
注意事项
一旦定义了扩展,就可以在应用中的任何位置使用它,就像内置类函数一样。 如果您不确定函数或属性语法应该是什么样子,您可以Option+单击类似的内置方法。例如,当我 Option+单击UIColor.greenColor
时,我看到声明是 class func greenColor() -> UIColor
。这为我提供了如何设置自定义方法的好线索。
Apple Documentation for Extensions
在 Objective-C 中,扩展被称为类别。
【讨论】:
为什么UIColor用class
定义函数而不用String?
@jacky,函数前的'class'关键字使它成为静态类型方法而不是实例方法。这样,您不必为了获得自定义颜色而实例化 UIColor。有关详细信息,请参阅此答案:***.com/a/31630431/3681880
今天将介绍我,但是您如何进行独特的扩展,即类动物、扩展牛、扩展猫、扩展狗?
@LorneK,听起来你在谈论subclassing。扩展只是向现有的类类型添加额外的功能或方法。另请参阅this article 进行比较。
值得注意的是,xcode 可能不会立即获取扩展方法并将您的呼叫视为未解决。自动触发构建就可以了!棘手。【参考方案2】:
试试这个新的扩展方法:
UIColor
extension UIColor
//get new color from rgb value
class func RGB(_ red:CGFloat , andGreenColor green:CGFloat, andBlueColor blue:CGFloat, withAlpha alpha:CGFloat) -> UIColor
let color = UIColor(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: alpha)
return color
//return color from comma separated string of RGB paramater
convenience init(rgbString :String, alpha:CGFloat = 1.0)
let arrColor = rgbString.components(separatedBy: ",")
let red:CGFloat = CGFloat(NumberFormatter().number(from: arrColor[0])!)
let green:CGFloat = CGFloat(NumberFormatter().number(from: arrColor[1])!)
let blue:CGFloat = CGFloat(NumberFormatter().number(from: arrColor[2])!)
self.init(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: alpha)
//return color from hexadecimal value
//let color2 = UIColor(rgbHexaValue: 0xFFFFFFFF)
convenience init(rgbHexaValue: Int, alpha: CGFloat = 1.0)
self.init(red: CGFloat((rgbHexaValue >> 16) & 0xFF), green: CGFloat((rgbHexaValue >> 8) & 0xFF), blue: CGFloat(rgbHexaValue & 0xFF), alpha: alpha)
UITextField
extension UITextField
//set cornerRadius
func cornerRadius()
self.layoutIfNeeded()
self.layer.cornerRadius = self.frame.height / 2
self.clipsToBounds = true
//set bordercolor
func borderColor()
self.layer.borderColor = TEXTFIELD_BORDER_COLOR.cgColor
self.layer.borderWidth = 1.0
//set borderWidth
func borderWidth(size:CGFloat)
self.layer.borderWidth = size
//check textfield is blank
func blank() -> Bool
let strTrimmed = self.text!.trim()//get trimmed string
if(strTrimmed.characters.count == 0)//check textfield is nil or not ,if nil then return false
return true
return false
//set begginning space - left space
func setLeftPadding(paddingValue:CGFloat)
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: paddingValue, height: self.frame.size.height))
self.leftViewMode = .always
self.leftView = paddingView
//set end of space
func setRightPadding(paddingValue:CGFloat)
let paddingView = UIView(frame: CGRect(x: (self.frame.size.width - paddingValue), y: 0, width: paddingValue, height: self.frame.size.height))
self.rightViewMode = .always
self.rightView = paddingView
UIFont
extension UIFont
// Returns a scaled version of UIFont
func scaled(scaleFactor: CGFloat) -> UIFont
let newDescriptor = fontDescriptor.withSize(fontDescriptor.pointSize * scaleFactor)
return UIFont(descriptor: newDescriptor, size: 0)
UIImage
public enum ImageFormat
case PNG
case JPEG(CGFloat)
extension UIImage
//convert image to base64 string
func toBase64() -> String
var imageData: NSData
switch format
case .PNG: imageData = UIImagePNGRepresentation(self)! as NSData
case .JPEG(let compression): imageData = UIImageJPEGRepresentation(self, compression)! as NSData
return imageData.base64EncodedString(options: .lineLength64Characters)
//convert string to image
class func base64ToImage(toImage strEncodeData: String) -> UIImage
let dataDecoded = NSData(base64Encoded: strEncodeData, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)!
let image = UIImage(data: dataDecoded as Data)
return image!
//Function for store file/Image into local directory. If image is already on the directory then first remove it and replace new image/File on that location
func storedFileIntoLocal(strImageName:String) -> String
var strPath = ""
let documentDirectory1 = NSString.init(string: String.documentDirectory())
let imageName:String = strImageName + ".png"
let imagePath = documentDirectory1.appendingPathComponent(imageName)
strPath = imagePath
let fileManager = FileManager.default
let isExist = fileManager.fileExists(atPath: String.init(imagePath))
if(isExist == true)
do
try fileManager.removeItem(atPath: imagePath as String)//removing file if exist
// print("Remove success")
catch
print(error)
let imageData:Data = UIImageJPEGRepresentation(self, 0.5)!
do
try imageData.write(to: URL(fileURLWithPath: imagePath as String), options: .atomic)
catch
print(error)
strPath = "Failed to cache image data to disk"
return strPath
return strPath
//function for resize image
func resizeImage(targetSize: CGSize) -> UIImage
let size = self.size
let widthRatio = targetSize.width / self.size.width
let heightRatio = targetSize.height / self.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio)
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
else
// newSize = size
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
日期
let YYYY_MM_DD_HH_MM_SS_zzzz = "yyyy-MM-dd HH:mm:ss +zzzz"
let YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"
let DD_MM_YYYY = "dd-MM-yyyy"
let MM_DD_YYYY = "MM-dd-yyyy"
let YYYY_DD_MM = "yyyy-dd-MM"
let YYYY_MM_DD_T_HH_MM_SS = "yyyy-MM-dd'T'HH:mm:ss"
extension Date
//convert string to date
static func convertStringToDate(strDate:String, dateFormate strFormate:String) -> Date
let dateFormate = DateFormatter()
dateFormate.dateFormat = strFormate
dateFormate.timeZone = TimeZone.init(abbreviation: "UTC")
let dateResult:Date = dateFormate.date(from: strDate)!
return dateResult
//Function for old date format to new format from UTC to local
static func convertDateUTCToLocal(strDate:String, oldFormate strOldFormate:String, newFormate strNewFormate:String) -> String
let dateFormatterUTC:DateFormatter = DateFormatter()
dateFormatterUTC.timeZone = NSTimeZone(abbreviation: "UTC") as TimeZone!//set UTC timeZone
dateFormatterUTC.dateFormat = strOldFormate //set old Format
if let oldDate:Date = dateFormatterUTC.date(from: strDate) as Date?//convert date from input string
dateFormatterUTC.timeZone = NSTimeZone.local//set localtimeZone
dateFormatterUTC.dateFormat = strNewFormate //make new dateformatter for output format
if let strNewDate:String = dateFormatterUTC.string(from: oldDate as Date) as String?//convert dateInUTC into string and set into output
return strNewDate
return strDate
return strDate
//Convert without UTC to local
static func convertDateToLocal(strDate:String, oldFormate strOldFormate:String, newFormate strNewFormate:String) -> String
let dateFormatterUTC:DateFormatter = DateFormatter()
//set local timeZone
dateFormatterUTC.dateFormat = strOldFormate //set old Format
if let oldDate:Date = dateFormatterUTC.date(from: strDate) as Date?//convert date from input string
dateFormatterUTC.timeZone = NSTimeZone.local
dateFormatterUTC.dateFormat = strNewFormate //make new dateformatter for output format
if let strNewDate = dateFormatterUTC.string(from: oldDate as Date) as String?//convert dateInUTC into string and set into output
return strNewDate
return strDate
return strDate
//Convert Date to String
func convertDateToString(strDateFormate:String) -> String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = strDateFormate
let strDate = dateFormatter.string(from: self)
// dateFormatter = nil
return strDate
//Convert local to utc
static func convertLocalToUTC(strDate:String, oldFormate strOldFormate:String, newFormate strNewFormate:String) -> String
let dateFormatterUTC:DateFormatter = DateFormatter()
dateFormatterUTC.timeZone = NSTimeZone.local as TimeZone!//set UTC timeZone
dateFormatterUTC.dateFormat = strOldFormate //set old Format
if let oldDate:Date = dateFormatterUTC.date(from: strDate) as Date?//convert date from input string
dateFormatterUTC.timeZone = NSTimeZone.init(abbreviation: "UTC")! as TimeZone//set localtimeZone
dateFormatterUTC.dateFormat = strNewFormate //make new dateformatter for output format
if let strNewDate:String = dateFormatterUTC.string(from: oldDate as Date) as String?//convert dateInUTC into string and set into output
return strNewDate
return strDate
return strDate
//Comparison two date
static func compare(date:Date, compareDate:Date) -> String
var strDateMessage:String = ""
let result:ComparisonResult = date.compare(compareDate)
switch result
case .orderedAscending:
strDateMessage = "Future Date"
break
case .orderedDescending:
strDateMessage = "Past Date"
break
case .orderedSame:
strDateMessage = "Same Date"
break
default:
strDateMessage = "Error Date"
break
return strDateMessage
调用这个函数:
let color1 = UIColor.RGB(100.0, andGreenColor: 200.0, andBlueColor: 300.0, withAlpha: 1.0)
let color2 = UIColor.init(rgbHexaValue: 800000, alpha: 1.0)
let color3 = UIColor.init(rgbString: ("100.0,200.0,300.0", alpha: 1.0)
self.txtOutlet.cornerRadius()
self.txtOutlet.borderColor()
self.txtOutlet.setLeftPadding(paddingValue: 20.0)
self.txtOutlet.setRightPadding(paddingValue: 20.0)
let yourScaledFont = self.dependentView.font.scaled(scaleFactor: n as! CGFloat)
let base64String = (image?.toBase64(format: ImageFormat.PNG))!
let resultImage = UIImage.base64ToImage(toImage: base64String)
let path = yourImage.storedFileIntoLocal(strImageName: "imagename")
【讨论】:
【参考方案3】:Swift 3.0 示例:
extension UITextField
func useUnderline()
let border = CALayer()
let borderWidth = CGFloat(1.0)
border.borderColor = UIColor.lightGray.cgColor
border.frame = CGRect(origin: CGPoint(x: 0,y :self.frame.size.height - borderWidth), size: CGSize(width: self.frame.size.width, height: self.frame.size.height))
border.borderWidth = borderWidth
self.layer.addSublayer(border)
self.layer.masksToBounds = true
【讨论】:
在您的情况下,我宁愿创建一个继承自 UITextField 的新类,而不是扩展原始 UITextField。它提供了更大的灵活性。如果我想在同一个应用程序中为我的文本字段使用不同的样式怎么办?扩展被全局添加到原始类中。【参考方案4】:
UITextField
中的文字下划线
用于函数ViewDidLoad()
firstNametext.underlined(0.5)
扩展
extension UITextField
func underlined(_ size:Double)
let border = CALayer()
let width = CGFloat(size)
border.borderColor = UIColor.red.cgColor
border.frame = CGRect(x: 0, y: self.frame.size.height - width,
width: self.frame.size.width, height: self.frame.size.height)
border.borderWidth = width
self.layer.addSublayer(border)
self.layer.masksToBounds = true
【讨论】:
嗨!欢迎来到堆栈溢出!关于 *** 的好的答案,通常会有一些解释。下次回答问题时要考虑一下! @Qwerty,它有解释,但它的格式像代码。我重新格式化了它。【参考方案5】:UIColor+util.swift
import UIKit
extension UIColor
class func getCustomBlueColor() -> UIColor
return UIColor(red:0.043, green:0.576 ,blue:0.588 , alpha:1.00)
func getNameofColour() ->String
return "myOrange"
用法:
NSLog("\(UIColor.getCustomBlueColor())")
let color=UIColor(red:0.043, green:0.576 ,blue:0.588 , alpha:1.00);
NSLog(color.getNameofColour())
我希望你看到有什么不同。一个以 class func 开头的函数,另一个仅以 func 开头的函数。你可以使用你喜欢的。
【讨论】:
导入uikit时报错,是我做错了吗?【参考方案6】:扩展和便利初始化器的最佳示例之一:
extension UIActivityIndicatorView
convenience init(activityIndicatorStyle: UIActivityIndicatorViewStyle, color: UIColor, placeInTheCenterOf parentView: UIView)
self.init(activityIndicatorStyle: activityIndicatorStyle)
center = parentView.center
self.color = color
parentView.addSubview(self)
您可以通过以下方式使用它:
初始化活动指示器
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge, color: .gray, placeInTheCenterOf: view)
开始动画活动指示器
activityIndicator.startAnimating()
停止动画活动指示器
activityIndicator.stopAnimating()
【讨论】:
【参考方案7】:如果您喜欢使用具有给定色调的颜色,例如品牌手册中使用的颜色: Swift 4.2 + xcode 9.4.1。
extension UIColor
func withTint(tint: CGFloat)->UIColor
var tint = max(tint, 0)
tint = min(tint, 1)
/* Collect values of sender */
var r : CGFloat = 0
var g : CGFloat = 0
var b : CGFloat = 0
var a : CGFloat = 0
self.getRed(&r, green: &g, blue: &b, alpha: &a)
/* Calculate the tint */
r = r+(1-r)*(1-tint)
g = g+(1-g)*(1-tint)
b = b+(1-b)*(1-tint)
a = 1
return UIColor.init(red: r, green: g, blue: b, alpha: a)
在您的代码中
let redWithTint = UIColor.red.withTint(tint: 0.4)
【讨论】:
【参考方案8】:这是一个引人注目的动画效果的扩展示例,它适用于 UITableView 中的单元格。当您滚动 UITableView 时,每个单元格都会从一个点源增长到正常大小。根据需要调整动画时间。
由于每个单元格在滚动时会出现一点时间错开,因此效果会很好地涟漪!请看这个展示效果的 15 秒剪辑:https://www.youtube.com/watch?v=BVeQpno56wU&feature=youtu.be
extension UITableViewCell
func growCellDuringPresentation(thisCell : UITableViewCell)
thisCell.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
UIView.animate(withDuration: TimeInterval(0.35), delay: 0.0, options: UIView.AnimationOptions.allowUserInteraction, animations:
thisCell.transform = CGAffineTransform(scaleX: 1, y: 1)
, completion: nil)
要使用扩展程序,您只需在 cellForRowAt 中返回单元格之前调用它,如下所示:
cell.growCellDuringPresentation(thisCell: cell)
return cell
请注意,在为集合视图返回单元格时,此方法也适用。
这是一个完全一样的扩展,除了它在演示期间旋转单元格:
extension UITableViewCell
func rotateCellDuringPresentation(thisCell : UITableViewCell)
thisCell.transform = CGAffineTransform(rotationAngle: .pi)
UIView.animate(withDuration: TimeInterval(0.35), delay: 0.0, options: UIView.AnimationOptions.allowUserInteraction, animations:
thisCell.transform = CGAffineTransform(rotationAngle: 0)
, completion: nil)
类似的叫法:
cell.rotateCellDuringPresentation(thisCell: cell)
return cell
这是沿 X 方向平移单元格的相同线的延伸
extension UITableViewCell
func translateCellDuringPresentation(thisCell : UITableViewCell)
thisCell.layer.transform = CATransform3DMakeTranslation(-300, 0, 0)
UIView.animate(withDuration: TimeInterval(0.5), delay: 0.0, options: UIView.AnimationOptions.allowUserInteraction, animations:
thisCell.layer.transform = CATransform3DMakeTranslation(0, 0, 0)
, completion: nil)
类似的叫法:
cell.translateCellDuringPresentation(thisCell: cell)
return cell
【讨论】:
以上是关于Swift 扩展示例的主要内容,如果未能解决你的问题,请参考以下文章