Ver Fonte

做了一些改动

100Years há 2 meses atrás
pai
commit
b769a1005a

+ 2 - 2
TSSmalCoacopods/Classes/BaseClass/TSBaseCollectionCell.swift

@@ -46,7 +46,7 @@ open class TSBaseCollectionCell: UICollectionViewCell,TSComponentView  {
     }
     
     deinit {
-        debugPrint("<---deinit \(String(describing: self))")
+//        debugPrint("<---deinit \(String(describing: self))")
     }
     
     public var cellIndexPath:IndexPath?{
@@ -115,7 +115,7 @@ open class TSBaseCollectionnReusableView : UICollectionReusableView ,TSComponent
     
     
     deinit {
-        debugPrint("<---deinit \(String(describing: self))")
+//        debugPrint("<---deinit \(String(describing: self))")
     }
     
 }

+ 1 - 1
TSSmalCoacopods/Classes/BaseClass/TSBaseTabViewCell.swift

@@ -35,6 +35,6 @@ open class TSBaseTabViewCell: UITableViewCell {
     }
     
     deinit {
-        debugPrint("<---deinit \(String(describing: self))")
+//        debugPrint("<---deinit \(String(describing: self))")
     }
 }

+ 3 - 3
TSSmalCoacopods/Classes/Config/TSConfig.swift

@@ -7,9 +7,9 @@
 
 public let TSConfigShared = TSConfig.shared
 open class TSConfig: NSObject {
-    static var shared = TSConfig()
+    public static var shared = TSConfig()
     
-    static let appLanguage: String = {
+    public static let appLanguage: String = {
         let systemLanguages = UserDefaults.standard.value(forKey: "AppleLanguages")
         var currentLanguage: String?
         if let arr = systemLanguages as? [String] {
@@ -21,7 +21,7 @@ open class TSConfig: NSObject {
         return currentLanguage ?? ""
     }()
     
-    static let appLanguageShort: String? = {
+    public static let appLanguageShort: String? = {
         let currentLanguage = Bundle.main.preferredLocalizations.first
         if let str = currentLanguage?.components(separatedBy: "-").first,
            str.count >= 2 {

+ 4 - 0
TSSmalCoacopods/Classes/Ex/UIImageView+Ex.swift

@@ -184,6 +184,10 @@ public extension UIImageView {
 
 public extension UIImageView {
 
+    static func retrieveImageInMemoryCache(urlString: String) -> UIImage? {
+        return ImageCache.default.retrieveImageInMemoryCache(forKey: urlString)
+    }
+    
     static func downloadImageWithProgress(
         urlString: String,
         progressHandler: ((Float) -> Void)? = nil,

+ 4 - 4
TSSmalCoacopods/Classes/GlobalImports/GlobalImports.swift

@@ -97,16 +97,16 @@ public func kGetUIH(designSize:CGSize,currentW:CGFloat) -> CGFloat {
     
 
 public func debugPrint<T>(_ messsage: T, file: String = #file, funcName: String = #function, lineNum: Int = #line) {
-    #if DEBUG
+//    #if DEBUG
     let fileName = (file as NSString).lastPathComponent
     print(Date.hmsString + " \(fileName) (\(funcName)): [\(lineNum)]- \(messsage)")
-    #endif
+//    #endif
 }
 
 public func dePrint<T>(_ messsage: T) {
-    #if DEBUG
+//    #if DEBUG
     print(Date.hmsString + " \(messsage)")
-    #endif
+//    #endif
 }
 
 public func className(from object: Any) -> String {

+ 15 - 0
TSSmalCoacopods/Classes/Tool/TSCommonTool/TSCommonTool.swift

@@ -174,3 +174,18 @@ public func kCalculateScaledSize(containerSize: CGSize, subviewSize: CGSize, con
         return subviewSize
     }
 }
+
+
+public func kGetCollectionViewCellSize(sectionInset:UIEdgeInsets,
+               itemSpacing:CGFloat,
+               originalSize:CGSize,
+               cellRowNum:Int)->CGSize{
+    let widthReduction:CGFloat = 1.0
+    let originalScale = originalSize.width/originalSize.height
+    var w = k_ScreenWidth-sectionInset.left-sectionInset.right-widthReduction
+    w = w - itemSpacing * CGFloat((cellRowNum-1))
+    w = w/CGFloat(cellRowNum)
+    let h = w/originalScale
+    let cellSize = CGSizeMake(w, h)
+    return cellSize
+}

+ 21 - 6
TSSmalCoacopods/Classes/View/TSReusableCollectionView/TSSimpleCollectionView.swift

@@ -10,7 +10,13 @@ import UIKit
 public protocol TSSimpleConfigurableView {
     var data:Any? { get set }
     var delegate:TSSimpleCollectionViewDelegate? { get set }
-    var indexPath:IndexPath? { get set }
+    var indexPath:IndexPath { get set }
+}
+
+public extension TSSimpleConfigurableView {
+    func actionCustom(custom:String){
+        delegate?.collectionView(didTrigger: TSSimpleCellEvent(action: .custom(custom), indexPath: indexPath, data: data))
+    }
 }
 
 // 单元格事件类型
@@ -70,6 +76,8 @@ open class TSSimpleCollectionView: UIView {
         cv.backgroundColor = .clear
         cv.delegate = self
         cv.dataSource = self
+        cv.showsHorizontalScrollIndicator = false
+        cv.showsVerticalScrollIndicator = false
         return cv
     }()
     
@@ -78,6 +86,13 @@ open class TSSimpleCollectionView: UIView {
     
     public var cellTypes: [String: (UIView & TSSimpleConfigurableView).Type] = [:]
     public var cellIdentifierForItem: ((Any) -> String)?
+    
+    public var headerTypes: [String: (UIView & TSSimpleConfigurableView).Type] = [:]
+    public var headerIdentifierForItem: ((Any) -> String)?
+    
+    public var bottomTypes: [String: (UIView & TSSimpleConfigurableView).Type] = [:]
+    public var bottomIdentifierForItem: ((Any) -> String)?
+    
     // MARK: - Initialization
     override init(frame: CGRect) {
         super.init(frame: frame)
@@ -107,12 +122,12 @@ open class TSSimpleCollectionView: UIView {
     }
     
     public func registerSectionHeader<Cell: UIView & TSSimpleConfigurableView>(_ cellType: Cell.Type, identifier: String) {
-        cellTypes[identifier] = cellType
+        headerTypes[identifier] = cellType
         collectionView.register(cellType, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: identifier)
     }
     
     public func registerSectionFooter<Cell: UIView & TSSimpleConfigurableView>(_ cellType: Cell.Type, identifier: String) {
-        cellTypes[identifier] = cellType
+        bottomTypes[identifier] = cellType
         collectionView.register(cellType, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: identifier)
     }
     
@@ -169,14 +184,14 @@ extension TSSimpleCollectionView: UICollectionViewDataSource, UICollectionViewDe
     
     public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
         let data = sections[indexPath.section]
-        let identifier = cellIdentifierForItem?(data) ?? String(describing: type(of: data))
+        let identifier = headerIdentifierForItem?(data) ?? String(describing: type(of: data))
         
-        guard let cellType = cellTypes[identifier] else {
+        guard let headerType = headerTypes[identifier] else {
             fatalError("未注册对应数据类型的区间头尾: \(identifier)")
         }
         
         let reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: identifier, for: indexPath)
-        if var configurableCell = reusableView as? (UICollectionViewCell & TSSimpleConfigurableView) {
+        if var configurableCell = reusableView as? TSSimpleConfigurableView {
             configurableCell.data = data
             configurableCell.delegate = delegate
             configurableCell.indexPath = indexPath

+ 9 - 5
TSSmalCoacopods/Classes/View/TSSaveSuccessTool/TSSaveSuccessTool.swift

@@ -27,7 +27,7 @@ open class TSSaveSuccessTool {
     
     private lazy var viewButton:UIView = {
         let color = "4FEA9D".uiColor
-        let viewButton = UIButton.createButton(title: "View".localized ,backgroundColor: color.withAlphaComponent(0.1),font: UIFont.font(size: 14),titleColor: color,corner: 14) { [weak self]  in
+        let viewButton = UIButton.createButton(title: "View".localized ,backgroundColor: color.withAlphaComponent(0.1),font: UIFont.font(size: 12),titleColor: color,corner: 14) { [weak self]  in
             guard let self = self else { return }
             if let clickViewHandle = clickViewHandle {
                 clickViewHandle()
@@ -40,6 +40,7 @@ open class TSSaveSuccessTool {
                 }
             }
         }
+        viewButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
         return viewButton
     }()
     
@@ -76,7 +77,7 @@ open class TSSaveSuccessTool {
         view.addSubview(viewButton)
         view.addSubview(textLabel)
         viewButton.snp.makeConstraints { make in
-            make.width.equalTo(65)
+            make.width.equalTo(viewButton.intrinsicContentSize.width)
             make.height.equalTo(28)
             make.trailing.equalTo(-8)
             make.centerY.equalToSuperview()
@@ -84,7 +85,7 @@ open class TSSaveSuccessTool {
     
         textLabel.snp.makeConstraints { make in
             make.leading.equalTo(iconView.snp.trailing).offset(8)
-            make.trailing.equalTo(viewButton.snp.leading).offset(-4)
+            make.trailing.equalTo(viewButton.snp.leading).offset(-8)
             make.centerY.equalToSuperview()
         }
 
@@ -94,7 +95,9 @@ open class TSSaveSuccessTool {
     
     
     public func getBottom(topY:CGFloat)->CGFloat{
-        return -(k_ScreenHeight - 48 - topY)
+        let bottom = -(k_ScreenHeight - 48 - topY)
+        debugPrint("bottom=\(bottom)")
+        return bottom
     }
     
     public func show(atView:UIView,text:String = "Save Successfully".localized,deadline:Double = 2.0,bottom:CGFloat = -112,showViewBtn:Bool = true,clickViewHandle:(()->Void)? = nil) {
@@ -104,7 +107,8 @@ open class TSSaveSuccessTool {
             self.viewButton.isHidden = !showViewBtn
             atView.addSubview(self.saveSuccessBg)
             self.saveSuccessBg.snp.remakeConstraints { make in
-                make.width.equalTo(288)
+                make.width.greaterThanOrEqualTo(288)
+                make.width.lessThanOrEqualTo(k_ScreenWidth-32)
                 make.height.equalTo(48)
                 make.centerX.equalToSuperview()
                 make.bottom.equalTo(bottom)

+ 148 - 0
TSSmalCoacopods/Classes/View/UIStackView/KLMultiScrollContainer.swift

@@ -0,0 +1,148 @@
+//
+//  ScrollContainer.swift
+//  TmpProject
+//
+//  Created by nkl on 2025/4/27.
+//
+
+import Foundation
+import UIKit
+
+open class KLMultiScrollContainer: UIScrollView {
+    
+    public override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        // 在某些情况下,contentView中的点击事件会被panGestureRecognizer拦截,导致不能响应,
+        // 这里设置cancelsTouchesInView表示不拦截
+        // panGestureRecognizer.cancelsTouchesInView = false
+        
+        if #available(iOS 13.0, *) {
+            automaticallyAdjustsScrollIndicatorInsets = false
+        }
+        if #available(iOS 11.0, *) {
+            contentInsetAdjustmentBehavior = .never
+        } else {
+        
+        }
+        delegate = self
+        showsVerticalScrollIndicator = false
+    }
+    
+    required public init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    // scroller最大偏移量(最多只能滑动多少)
+    @objc public var maxContentOffset: CGFloat = 0.0
+    
+    // 是否能滑动/或者正在滑动 超过了 maxContentOffset 就不能滑动
+    @objc public private(set) var isScrolling: Bool = true {
+        didSet {
+            if isScrolling == oldValue {
+                return
+            }
+            updateSubScollViewsState()
+        }
+    }
+    
+    @objc public var subScrollViews: [UIScrollView] = [UIScrollView]() {
+        willSet{
+            subScrollViews.forEach {
+                $0.removeObserver(self, forKeyPath: kObserveKeyPath)
+            }
+        }
+        didSet {
+            subScrollViews.forEach {
+                $0.addObserver(self, forKeyPath: kObserveKeyPath, options: .new, context: nil)
+                $0.scrollsToTop = false
+                if #available(iOS 11.0, *) {
+                    $0.contentInsetAdjustmentBehavior = .never
+                } else {
+                
+                }
+            }
+        }
+    }
+    
+    public func addScrollView(_ scrollView : UIScrollView){
+        if subScrollViews.contains(scrollView) {return}
+        subScrollViews.append(scrollView)
+    }
+        
+    deinit {
+        subScrollViews.forEach { $0.removeObserver(self, forKeyPath: kObserveKeyPath) }
+    }
+}
+
+//MARK: - UIGestureRecognizerDelegate
+
+extension KLMultiScrollContainer : UIGestureRecognizerDelegate {
+    
+    /// 返回true表示可以继续传递触摸事件,这样两个嵌套的scrollView才能同时滚动
+    open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
+        if let view = otherGestureRecognizer.view as? UIScrollView {
+            return subScrollViews.contains(view)
+        }
+        return false
+    }
+}
+
+//MARK: - Observer
+
+extension KLMultiScrollContainer {
+    
+    open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
+        guard let newValue = change?[.newKey] as? CGPoint else {
+            return
+        }
+        
+        guard let scrollView = object as? UIScrollView else {
+            return
+        }
+        
+        // 只有在拖动的时候才考虑设置
+        // 当点击某个单元格,push到另一个页面时,也会触发该监听,
+        // 同时offset被置为0了,导致自动滚到顶部,因此要添加该判断
+        if !scrollView.isDragging {
+            return
+        }
+        
+        if isScrolling && maxContentOffset > contentOffset.y {
+            // 先移除一下监听,contentOffset被设置时也会调用监听,导致重复调用
+            // 虽然可以使用 ‘scrollView.setContentOffset(.zero, animated: false)’ 保证不被重复监听,但是滑动效果不顺畅
+            scrollView.removeObserver(self, forKeyPath: kObserveKeyPath)
+            scrollView.contentOffset = .zero
+            scrollView.addObserver(self, forKeyPath: kObserveKeyPath, options: .new, context: nil)
+            return
+        }
+        if  newValue.y <= 0 {
+            isScrolling = true
+        } else {
+            isScrolling = false
+        }
+        
+    }
+    
+    fileprivate func updateSubScollViewsState() -> Void {
+        subScrollViews.forEach { scrollView in
+            if isScrolling {
+                scrollView.setContentOffset(.zero, animated: false)
+            }
+            scrollView.showsVerticalScrollIndicator = !isScrolling
+        }
+    }
+}
+
+extension KLMultiScrollContainer : UIScrollViewDelegate {
+    
+    open func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        if  (scrollView.contentOffset.y > maxContentOffset) ||
+            (scrollView.contentOffset.y < maxContentOffset && !isScrolling) {
+            scrollView.contentOffset = CGPoint(x: 0, y: maxContentOffset)
+        }
+    }
+}
+
+fileprivate var kObserveKeyPath = "contentOffset"
+fileprivate var kOffsetContext = "content_offset_context"

+ 11 - 3
TSSmalCoacopods/Classes/View/UIStackView/TSCustomStackView.swift

@@ -11,6 +11,11 @@ import SnapKit
 open class TSCustomStackView: UIView {
     // 内部的 UIScrollView 和 UIStackView
     public let scrollView: UIScrollView
+//    public let scrollView: KLMultiScrollContainer
+    
+    
+    
+    
     public let stackView: UIStackView
     
     // 开放的属性,用于设置方向和间距
@@ -40,12 +45,15 @@ open class TSCustomStackView: UIView {
     }
     
     // 初始化方法
-    public init(axis: NSLayoutConstraint.Axis = .vertical, spacing: CGFloat = 0) {
+    public init(axis: NSLayoutConstraint.Axis = .vertical,alignment:UIStackView.Alignment = .leading, spacing: CGFloat = 0) {
         self.scrollView = UIScrollView()
+//        self.scrollView = KLMultiScrollContainer()
+        self.scrollView.showsVerticalScrollIndicator = false
+        self.scrollView.showsHorizontalScrollIndicator = false
         self.stackView = UIStackView()
         self.stackView.axis = axis
         self.stackView.spacing = spacing
-        self.stackView.alignment = .fill
+        self.stackView.alignment = alignment
         self.stackView.distribution = .fill
         super.init(frame: .zero)
         setupUI()
@@ -83,7 +91,7 @@ open class TSCustomStackView: UIView {
     }
     
     // 动态添加子视图的方法
-    public func addSubviewToStack(_ view: UIView,length:CGFloat? = nil,animate:Bool = false) {
+    public func addSubviewToStack(_ view: UIView,length:CGFloat? = nil) {
         stackView.addArrangedSubview(view)
         view.snp.makeConstraints { make in
             if axis == .vertical {