廢話不多說(shuō)姆打,直接上代碼状原,通過(guò)一個(gè)彈窗來(lái)展示效果
import UIKit
import FZBaseKit
import SnapKit
import RxSwift
@objcMembers
/// 新的彈窗alert珍语,支持富文本點(diǎn)擊跳轉(zhuǎn)峻贮,支持左側(cè)取消按鈕,右側(cè)確定按鈕腌紧;支持中間一個(gè)確定按鈕
open class FZAlertView: UIView {
//按鈕點(diǎn)擊回調(diào),取消按鈕false 確認(rèn)按鈕 true
typealias hander = (_ result: Bool)->()
typealias strHander = (_ index: Int, _ linkStr: String)->()
//按鈕點(diǎn)擊回調(diào)屬性
private var callBlock:hander?
//富文本點(diǎn)擊回調(diào)屬性
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 //禁止?jié)L動(dòng)
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
}()
/// 創(chuàng)建alertView
/// - Parameters:
/// - message: 文本信息
/// - sureBtnTitle: 確認(rèn)按鈕標(biāo)題
/// - cancelBtnTitle: 取消按鈕標(biāo)題夜涕,如果無(wú)取消按鈕該值不傳
/// - supperVC: 推出alertview的VC犯犁,如果為空,就通過(guò)KAppwindow彈出
/// - btnActionCallBack: 取消女器、確認(rèn)按鈕點(diǎn)擊回調(diào)
/// - attributedArr: 富文本點(diǎn)擊數(shù)組,數(shù)組內(nèi)部字典組成為酸役,無(wú)富文本點(diǎn)擊可不傳
/// - attributedClickActionCallBack: 富文本點(diǎn)擊回調(diào)
/// - 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構(gòu)建
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)
}
}
//數(shù)據(jù)處理
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)
//按鈕點(diǎn)擊
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)
}
//布局構(gòu)建
private func layoutUI(message: String, cancelTitle: String) {
let btnWidth = KRatio(105)
let btnHeight = KRatio(44)
var contentWidth = KRatio(275)//默認(rèn)高度
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) {
//如果高度過(guò)高,那么設(shè)置最大高度晓避,并且設(shè)置textView可滾動(dòng)
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))
}
//按鈕布局分為取消簇捍、確認(rèn)按鈕和只有確認(rèn)按鈕兩種情況,根據(jù)cancelTitle來(lái)判斷
if cancelTitle.count == 0 {
//隱藏cancelTitle
cancelBtn.isHidden = true
//surebtn據(jù)中
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 {
//對(duì)link富文本點(diǎn)擊進(jìn)行處理
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俏拱,那么說(shuō)明點(diǎn)擊的是該link跳轉(zhuǎn)暑塑,那么將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! {
//根據(jù)數(shù)組添加字體、顏色锅必、link富文本
//跳轉(zhuǎn)鏈接如果不是http或https鏈接跳轉(zhuǎn)事格,那么就在后面追加://
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點(diǎn)擊后跳轉(zhuǎn)的urlStr
public let linkRange: NSRange //富文本可跳轉(zhuǎn)的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
}
}