美文网首页
UITextView link跳转

UITextView link跳转

作者: 流云_henry | 来源:发表于2022-08-10 17:13 被阅读0次

    废话不多说,直接上代码,通过一个弹窗来展示效果

    import UIKit
    import FZBaseKit
    import SnapKit
    import RxSwift
    @objcMembers
    /// 新的弹窗alert,支持富文本点击跳转,支持左侧取消按钮,右侧确定按钮;支持中间一个确定按钮
    open class FZAlertView: UIView {
        //按钮点击回调,取消按钮false 确认按钮 true
        typealias hander = (_ result: Bool)->()
        typealias strHander = (_ index: Int, _ linkStr: String)->()
        //按钮点击回调属性
        private var callBlock:hander?
        //富文本点击回调属性
        private var strCallBlock:strHander?
        private var attributedArr: Array<FZAlertViewModel>?
        private let bag = DisposeBag.init()
        //白色承载体
        lazy var bgView: UIView = {
            let view = UIView.init()
            view.backgroundColor = .white
            view.layer.cornerRadius = CGFloat(KRatio(15))
            view.clipsToBounds = true
            return view
        }()
        
        lazy var contentTextView: UITextView = {
            let textView = UITextView.init()
            textView.textAlignment = .center
            textView.font = KFont(CGFloat(KRatio(15)))
            textView.textColor = UIColor.hex("#3D3838")
            textView.backgroundColor = .white
            textView.delegate = self
            textView.isEditable = false //禁止编辑
            textView.isScrollEnabled = false //禁止滚动
            return textView
        }()
        
        lazy var cancelBtn: UIButton = {
            let btn = UIButton.initButton(title: "", titleColor: UIColor.hex("#3D3838"), fontSize: 18, bgColor: UIColor.clear, imageName: "")
            btn.layer.masksToBounds = true
            btn.layer.cornerRadius = CGFloat(KRatio(22))
            btn.layer.borderWidth = 0.5
            btn.layer.borderColor = UIColor.hex("#918B8B").cgColor
            return btn
        }()
        
        lazy var confirmBtn: UIButton = {
            let btn = UIButton.initButton(title: "", titleColor: UIColor.white, fontSize: 18, bgColor: UIColor.hex("#6249EE"), imageName: "")
            btn.layer.masksToBounds = true
            btn.layer.cornerRadius = CGFloat(KRatio(22))
            return btn
        }()
        
        /// 创建alertView
        /// - Parameters:
        ///   - message: 文本信息
        ///   - sureBtnTitle: 确认按钮标题
        ///   - cancelBtnTitle: 取消按钮标题,如果无取消按钮该值不传
        ///   - supperVC: 推出alertview的VC,如果为空,就通过KAppwindow弹出
        ///   - btnActionCallBack: 取消、确认按钮点击回调
        ///   - attributedArr: 富文本点击数组,数组内部字典组成为,无富文本点击可不传
        ///   - attributedClickActionCallBack: 富文本点击回调
        /// - Returns: 返回alertView
       public static func showAlertView(message: String, supperVC: UIViewController?, sureBtnTitle: String, cancelBtnTitle: String = "", attributedArr: Array<FZAlertViewModel> = [], btnActionCallBack: @escaping (_ result: Bool)->(), attributedClickActionCallBack: @escaping (_ index: Int, _ linkStr: String)->()) {
            let frame = supperVC == nil ? CGRect.init(x: 0, y: 0, width: KWIDTH_SCREEN, height: KHEIGHT_SCREEN) : supperVC!.view.bounds
            let alertView = FZAlertView.init(frame: frame)
            alertView.callBlock = btnActionCallBack
            alertView.strCallBlock = attributedClickActionCallBack
            alertView.attributedArr = attributedArr
            alertView.initUI(supperVC: supperVC)
            alertView.setData(message: message, sureBtnTitle: sureBtnTitle, cancelTitle: cancelBtnTitle)
            alertView.layoutUI(message: message, cancelTitle: cancelBtnTitle)
        }
        
        //UI构建
        private func initUI(supperVC: UIViewController?) {
            self.backgroundColor = UIColor.RGBA(0, 0, 0, 0.6)
            self.addSubview(bgView)
            bgView.addSubview(contentTextView)
            bgView.addSubview(confirmBtn)
            bgView.addSubview(cancelBtn)
            if supperVC == nil {
                KAppWindow?.addSubview(self)
            } else {
                supperVC?.view.addSubview(self)
                supperVC?.view.bringSubviewToFront(self)
            }
        }
        
        //数据处理
        private func setData(message: String, sureBtnTitle: String, cancelTitle: String) {
            self.confirmBtn.setTitle(sureBtnTitle, for: .normal)
            self.cancelBtn.setTitle(cancelTitle, for: .normal)
            //textView富文本
            contentTextView.attributedText = self.getContentTextViewAttributedText(message: message)
            //按钮点击
            cancelBtn.rx.tap.asObservable()
                .subscribe {[weak self] _ in
                    guard let self = self else {return}
                    if self.callBlock != nil {
                        self.callBlock!(false)
                        self.removeFromSuperview()
                    }
                }
                .disposed(by: bag)
            
            confirmBtn.rx.tap.asObservable()
                .subscribe{[weak self] _ in
                    guard let self = self else {return}
                    if self.callBlock != nil {
                        self.callBlock!(true)
                        self.removeFromSuperview()
                    }
                }
                .disposed(by: bag)
        }
        
        //布局构建
        private func layoutUI(message: String, cancelTitle: String) {
            let btnWidth = KRatio(105)
            let btnHeight = KRatio(44)
            var contentWidth = KRatio(275)//默认高度
            let textViewHeight = message.getStringHeight(CGFloat(KRatio(230)), KFont(CGFloat(KRatio(15)))) + CGFloat(KRatio(20))
            
            var contentHeight = Int(textViewHeight) + KRatio(20) + btnHeight + KRatio(40)
            if contentHeight < KRatio(175) {
                contentHeight = KRatio(175)
            }
            if contentHeight > KRatio(550) {
                //如果高度过高,那么设置最大高度,并且设置textView可滚动
                contentHeight = KRatio(550)
                contentTextView.isScrollEnabled = true
            }
            
            bgView.snp.makeConstraints { make in
                make.center.equalToSuperview()
                make.size.equalTo(CGSize.init(width: contentWidth, height: contentHeight))
            }
            contentTextView.snp_makeConstraints { make in
                make.left.equalTo(bgView).offset(KRatio(20))
                make.right.equalTo(bgView).offset(KRatio(-20))
                make.top.equalTo(bgView).offset(KRatio(20))
            }
            //按钮布局分为取消、确认按钮和只有确认按钮两种情况,根据cancelTitle来判断
            if cancelTitle.count == 0 {
                //隐藏cancelTitle
                cancelBtn.isHidden = true
                //surebtn据中
                confirmBtn.snp.makeConstraints { make in
                    make.centerX.equalTo(bgView)
                    make.size.equalTo(CGSize.init(width: btnWidth, height: btnHeight))
                    make.bottom.equalTo(bgView).offset(KRatio(-17))
                }
            } else {
                cancelBtn.snp.makeConstraints { make in
                    make.left.equalTo(bgView).offset(KRatio(20))
                    make.bottom.equalTo(bgView).offset(KRatio(-17))
                    make.size.equalTo(CGSize.init(width: btnWidth, height: btnHeight))
                }
                confirmBtn.snp.makeConstraints { make in
                    make.bottom.size.equalTo(cancelBtn)
                    make.right.equalTo(bgView).offset(KRatio(-20))
                }
            }
        }
    }
    
    extension FZAlertView: UITextViewDelegate {
        //对link富文本点击进行处理
        public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
            KLog("scheme = \(URL.scheme?.description) --- range = \(characterRange.description) --- inter = \(interaction)")
            for (index, model) in self.attributedArr!.enumerated() {
                if URL.absoluteString.contains(model.linkStr) {
                    //如果url包含model中的linkUrl,那么说明点击的是该link跳转,那么将index回传回去
                    if self.strCallBlock != nil {
                        self.strCallBlock!(index, model.linkStr)
                    }
                    return false
                }
            }
            return true
        }
    }
    
    extension FZAlertView {
        //获取富文本
        private func getContentTextViewAttributedText(message: String) -> NSAttributedString {
            let attrStr = NSMutableAttributedString.init(string: message)
            attrStr.addAttribute(NSAttributedString.Key.font, value: KFont(CGFloat(KRatio(15))), range: NSRange.init(location: 0, length: message.count))
            if self.attributedArr!.count > 0 {
                for model in attributedArr! {
                    //根据数组添加字体、颜色、link富文本
                    //跳转链接如果不是http或https链接跳转,那么就在后面追加://
                    attrStr.addAttributes([NSAttributedString.Key.font: KFont(CGFloat(KRatio(16))), NSAttributedString.Key.foregroundColor: model.linkColor, NSAttributedString.Key.link: model.linkStr.contains("http") ? model.linkStr : model.linkStr+"://"], range: model.linkRange)
                }
            }
            return attrStr
        }
    }
    
    //MARK: FZAlertViewModel
    @objcMembers
    open class FZAlertViewModel: NSObject {
        public let linkStr: String         //富文本link点击后跳转的urlStr
        public let linkRange: NSRange      //富文本可跳转的range范围
        public let linkColor: UIColor
        
        public init(linkStr: String, linkRange: NSRange, linkColor: UIColor = UIColor.hex("#333333")) {
            self.linkStr = linkStr
            self.linkRange = linkRange
            self.linkColor = linkColor
        }
    }
    

    相关文章

      网友评论

          本文标题:UITextView link跳转

          本文链接:https://www.haomeiwen.com/subject/oheawrtx.html