【问题标题】:Swift extension exampleSwift 扩展示例
【发布时间】:2016-02-29 18:37:51
【问题描述】:

我本来想知道怎么做这样的东西

UIColor.myCustomGreen

这样我就可以定义自己的颜色并在整个应用程序中使用它们。

我之前研究过扩展,我认为我可能可以使用它们来解决我的问题,但我不记得具体如何设置扩展。在撰写本文时,在 Google 上搜索“Swift 扩展”导致出现 documentationseveral long tutorials,以及一个相当无用的 Stack Overflow question

所以答案就在那里,但需要深入研究文档和教程。我决定写下这个问题和下面的答案,以向 Stack Overflow 添加一些更好的搜索关键字,并快速复习如何设置扩展。

我特别想知道:

  • 扩展位于何处(文件和命名约定)?
  • 什么是扩展语法?
  • 有哪些简单的常用示例?

【问题讨论】:

    标签: swift extension-methods


    【解决方案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。有关详细信息,请参阅此答案:stackoverflow.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 }
          }
      }
      

      【讨论】:

      • 嗨!欢迎来到堆栈溢出!关于 stackoverflow 的好的答案,通常会有一些解释。下次回答问题时要考虑一下!
      • @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)
        }
      }
      

      您可以通过以下方式使用它:

      1. 初始化活动指示器

        let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge, color: .gray,  placeInTheCenterOf: view)
        
      2. 开始动画活动指示器

        activityIndicator.startAnimating()
        
      3. 停止动画活动指示器

        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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-10-22
            • 2011-05-10
            • 2015-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多