• Swift自定义AlertView


    今天项目加新需求,添加积分过期提醒功能:

    第一反应就用系统的UIAlertViewController,但是message中积分是需要红色显示。

    //        let str = "尊敬的顾客,您有1000积分即将过期,请尽快使用"
    //        let attributeStr = changeTextChange(regex: "\d+", text: str, color: UIColor.red)
    //        let alertController = UIAlertController(title: "积分即将过期提醒",
    //                                                message: attributeStr.string, preferredStyle: .alert)
    //        let cancelAction = UIAlertAction(title: "兑换菜品", style: .cancel, handler: nil)
    //        let okAction = UIAlertAction(title: "暂不兑换", style: .default, handler: {
    //            action in
    //            print("点击了确定")
    //        })
    //        alertController.addAction(cancelAction)
    //        alertController.addAction(okAction)
    //        self.present(alertController, animated: true, completion: nil)

    //根据正则表达式改变文字颜色

    
    

        func changeTextChange(regex: String, text: String, color: UIColor) -> NSMutableAttributedString {

    
    

            let attributeString = NSMutableAttributedString(string: text)

    
    

            do {

    
    

                let regexExpression = try NSRegularExpression(pattern: regex, options: NSRegularExpression.Options())

    
    

                let result = regexExpression.matches(in: text, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, text.characters.count))

    
    

                for item in result {

    
    

                    attributeString.addAttribute(NSAttributedStringKey.foregroundColor, value: color, range: item.range)

    
    

                }

    
    

            } catch {

    
    

                print("Failed with error: (error)")

    
    

            }

    
    

            return attributeString

    
    

        }

    用NSAttributedstring改变属性了的属性字符串,如果再转换成String,之前的属性就没有了,是否可以直接把NSAttributedstring的属性字符串直接添加到AlertViewController中替换掉要改变字体颜色的string呢?

    网上说是有解决办法的,但是没找到解决办法,有知道记得告诉思思哈。

    http://www.maccocoa.com/forum/archive/index.php/t-130.html

    于是只有自定义AlertView,这样怎么都能实现了。

    //
    //  CustomAlertView.swift
    //  HaidilaoPad
    //
    //  Created by 彭思 on 2018/5/3.
    //  Copyright © 2018年 HongHuoTai. All rights reserved.
    //
    
    import UIKit
    
    let AlertWidth: CGFloat   = 270
    let AlertHeight: CGFloat  = 130
    let AlertPadding: CGFloat = 10
    let MenuHeight: CGFloat   = 44
    
    enum ButtonType {
        case button_OK
        case button_CANCEL
        case button_OTHER
    }
    
    class AlertItem: NSObject {
        var title: String?
        var type: ButtonType?
        var tag: NSInteger?
        var action: ((_ item:AlertItem) -> Void)?
    }
    
    class CustomAlertView: UIView {
    
        // MARK: - Lazy
        lazy var coverView: UIView = {
            let coverView = UIView(frame: self.topView().bounds)
            coverView.backgroundColor = UIColor.black
            coverView.alpha = 0
            coverView.autoresizingMask = UIViewAutoresizing.flexibleHeight
            return coverView
        }()
        lazy var alertView: UIView = {
            let alertView = UIView(frame: CGRect(x: 0, y: 0,  AlertWidth, height: AlertHeight))
            alertView.center = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
            alertView.layer.masksToBounds = true
            alertView.layer.cornerRadius  = 10
            alertView.backgroundColor = UIColor.white
            return alertView
        }()
        lazy var titleLabel: UILabel = {
            let titleLabel = UILabel()
            titleLabel.font      = UIFont.boldSystemFont(ofSize: 17)
            titleLabel.textColor = UIColor.black
            titleLabel.textAlignment = NSTextAlignment.center
            titleLabel.numberOfLines = 0
            titleLabel.text = self.title
            titleLabel.lineBreakMode = NSLineBreakMode.byCharWrapping
            return titleLabel
        }()
        lazy var topLineView: UIView = {
            let topLineView = UIView()
            topLineView.backgroundColor = UIColor.lightGray
            return topLineView
        }()
        lazy var messageLabel: UILabel = {
            let messageLabel = UILabel()
            messageLabel.font = UIFont.systemFont(ofSize: 14)
            messageLabel.textAlignment = .center
            messageLabel.numberOfLines = 0
            messageLabel.textAlignment = NSTextAlignment.center
            messageLabel.lineBreakMode = NSLineBreakMode.byCharWrapping
            return messageLabel
        }()
        
        var buttonScrollView: UIScrollView?
        var contentScrollView: UIScrollView?
        
        var items: NSMutableArray?
        var title: String?
        var message: String?
        
        var buttonWidth: CGFloat?
        var contentView: UIView?
        
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
        
        // 便利构造函数
        convenience init(title:String, message:String, messageColor:UIColor?) {
            
            // 计算frame
            var screenWidth  = UIScreen.main.bounds.size.width
            var screenHeight = UIScreen.main.bounds.size.height
            // On iOS7, screen width and height doesn't automatically follow orientation
            if floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1 {
                let interfaceOrientation = UIApplication.shared.statusBarOrientation
                if UIInterfaceOrientationIsLandscape(interfaceOrientation) {
                    let tmp = screenWidth
                    screenWidth = screenHeight
                    screenHeight = tmp
                }
            }
            let rect = CGRect(x: 0, y: 0,  screenWidth, height: screenHeight)
            self.init(frame: rect)
            self.items = NSMutableArray()
            self.title = title
            self.message = message
            
            // 设置views
            self.setupSubViews(messageColor)
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        // MARK: - Setup UI
        
        func setupSubViews(_ color:UIColor?) {
            
            self.topView().addSubview(self.coverView)
            self.addSubview(self.alertView)
            // 设置title
            let labelHeight = self.heightOfRow(self.title!, font: 17,  AlertWidth - 2 * AlertPadding)
            titleLabel.frame = CGRect(x: AlertPadding, y: AlertPadding,  AlertWidth - 2 * AlertPadding, height: labelHeight)
            self.alertView.addSubview(self.titleLabel)
            topLineView.frame = CGRect(x: 0, y: self.titleLabel.frame.origin.y + self.titleLabel.frame.size.height + 5,  AlertWidth, height: 0.5)
            self.alertView.addSubview(self.topLineView)
            
            // 设置message
            let messageHeight = self.heightOfRow(self.message!, font: 14,  AlertWidth - 2 * AlertPadding)
            messageLabel.frame = CGRect(x: AlertPadding, y: self.topLineView.frame.origin.y + self.topLineView.frame.size.height + 5,  AlertWidth - 2 * AlertPadding, height: messageHeight + 2 * AlertPadding)
            self.alertView.addSubview(self.messageLabel)
            
            let mesColor:UIColor = color ?? UIColor.black
            messageLabel.textColor = mesColor
            let attributeStr = changeTextChange(regex: "\d+", text: self.message!, color: UIColor.red)
            self.messageLabel.attributedText = attributeStr
            self.alertView.addSubview(self.messageLabel)
            
            self.contentScrollView = UIScrollView(frame: CGRect.zero)
            self.alertView.addSubview(self.contentScrollView!)
            
            UIDevice.current.beginGeneratingDeviceOrientationNotifications()
            NotificationCenter.default.addObserver(self, selector: #selector(CustomAlertView.deviceOrientationDidChange(_:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
        }
        
        // dealloc
        deinit {
            UIDevice.current.endGeneratingDeviceOrientationNotifications()
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
        }
        
        // override func
        
        override func layoutSubviews() {
            self.buttonScrollView?.frame = CGRect(x: 0, y: self.alertView.frame.size.height-MenuHeight, self.alertView.frame.size.width, height: MenuHeight);
            self.contentScrollView?.frame = CGRect(x: 0, y: self.titleLabel.frame.origin.y + self.titleLabel.frame.size.height,  self.alertView.frame.size.width, height: self.alertView.frame.size.height - MenuHeight);
            self.contentView?.frame = CGRect(x: 0,y: 0, self.contentView!.frame.size.width, height: self.contentView!.frame.size.height);
            if self.contentView != nil {
                self.contentScrollView?.contentSize = self.contentView!.frame.size;
            }
            
        }
        
        override func willMove(toSuperview newSuperview: UIView?) {
            self.addButtonItem()
            if self.contentView != nil {
                self.contentScrollView?.addSubview(self.contentView!)
            }
            self.reLayout()
        }
        
        // show and dismiss
        func topView() -> UIView {
            let window = UIApplication.shared.keyWindow
            return (window?.subviews[0])!
        }
        
        func show() {
            UIView.animate(withDuration: 0.5, animations: { () -> Void in
                self.coverView.alpha = 0.5
            }, completion: { (finished) -> Void in
                
            })
            self.topView().addSubview(self)
            self.showAnimation()
        }
        
        //------Preoperties------
        func addButtonWithTitle(_ title:String) -> NSInteger {
            let item = AlertItem()
            item.title = title
            item.action = {(ite:AlertItem)->Void in
                print("no action")
            }
            item.type = ButtonType.button_OK
            self.items?.add(item)
            return (self.items?.index(of: title))!
        }
        
        func addButton(_ type:ButtonType, title:String, handler:@escaping ((_ item:AlertItem) -> Void)) {
            let item = AlertItem()
            item.title = title
            item.action = handler
            item.type = type
            self.items?.add(item)
            item.tag = self.items?.index(of: item)
        }
        
        func addButtonItem() {
            self.buttonScrollView = UIScrollView(frame: CGRect(x: 0, y: self.alertView.frame.size.height -  MenuHeight, AlertWidth, height: MenuHeight))
            self.buttonScrollView?.bounces = false
            self.buttonScrollView?.showsHorizontalScrollIndicator = false
            self.buttonScrollView?.showsVerticalScrollIndicator = false
            let CGFloat
            if (self.buttonWidth != nil) {
                width = self.buttonWidth!
                let a = CGFloat((self.items?.count)!)
                self.buttonScrollView?.contentSize = CGSize( a * width, height: MenuHeight)
            } else {
                width = (self.alertView.frame.size.width) / CGFloat((self.items?.count)!)
            }
            
            self.items?.enumerateObjects({ (item, idx, stop) in
                let button = UIButton(type: UIButtonType.system)
                button.frame = CGRect(x: CGFloat(idx) * width, y: 1,  width, height: MenuHeight)
                button.backgroundColor = UIColor.white
                button.layer.shadowColor = UIColor.gray.cgColor
                button.layer.shadowRadius = 0.5
                button.layer.shadowOpacity = 1
                button.layer.shadowOffset = CGSize.zero
                button.layer.masksToBounds = false
                button.tag = 90000 + idx
                button.setTitleColor(UIColor.darkGray, for: .normal)
                
                let ite = item as! AlertItem
                
                button.setTitle(ite.title, for: UIControlState())
                button.setTitle(ite.title, for: UIControlState.selected)
                button.titleLabel?.font = UIFont.boldSystemFont(ofSize: (button.titleLabel?.font.pointSize)!)
                
                button.addTarget(self, action: #selector(CustomAlertView.buttonTouched(_:)), for: UIControlEvents.touchUpInside)
                self.buttonScrollView?.addSubview(button)
                
                // 按钮边框
                if idx != (self.items?.count)! - 1 {
                    let seprateLineVer = UIView(frame: CGRect(x: width - 1, y: 0,  0.5, height: MenuHeight))
                    seprateLineVer.backgroundColor = UIColor.lightGray
                    button.addSubview(seprateLineVer)
                }
                
                let seprateLineHor = UIView(frame: CGRect(x: 0, y: 0,  self.buttonScrollView!.frame.size.width, height: 0.5))
                seprateLineHor.backgroundColor = UIColor.lightGray
                self.buttonScrollView?.addSubview(seprateLineHor)
            })
            self.alertView.addSubview(self.buttonScrollView!)
        }
        
        @objc func buttonTouched(_ button:UIButton) {
            let item:AlertItem = self.items![button.tag - 90000] as! AlertItem
            if (item.action != nil) {
                item.action!(item)
            }
            self.dismiss()
        }
        
        func reLayout() {
            var plus:CGFloat
            if self.contentView != nil {
                plus = (self.contentView!.frame.size.height) - ((self.alertView.frame.size.height) - MenuHeight)
            } else {
                plus = (self.messageLabel.frame.origin.y) + (self.messageLabel.frame.size.height) - ((self.alertView.frame.size.height) - MenuHeight)
            }
            plus = max(0, plus)
            let height = min(self.screenBounds().size.height - MenuHeight, (self.alertView.frame.size.height) + plus)
            
            self.alertView.frame = CGRect(x: self.alertView.frame.origin.x, y: self.alertView.frame.origin.y,  AlertWidth, height: height)
            self.alertView.center = self.center
            self.setNeedsDisplay()
            self.setNeedsLayout()
        }
        
        func dismiss() {
            self.hideAnimation()
        }
        
        // MARK: - showAnimation
        func showAnimation() {
            let popAnimation = CAKeyframeAnimation(keyPath: "transform")
            popAnimation.duration = 0.4
            popAnimation.values   = [
                NSValue.init(caTransform3D: CATransform3DMakeScale(0.01, 0.01, 1.0)),
                NSValue.init(caTransform3D: CATransform3DMakeScale(1.1, 1.1, 1.0)),
                NSValue.init(caTransform3D: CATransform3DMakeScale(0.9, 0.9, 1.0)),
                NSValue.init(caTransform3D: CATransform3DIdentity)
            ]
            popAnimation.keyTimes = [0.2, 0.5, 0.75, 1.0]
            popAnimation.timingFunctions = [
                CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut),
                CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut),
                CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
            ]
            self.alertView.layer.add(popAnimation, forKey: nil)
        }
        
        func hideAnimation() {
            UIView.animate(withDuration: 0.4, animations: { () -> Void in
                self.coverView.alpha = 0.0
                self.alertView.alpha = 0.0
            }, completion: { (finished) -> Void in
                self.removeFromSuperview()
            })
        }
        
        // handle device orientation changes
        @objc func deviceOrientationDidChange(_ notification:Notification) {
            self.frame = self.screenBounds()
            UIView.animate(withDuration: 0.2, delay: 0.0, options: UIViewAnimationOptions(), animations: { () -> Void in
                self.reLayout()
            }) { (finished) -> Void in
                
            }
        }
        
        //------Tools-------
        // 计算frame
        func screenBounds() -> CGRect {
            var screenWidth  = UIScreen.main.bounds.size.width
            var screenHeight = UIScreen.main.bounds.size.height
            // On iOS7, screen width and height doesn't automatically follow orientation
            if floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1 {
                let interfaceOrientation = UIApplication.shared.statusBarOrientation
                if UIInterfaceOrientationIsLandscape(interfaceOrientation) {
                    let tmp = screenWidth
                    screenWidth = screenHeight
                    screenHeight = tmp
                }
            }
            return CGRect(x: 0, y: 0,  screenWidth, height: screenHeight)
        }
        
        // 计算字符串高度
        func heightOfRow(_ text:String, font:CGFloat, CGFloat) -> CGFloat {
            let size:CGSize = text.boundingRect(with: CGSize( width, height: 0), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : UIFont.systemFont(ofSize: font)], context: nil).size
            return size.height;
        }
        
        //根据正则表达式改变文字颜色
        func changeTextChange(regex: String, text: String, color: UIColor) -> NSMutableAttributedString {
            let attributeString = NSMutableAttributedString(string: text)
            do {
                let regexExpression = try NSRegularExpression(pattern: regex, options: NSRegularExpression.Options())
                let result = regexExpression.matches(in: text, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, text.characters.count))
                for item in result {
                    attributeString.addAttribute(NSAttributedStringKey.foregroundColor, value: color, range: item.range)
                }
            } catch {
                print("Failed with error: (error)")
            }
            return attributeString
        }
    }

     实现效果如下:

  • 相关阅读:
    React Native之Android应用开发IDE选项
    react-native环境配置——Android工程搭建
    《更换电池》
    canvas绘图是基于状态的绘图方式
    关于JSONP的一些概念
    iOS 学习笔记七 【博爱手把手教你使用2016年gitHub Mac客户端】
    iOS 学习笔记六 【APP中的文字和APP名字的国际化多语言处理】
    iOS 学习笔记五 【2016年百度地图定位详细使用方法】
    iOS 学习笔记四 【xcode 7.3 ESJsonFormat-Xcode 插件不能使用的解决办法】
    iOS 学习笔记三【segmentedControl分段控制器详细使用方法】
  • 原文地址:https://www.cnblogs.com/pengsi/p/8986209.html
Copyright © 2020-2023  润新知