swift---自用圓形頭像控件(繼承UIControl)

此控件搭配Kingfisher使用,你也可以自己替換成SD求厕。繼承UIControl端衰,可以不用再去加手勢叠洗,直接調(diào)用UIControl 的addTarget...方法實現(xiàn)點擊事件

直接上代碼

class ImageView: UIControl {
    
    
    /// 圖像類型
    ///
    /// - none: 矩形直角
    /// - round: 圓形
    /// - radius: 圓角
    enum AvatarType {
        case none, round, radius(CGFloat)
    }
    
    var image: UIImage? {
        didSet {
            if image != oldValue {
                setNeedsDisplay()
            }
        }
    }
    
    var defaultImage: UIImage? {
        didSet {
            if defaultImage != oldValue {
                setNeedsDisplay()
            }
        }
    }
    
    var highlightedImage: UIImage? {
        didSet {
            if highlightedImage != oldValue {
                setNeedsDisplay()
            }
        }
    }
    
    override var isHighlighted: Bool {
        didSet {
            setNeedsDisplay()
        }
    }
    
    override var isSelected: Bool {
        didSet {
            setNeedsDisplay()
        }
    }

    
    init(frame: CGRect, type: AvatarType = .round) {
        self.type = type
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        self.type = .none
        super.init(coder: aDecoder)
        setup()
    }
    
    private let type: AvatarType
    private var cornerRadius: CGFloat = 0
    
    override func draw(_ rect: CGRect) {
        guard bounds.width > 0, bounds.height > 0 else {
            return
        }
        
        let context = UIGraphicsGetCurrentContext()
        let img = UIImageView()
        context?.saveGState()
        defer {
            context?.restoreGState()
        }
        
        if cornerRadius > 0 {
            // 防止中途改變size
            if case .round = type {
                cornerRadius = bounds.size.width * 0.5
            }
            context?.addPath(UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath)
            context?.clip()
        }
        
        if let image = showImage(), image.size.height > 0, image.size.width > 0, let cgImage = image.cgImage {
            //ScaleAspectFill模式
            let newCenter = CGPoint(x: bounds.width * 0.5, y: bounds.height * 0.5)
            //哪個小按哪個縮
            let scaleW = image.size.width / bounds.width
            let scaleH = image.size.height / bounds.height
            let scale = min(scaleW, scaleH)
            
            let newSize = CGSize(width: image.size.width / scale, height: image.size.height / scale)
            
            let drawRect = CGRect(x: newCenter.x - newSize.width / 2, y: newCenter.y - newSize.height / 2, width: newSize.width, height: newSize.height)
            context?.draw(cgImage, in: drawRect)
        }
    }

}

extension ImageView {
    fileprivate func setup() {
        backgroundColor = UIColor.clear
        layer.isGeometryFlipped = true
        switch type {
        case .none: cornerRadius = 0.0
        case .round: cornerRadius = bounds.size.width * 0.5
        case .radius(let radius): cornerRadius = radius
        }
    }
    
    fileprivate func showImage() -> UIImage? {
        let current = (state == .highlighted || state == .selected)
        let img = image ?? defaultImage
        return current ? (highlightedImage != nil) ? highlightedImage : img : img
    }
}

下面是控件調(diào)用url甘改,網(wǎng)絡(luò)請求賦值的方法

extension ImageView {
    
    func image(for url: String?) {
        guard let url = url else { return }
        let Url = URL(string: url)
        image(for: Url)
    }
    
    @discardableResult
    func image(for resource: Resource?,
               placeholder: UIImage? = nil,
               options: KingfisherOptionsInfo? = nil,
               progressBlock: DownloadProgressBlock? = nil,
               completionHandler: CompletionHandler? = nil) -> RetrieveImageTask {
        guard let resource = resource else {
            image = placeholder
            setWebURL(nil)
            completionHandler?(nil, nil, .none, nil)
            return .empty
        }
        
        var options = KingfisherManager.shared.defaultOptions + (options ?? [])
        
        if !options.keepCurrentImageWhileLoading {
            image = placeholder
        }
        
        setWebURL(resource.downloadURL)
        
        if shouldPreloadAllAnimation()  {
            options.append(.preloadAllAnimationData)
        }
        
        let task = KingfisherManager.shared.retrieveImage(with: resource, options: options, progressBlock: { receivedSize, totalSize in
            guard resource.downloadURL == self.webURL else { return }
            if let progressBlock = progressBlock {
                progressBlock(receivedSize, totalSize)
            }
        }) { [weak self] image, error, cacheType, imageURL in
            DispatchQueue.main.safeAsync {
                guard let strongSelf = self, imageURL == strongSelf.webURL else {
                    completionHandler?(image, error, cacheType, imageURL)
                    return
                }
                
                self?.setImageTask(nil)
                guard let img = image else {
                    completionHandler?(nil, error, cacheType, imageURL)
                    return
                }
                
                strongSelf.image = img
                completionHandler?(img, error, cacheType, imageURL)
                
            }
        }
        
        setImageTask(task)
        
        return task
    }
}

取消網(wǎng)絡(luò)請求的方法

func cancelDownloadTask() {
        imageTask?.cancel()
    }

使用runtime在網(wǎng)絡(luò)請求的時候為控件的屬性賦值

private var lastURLKey: Void?
private var imageTaskKey: Void?
extension ImageView {
    var webURL: URL? {
        return objc_getAssociatedObject(self, &lastURLKey) as? URL
    }
    fileprivate func setWebURL(_ url: URL?) {
        objc_setAssociatedObject(self, &lastURLKey, url, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    
    fileprivate var imageTask: RetrieveImageTask? {
        return objc_getAssociatedObject(self, &imageTaskKey) as? RetrieveImageTask
    }
    
    fileprivate func setImageTask(_ task: RetrieveImageTask?) {
        objc_setAssociatedObject(self, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    fileprivate func shouldPreloadAllAnimation() -> Bool { return true }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旅东,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子十艾,更是在濱河造成了極大的恐慌抵代,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忘嫉,死亡現(xiàn)場離奇詭異荤牍,居然都是意外死亡,警方通過查閱死者的電腦和手機庆冕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門康吵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人访递,你說我怎么就攤上這事晦嵌。” “怎么了拷姿?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵惭载,是天一觀的道長。 經(jīng)常有香客問我响巢,道長描滔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任踪古,我火速辦了婚禮含长,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伏穆。我一直安慰自己拘泞,他們只是感情好,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布蜈出。 她就那樣靜靜地躺著田弥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铡原。 梳的紋絲不亂的頭發(fā)上偷厦,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天,我揣著相機與錄音燕刻,去河邊找鬼只泼。 笑死,一個胖子當著我的面吹牛卵洗,可吹牛的內(nèi)容都是我干的请唱。 我是一名探鬼主播弥咪,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼十绑!你這毒婦竟也來了聚至?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤本橙,失蹤者是張志新(化名)和其女友劉穎扳躬,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甚亭,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡贷币,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亏狰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片役纹。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖暇唾,靈堂內(nèi)的尸體忽然破棺而出促脉,到底是詐尸還是另有隱情,我是刑警寧澤信不,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布嘲叔,位于F島的核電站,受9級特大地震影響抽活,放射性物質(zhì)發(fā)生泄漏硫戈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一下硕、第九天 我趴在偏房一處隱蔽的房頂上張望丁逝。 院中可真熱鬧,春花似錦梭姓、人聲如沸霜幼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽罪既。三九已至,卻和暖如春铡恕,著一層夾襖步出監(jiān)牢的瞬間琢感,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工探熔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留驹针,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓诀艰,卻偏偏與公主長得像柬甥,于是被迫代替她去往敵國和親饮六。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容