你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 使用 Swift 構建自定義的ActivityIndicator View

使用 Swift 構建自定義的ActivityIndicator View

編輯:IOS開發基礎

目前在自己的個人項目裡,已經開始使用Swift去編寫代碼。這篇文章把項目中自己設計的一個ActivityIndicator View展示給大家。

在開始之前,我們先看看最終的效果,如下圖:

content-loader.gif

我建議大家下載本文對應在Github分享的完整項目,以便跟著本篇文章來閱讀代碼。

需求分析

我們需要實現一個自定義的和 UIActivityIndicatorView 提供相似功能的一個Loading效果。我們將使用 Core Graphics 來繪制這樣的效果,並讓它動起來。

讓我們先分析一下這個控件的組成,為我們實際編碼提供具體的思路。

首先,這個loading效果圖,是由8個圓弧組成的一個圓。

我們先要會畫圓弧:

360桌面截圖20141211151745.jpg

像這樣畫8個圓弧,圍成一個圓:

360桌面截圖20141211151813.jpg

然後通過重復改變每一個圓弧的顏色,讓它動起來。

我們繼承UIView, 重寫drawRect方法繪制界面,第一步得到當前繪圖的上下文:

let context = UIGraphicsGetCurrentContext()

繪制圓弧

這裡我們使用 UIBezierPath 類去構建路徑,然後通過繪制路徑的方式繪制圓弧。

// 初始化一個 UIBezierPath 實例
let arcPath = UIBezierPath()

// 構建Arc路徑
arcPath.addArcWithCenter(CGPointMake(CGFloat(self.frame.size.width/2), CGFloat(self.frame.size.height/2)), radius: CGFloat(Config.CC_ARC_DRAW_RADIUS), startAngle: CGFloat(DegreesToRadians(startAngle)), endAngle: CGFloat(DegreesToRadians(startAngle + Config.CC_ARC_DRAW_DEGREE)), clockwise: true)

// 把路徑添加到當前繪圖的上下文
CGContextAddPath(context, arcPath.CGPath)

// 設置線段寬度
CGContextSetLineWidth(context, CGFloat(Config.CC_ARC_DRAW_WIDTH))

// 設置線段顏色
CGContextSetStrokeColorWithColor(context, strokeColor)

// 繪制        
CGContextStrokePath(context)

通過如上的方式,我們就可以成功畫出一個圓弧。其中:

func addArcWithCenter(center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)

這個方法構建路徑的解釋是 center 為圓點坐標,radius 為半徑,startAngle 為開始的弧度,endAngle 為結束的弧度,clockwise 表示的是順時針還是逆時針。

繪制8個圓弧

當我們可以成功在繪圖上下文繪制出圓弧時,我們應該開始著手繪制效果圖中的8個圓弧,並讓它在正確的位置,並帶上不同顏色。

這裡是效果圖的一些參數設置,包括半徑,寬度,顏色等信息:

struct Config {
    static let CC_ACTIVITY_INDICATOR_VIEW_WIDTH = 40
    static let CC_ARC_DRAW_PADDING = 3.0
    static let CC_ARC_DRAW_DEGREE = 39.0
    static let CC_ARC_DRAW_WIDTH = 6.0
    static let CC_ARC_DRAW_RADIUS = 10.0
    static let CC_ARC_DRAW_COLORS = [UIColor(red: 242/255.0, green: 242/255.0, blue: 242/255.0, alpha: 1.0).CGColor, UIColor(red: 230/255.0, green: 230/255.0, blue: 230/255.0, alpha: 1.0).CGColor, UIColor(red: 179/255.0, green: 179/255.0, blue: 179/255.0, alpha: 1.0).CGColor, UIColor(red: 128/255.0, green: 128/255.0, blue: 128/255.0, alpha: 1.0).CGColor, UIColor(red: 128/255.0, green: 128/255.0, blue: 128/255.0, alpha: 1.0).CGColor, UIColor(red: 128/255.0, green: 128/255.0, blue: 128/255.0, alpha: 1.0).CGColor, UIColor(red: 128/255.0, green: 128/255.0, blue: 128/255.0, alpha: 1.0).CGColor, UIColor(red: 128/255.0, green: 128/255.0, blue: 128/255.0, alpha: 1.0).CGColor]
    }

我們可以在drawRect方法,循壞繪制8個圓弧,此時完整的代碼看上去像這樣:

override func drawRect(rect: CGRect) {

    let context = UIGraphicsGetCurrentContext()

    var startAngle = Config.CC_ARC_DRAW_PADDING

    for index in 1...8 {
        let arcPath = UIBezierPath()
        arcPath.addArcWithCenter(CGPointMake(CGFloat(self.frame.size.width/2), CGFloat(self.frame.size.height/2)), radius: CGFloat(Config.CC_ARC_DRAW_RADIUS), startAngle: CGFloat(DegreesToRadians(startAngle)), endAngle: CGFloat(DegreesToRadians(startAngle + Config.CC_ARC_DRAW_DEGREE)), clockwise: true)
        CGContextAddPath(context, arcPath.CGPath)
        startAngle += Config.CC_ARC_DRAW_DEGREE + (Config.CC_ARC_DRAW_PADDING * 2)

        CGContextSetLineWidth(context, CGFloat(Config.CC_ARC_DRAW_WIDTH))
        let colorIndex = abs(index - self.animateIndex)
        let strokeColor = Config.CC_ARC_DRAW_COLORS[colorIndex]
        CGContextSetStrokeColorWithColor(context, strokeColor)
        CGContextStrokePath(context)
    }
}

使用for循環繪制8次,產生8個圓弧,並且設置不同的顏色。這裡的self.animateIndex用來跟蹤整個動畫的頭一個顏色最淺圓弧的位置。通過它和當前index的絕對值,獲得當前圓弧應該顯示的顏色。

動起來

在設計一個ActivityIndicator View的時候,我們應該像UIKit提供的 UIActivityIndicatorView 一樣,至少需要實現這三組API:

func startAnimating()
func stopAnimating()
func isAnimating() -> Bool

這裡我們使用一個timer去改變self.animateIndex的值,不斷重畫當前視圖,來產生動畫效果,代碼看起來像這樣:

// 使用該值驅動改變圓弧顏色,產生動畫效果
private var animateIndex: Int = 1

// 動畫的Timer
private var animatedTimer: NSTimer?

// timer響應的事件,在這裡setNeedsDisplay讓UIKit重畫當前視圖,然後不斷改變animateIndex值。
@objc private func animate () {
    if !self.hidden {
        self.setNeedsDisplay()
        self.animateIndex++
        if self.animateIndex > 8 {
            self.animateIndex = 1
        }
    }
}

// 開始動畫
func startAnimating () {

    if self.hidden {
        self.hidden = false
    }

    if let timer = self.animatedTimer {
        timer.fire()
    } else {
        self.animatedTimer = NSTimer(timeInterval: 0.1, target: self, selector: "animate", userInfo: nil, repeats: true)
        NSRunLoop.currentRunLoop().addTimer(self.animatedTimer!, forMode: NSRunLoopCommonModes)
    }
}

這裡使用

init(timeInterval ti: NSTimeInterval, target aTarget: AnyObject, selector aSelector: Selector, userInfo: AnyObject?, repeats yesOrNo: Bool) -> NSTimer

而不是使用

class func scheduledTimerWithTimeInterval(ti: NSTimeInterval, target aTarget: AnyObject, selector aSelector: Selector, userInfo: AnyObject?, repeats yesOrNo: Bool) -> NSTimer

構建timer的原因是:當我們在使用自己的ActivityIndicator View的時候,我們可能把它放到UIScrollView上面。這個時候使用scheduledTimerWithTimeInterval創建的timer是加入到當前Run Loop中的,而UIScrollView在接收到用戶交互事件時,主線程Run Loop會設置為UITrackingRunLoopMode。這個時候會導致timer失效。更詳細的解答,我在走進Run Loop的世界 (一):什麼是Run Loop?一文中有說明。

總結

到這個時候,我們應該就能看到和效果圖一樣的動畫效果。但是寫一個可供使用的自定義控件時,應該考慮更多的細節工作。比如初始化,視圖移除,intrinsicContentSize,是否需要支持 @IBInspectable 和 @IBDesignable 等等,來讓使用我們控件的開發者更加友好。更加詳細的代碼和Demo可以去這裡查看:https://github.com/yechunjun/CCActivityIndicatorView

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved