123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- //
- // UICollectionView+Ext.swift
- // PQSpeed
- //
- // Created by SanW on 2020/6/6.
- // Copyright © 2020 BytesFlow. All rights reserved.
- //
- import KingfisherWebP
- import UIKit
- // MARK: - UIView的分类扩展
- /// UIView的分类扩展
- extension UIView {
- public func addCorner(roundingCorners: UIRectCorner = .allCorners, corner: CGFloat = cDefaultMargin) {
- if roundingCorners == .allCorners {
- layer.cornerRadius = corner
- layer.masksToBounds = true
- } else {
- let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: roundingCorners, cornerRadii: CGSize(width: corner, height: corner))
- let cornerLayer = CAShapeLayer()
- cornerLayer.frame = bounds
- cornerLayer.path = path.cgPath
- layer.mask = cornerLayer
- }
- }
- /// 添加阴影
- /// - Parameters:
- /// - color: <#color description#>
- /// - offset: <#offset description#>
- /// - Returns: <#description#>
- public func addShadowLayer(isAll: Bool = false, color: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5), offset: CGSize = CGSize(width: 1, height: 1)) {
- layer.shadowColor = color.cgColor
- layer.shadowOffset = offset
- layer.shadowRadius = 0.5
- layer.shadowOpacity = 1.0
- if isAll {
- layer.shadowColor = color.cgColor
- layer.shadowOffset = CGSize.zero
- // 设置偏移量为0,四周都有阴影
- layer.shadowRadius = 0.5 // 阴影半径
- layer.shadowOpacity = 0.3 // 阴影透明度
- layer.masksToBounds = false
- layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius).cgPath
- }
- }
- /// 添加虚线条
- public func addBorderToLayer(frame: CGRect? = nil) {
- // 线条颜色
- let borderLayer: CAShapeLayer = CAShapeLayer()
- borderLayer.strokeColor = UIColor.hexColor(hexadecimal: "#FFFFFF").cgColor
- borderLayer.fillColor = nil
- borderLayer.path = UIBezierPath(rect: frame == nil ? bounds : frame!).cgPath
- borderLayer.frame = bounds
- borderLayer.lineWidth = 2.0
- borderLayer.lineCap = .round
- // 第一位是 线条长度 第二位是间距 nil时为实线
- borderLayer.lineDashPattern = [5, 5]
- layer.addSublayer(borderLayer)
- }
- public func animateZoom() {
- transform = CGAffineTransform(scaleX: 0.4, y: 0.4)
- UIView.animate(withDuration: 0.5, animations: {
- self.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
- }) { _ in
- UIView.animate(withDuration: 0.5, animations: {
- self.transform = .identity
- }) { _ in
- }
- }
- }
- /// 添加抖动功能
- /// - Parameters:
- /// - fromValue: <#fromValue description#>
- /// - toValue: <#toValue description#>
- /// - duration: <#duration description#>
- /// - repeatCount: <#repeatCount description#>
- /// - Returns: <#description#>
- public func shakeAnimation(_ fromValue: Float, _ toValue: Float, _ duration: Float, _: Float) {
- layer.removeAllAnimations()
- let shake = CABasicAnimation(keyPath: "transform.rotation.z")
- shake.fromValue = fromValue
- shake.toValue = toValue
- shake.duration = CFTimeInterval(duration)
- shake.autoreverses = true
- shake.repeatCount = Float(CGFloat.greatestFiniteMagnitude)
- shake.isRemovedOnCompletion = false
- layer.add(shake, forKey: "imageView")
- // 增加锚点
- layer.anchorPoint = CGPoint(x: 0.5, y: 1)
- }
- /// 添加心跳动画
- /// - Parameters:
- /// - duration: <#duration description#>
- /// - isRepeat: <#isRepeat description#>
- /// - multiple: <#multiple description#>
- /// - Returns: <#description#>
- public func heartbeatAnimate(duration: TimeInterval, isRepeat: Bool, multiple: CGFloat) {
- UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = CGAffineTransform(scaleX: 1.0 + multiple, y: 1.0 + multiple)
- }) { _ in
- UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = .identity
- }) { _ in
- UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = CGAffineTransform(scaleX: 1.0 + multiple * 2, y: 1.0 + multiple * 2)
- }) { _ in
- UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = .identity
- }) { _ in
- if isRepeat {
- DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.3) {
- self.heartbeatAnimate(duration: duration, isRepeat: isRepeat, multiple: multiple)
- }
- }
- }
- }
- }
- }
- }
- /// 活动心跳动画
- /// - Returns: <#description#>
- public func activityHeartbeatAnimate() {
- layer.removeAllAnimations()
- UIView.animateKeyframes(withDuration: 0.45, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
- }) { _ in
- UIView.animateKeyframes(withDuration: 0.45, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = .identity
- }) { _ in
- self.activityHeartbeatAnimate()
- }
- }
- }
- /// 活动心跳动画
- /// - Returns: <#description#>
- public func heartbeatAnimate() {
- layer.removeAllAnimations()
- UIView.animateKeyframes(withDuration: 1, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
- }) { isFinished in
- UIView.animateKeyframes(withDuration: 1, delay: 0, options: .allowUserInteraction, animations: {
- self.transform = .identity
- }) { isFinished in
- if isFinished {
- self.heartbeatAnimate()
- }
- }
- }
- }
- public func addScaleBasicAnimation() {
- let animation = CABasicAnimation(keyPath: "transform.scale")
- animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
- animation.duration = 0.5
- animation.repeatCount = 1000
- animation.autoreverses = true
- animation.fromValue = 0.8
- animation.toValue = 1.1
- layer.add(animation, forKey: nil)
- }
- public func addScaleYBasicAnimation() {
- let animation = CAKeyframeAnimation(keyPath: "transform.translation.y")
- animation.duration = 0.5
- animation.repeatCount = 100
- animation.isRemovedOnCompletion = true
- // animation.
- animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
- layer.add(animation, forKey: nil)
- // CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"];
- // CGFloat duration = 1.f;
- // CGFloat height = 7.f;
- // CGFloat currentY = self.animationView.transform.ty;
- // animation.duration = duration;
- // animation.values = @[@(currentY),@(currentY - height/4),@(currentY - height/4*2),@(currentY - height/4*3),@(currentY - height),@(currentY - height/ 4*3),@(currentY - height/4*2),@(currentY - height/4),@(currentY)];
- // animation.keyTimes = @[ @(0), @(0.025), @(0.085), @(0.2), @(0.5), @(0.8), @(0.915), @(0.975), @(1) ];
- // animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
- // animation.repeatCount = HUGE_VALF;
- // [self.animationView.layer addAnimation:animation forKey:@"kViewShakerAnimationKey"];
- // }
- }
- /// 将view生成一张图片
- /// - Returns: <#description#>
- public func graphicsGetImage() -> UIImage? {
- UIGraphicsBeginImageContextWithOptions(frame.size, true, 0.0)
- layer.render(in: UIGraphicsGetCurrentContext()!)
- let newImage = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
- return newImage
- }
- /// 动画显示View
- /// - Returns: <#description#>
- public func showViewAnimate(duration: TimeInterval = 0.3, completion: ((Bool) -> Void)? = nil) {
- UIView.animate(withDuration: duration, animations: { [weak self] in
- self?.frame = CGRect(x: 0, y: cScreenHeigth - self!.frame.height, width: self!.frame.width, height: self!.frame.height)
- }) { isFinished in
- if completion != nil {
- completion!(isFinished)
- }
- }
- }
- /// 动画隐藏view
- /// - Returns: <#description#>
- public func dismissViewAnimate(duration: TimeInterval = 0.3, completion: ((Bool) -> Void)? = nil) {
- UIView.animate(withDuration: duration, animations: { [weak self] in
- self?.frame = CGRect(x: 0, y: cScreenHeigth, width: self!.frame.width, height: self!.frame.height)
- }) { isFinished in
- if completion != nil {
- completion!(isFinished)
- }
- }
- }
- /// add by ak 添加虚线框
- /// - Parameter color: 框色
- /// - Parameter lineWidth: 框宽
- public func addBorderToLayer(color: CGColor, lineWidth: CGFloat) {
- let border = CAShapeLayer()
- // 线条颜色
- border.strokeColor = color
- border.fillColor = nil
- border.path = UIBezierPath(rect: bounds).cgPath
- border.frame = bounds
- border.lineWidth = lineWidth
- border.lineCap = .square
- // 第一位是 线条长度 第二位是间距 nil时为实线
- border.lineDashPattern = [9, 4]
- layer.addSublayer(border)
- }
- }
- // MARK: - UICollectionView的分类扩展
- /// UICollectionView的分类扩展
- extension UICollectionView {
- /// 获取当前cell
- /// - Returns: <#description#>
- public func visibleCell() -> UICollectionViewCell? {
- let visibleRect = CGRect(origin: contentOffset, size: bounds.size)
- let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
- guard let visibleIndexPath = indexPathForItem(at: visiblePoint) else { return nil }
- return cellForItem(at: visibleIndexPath)
- }
- /// 添加刷新组件
- /// - Parameters:
- /// - scroller: <#scroller description#>
- /// - type: 1-头部跟尾部 2-头部 3-尾部
- public func addRefreshView(type: REFRESH_TYPE = .REFRESH_TYPE_ALL, refreshHandle: ((_ isHeader: Bool) -> Void)?) {
- if type == .REFRESH_TYPE_ALL || type == .REFRESH_TYPE_HEADER {
- let header = MJRefreshNormalHeader.init {
- if refreshHandle != nil {
- refreshHandle!(true)
- }
- }
- header.setTitle("下拉刷新", for: .willRefresh)
- header.setTitle("正在刷新...", for: .refreshing)
- header.setTitle("松开刷新", for: .pulling)
- header.setTitle("下拉刷新", for: .idle)
- header.lastUpdatedTimeLabel?.isHidden = true
- mj_header = header
- }
- if type == .REFRESH_TYPE_ALL || type == .REFRESH_TYPE_FOOTER {
- // MJRefreshBackNormalFooter 不会附在上面
- // MJRefreshAutoFooter 不会便宜
- let footer = MJRefreshBackNormalFooter.init {
- if refreshHandle != nil {
- refreshHandle!(false)
- }
- }
- footer.setTitle("暂时没有更多了", for: .noMoreData)
- footer.setTitle("精彩内容正在加载中...", for: .refreshing)
- mj_footer = footer
- }
- }
- public func indexPathsForElements(in rect: CGRect) -> [IndexPath] {
- let allLayoutAttributes = collectionViewLayout.layoutAttributesForElements(in: rect)!
- return allLayoutAttributes.map { $0.indexPath }
- }
- }
- // MARK: - UITabBar的分类扩展
- /// UITabBar的分类扩展
- extension UITabBar {
- /// 展示小红点
- /// - Parameter index: <#index description#>
- /// - Returns: <#description#>
- public func showPoint(index: Int) {
- let pointW: CGFloat = 8
- let pointView = UIView()
- pointView.tag = 11111 + index
- pointView.layer.cornerRadius = pointW / 2
- pointView.backgroundColor = UIColor.hexColor(hexadecimal: "#EE0051")
- let percentX: CGFloat = CGFloat(Double(index) + 0.7) / CGFloat(items?.count ?? 1)
- let pointX = ceil(percentX * frame.width)
- let pointY = ceil(0.1 * frame.height)
- pointView.frame = CGRect(x: pointX, y: pointY, width: pointW, height: pointW)
- addSubview(pointView)
- }
- /// 移除小红点
- /// - Parameter index: <#index description#>
- /// - Returns: <#description#>
- public func removePoint(index: Int) {
- for item in subviews {
- if item.tag == 11111 + index {
- item.removeFromSuperview()
- }
- }
- }
- /// 展示创作视频引导
- /// - Parameter index: <#index description#>
- /// - Returns: <#description#>
- public func showVideoMakeRemindView() {
- let isOldUploadClick: String? = getUserDefaults(key: cIsUploadClick) as? String
- let isUploadClick: String? = getUserDefaultsForJson(key: cIsUploadClick) as? String
- let isVerticalSlip: String? = getUserDefaults(key: cIsVerticalSlip) as? String
- if isOldUploadClick == nil && isVerticalSlip != nil && isVerticalSlip == "1", isUploadClick == nil || isUploadClick?.count ?? 0 <= 0 || isUploadClick != "2" {
- let width: CGFloat = 275 // 275
- let height: CGFloat = 107 // 107
- let videoMakeRemindBtn = UIButton(frame: CGRect(x: 0, y: -height + 5, width: width, height: height))
- videoMakeRemindBtn.tag = cVideoMakeRemindTag
- videoMakeRemindBtn.setBackgroundImage(UIImage(named: "videomk_guide"), for: .normal)
- addSubview(videoMakeRemindBtn)
- videoMakeRemindBtn.center.x = center.x
- videoMakeRemindBtn.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
- videoMakeRemindBtn.addScaleBasicAnimation()
- if isUploadClick == "1" {
- saveUserDefaultsToJson(key: cIsUploadClick, value: "2")
- } else {
- saveUserDefaultsToJson(key: cIsUploadClick, value: "1")
- }
- DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) { [weak self] in
- self?.removeVideoMakeRemindView()
- }
- }
- }
- @objc public func dismiss() {
-
- }
- /// 移除创作视频引导
- /// - Returns: <#description#>
- public func removeVideoMakeRemindView() {
- viewWithTag(cVideoMakeRemindTag)?.removeFromSuperview()
- }
- }
- // MARK: - UILabel的分类扩展
- /// UILabel的分类扩展
- extension UILabel {
- var isTruncated: Bool {
- guard let labelText = text else {
- return false
- }
- // 计算理论上显示所有文字需要的尺寸
- let rect = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
- let labelTextSize = (labelText as NSString)
- .boundingRect(with: rect, options: .usesLineFragmentOrigin,
- attributes: [NSAttributedString.Key.font: font as Any], context: nil)
- // 计算理论上需要的行数
- let labelTextLines = Int(ceil(CGFloat(labelTextSize.height) / font.lineHeight))
- // 实际可显示的行数
- var labelShowLines = Int(floor(CGFloat(bounds.size.height) / font.lineHeight))
- if numberOfLines != 0 {
- labelShowLines = min(labelShowLines, numberOfLines)
- }
- // 比较两个行数来判断是否需要截断
- return labelTextLines > labelShowLines
- }
- /// 添加阴影
- /// - Parameters:
- /// - color: <#color description#>
- /// - offset: <#offset description#>
- /// - Returns: <#description#>
- public func addShadow(color: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5), offset: CGSize = CGSize(width: 1, height: 1)) {
- shadowColor = color
- shadowOffset = offset
- }
- }
- extension UIImageView {
- /// imageView加载网络图片
- /// - Parameters:
- /// - url: 网络url
- public func setNetImage(url: String?, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
- if url == nil || (url?.count ?? 0) <= 0 {
- BFLog(message: "设置按钮网络图片地址为空")
- return
- }
- kf.setImage(with: URL(string: url!), placeholder: placeholder, options: url?.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
- }) { _ in
- }
- }
- /// 展示加载中动画
- /// - Returns: <#description#>
- public func showLoadingAnimation(duration: Double = 1) {
- let rotationAnim = CABasicAnimation(keyPath: "transform.rotation.z")
- rotationAnim.fromValue = 0
- rotationAnim.toValue = Double.pi * 2
- rotationAnim.repeatCount = MAXFLOAT
- rotationAnim.duration = duration
- rotationAnim.isRemovedOnCompletion = false
- layer.add(rotationAnim, forKey: nil)
- }
- /// 播放GIF
- /// - Parameters:
- /// - data : 图片二进制数据
- /// - images: 图片
- /// - repeatCount: 循环次数
- /// - duration: 时长
- /// - Returns: <#description#>
- public func displayGIF(data: Data? = nil, images: [UIImage]? = nil, repeatCount: Int = Int.max, duration: Double = 1) {
- if images != nil, (images?.count ?? 0) > 0, !isAnimating {
- layer.removeAllAnimations()
- stopAnimating()
- animationImages = images
- animationDuration = duration
- animationRepeatCount = repeatCount
- startAnimating()
- } else if images == nil && data != nil {
- PQPHAssetVideoParaseUtil.parasGIFImage(data: data!) { [weak self] _, images, duration in
- if images != nil, (images?.count ?? 0) > 0 {
- self?.displayGIF(images: images!, repeatCount: repeatCount, duration: duration ?? 1)
- }
- }
- }
- }
-
- /// 移除
- public func removePlayGIF() {
- layer.removeAllAnimations()
- stopAnimating()
- }
- }
- extension UIButton {
- /// UIButton加载网络图片
- /// - Parameters:
- /// - url: 网络url
- public func setNetImage(url: String?, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
- if url == nil || (url?.count ?? 0) <= 0 {
- BFLog(message: "设置按钮网络图片地址为空")
- return
- }
- kf.setImage(with: URL(string: url!), for: .normal, placeholder: placeholder, options: url?.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
- }) { _ in
- }
- }
- /// UIButton加载网络背景图片
- /// - Parameters:
- /// - url: 网络url
- public func setNetBackgroundImage(url: String, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
- kf.setBackgroundImage(with: URL(string: url), for: .normal, placeholder: placeholder, options: url.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
- }) { _ in
- }
- }
- }
|