乾貨之運用CALayer創建星級評分組件(五角星)

来源:http://www.cnblogs.com/ALongWay/archive/2016/11/04/6031272.html
-Advertisement-
Play Games

本篇記錄星級評分組件的創建過程以及CALayer的運用。 為了實現一個星級評分的組件,使用了CALayer,涉及到mask、CGPathRef、UIBezierPath、動畫和一個計算多角星關鍵節點的演算法。 CALayer管理基於圖像的內容,並讓我們可以在內容上添加動畫。UIView及其子類擁有一個 ...


本篇記錄星級評分組件的創建過程以及CALayer的運用。

為了實現一個星級評分的組件,使用了CALayer,涉及到mask、CGPathRef、UIBezierPath、動畫和一個計算多角星關鍵節點的演算法。

CALayer管理基於圖像的內容,並讓我們可以在內容上添加動畫。UIView及其子類擁有一個屬性layer,我們可以運用該屬性做出非常多的效果。例如圓角、多邊形、甚至自定義形狀的view,局部遮擋,擦除模糊效果,局部內容依次閃亮效果,弧形進度條等等。

首先查看CALayer的一個屬性mask,這個屬性也是CALayer類型,跟他的名字意義一樣,就是用來遮擋內容的,預設為nil,所以我們可以看到一個UIView上的內容。如果給一個可見內容的view的layer屬性賦值CALayer實例,那這個view立刻就“消失”了。如下代碼:

CALayer *maskLayer = [CALayer layer];

maskLayer.frame = testView.bounds;

self.layer.mask = maskLayer;

再看另一個類CAShapeLayer,繼承與CALayer,並具有眾多額外屬性,例如path、fillColor、strokeColor。其中的path屬性,可以決定“不遮擋”路徑範圍內的內容。如果我們將之前的mask屬性賦值為一個CAShapeLayer實例,或者在之前的CALayer實例上addSublayer該實例,並指定一個中心圓的路徑,那就實現了常見的圓形頭像顯示效果。與設置UIView的layer的corner作用一樣。

需要註意一點,如果添加的CAShapeLayer的fillColor為[UIColor clearColor].CGColor,即使在path範圍內,也將失去“不遮擋”作用,而該值預設為不透明黑色。簡單來說,如果透明就將遮擋內容。可以發現,mask及其sublayer上的填充和路徑顏色,都是不會顯示的,只用於決定是否遮擋自身所在layer的內容。

利用這一特點,可以實現“開門”和“關門”的類似效果,在一個CALayer上添加兩個sublayer作為“門”。還可以實現潑墨等更多的效果。

值得一提的是,每個sublayer也可以利用frame和mask屬性做出相對於view的局部的遮擋效果。

回到CAShapeLayer的fillColor屬性,該屬性將path範圍內填充上某種顏色;strokeColor是指定path軌跡上的顏色,strokeStart、strokeEnd指定軌跡的開始和結束的繪製點;還有line相關的屬性指定線的屬性。運用這些屬性,可以做出任意形狀的進度條、載入動畫等。

從以上記錄可以看出path屬性很重要,該屬性是CGPathRef類型。常用創建方法為 CGPathCreateMutable(void)系列方法:

    CGMutablePathRef path = CGPathCreateMutable();
    CGPoint firstPoint = [[keyPointsArray firstObject] CGPointValue];
    CGPathMoveToPoint(path, nil, firstPoint.x, firstPoint.y);
    
    for (int i = 1; i < keyPointsArray.count; i++) {
        CGPoint currentPoint = [keyPointsArray[i] CGPointValue];
        CGPathAddLineToPoint(path, nil, currentPoint.x, currentPoint.y);
    }
    
    CGPathAddLineToPoint(path, nil, firstPoint.x, firstPoint.y);
    
    _maskLayer.path = path;
    _starShapeLayer.path = path;
    CGPathRelease(path);

也可以使用UIBezierPath的系列類方法,添加好路徑後,由方法- (CGPathRef)CGPath得到path。例如:

    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(_bgShapeLayer.frame.size.width / 2.0, _bgShapeLayer.frame.size.height / 2.0) radius:_radius startAngle:0 endAngle: 2 * M_PI clockwise:YES];
    _bgShapeLayer.path = bezierPath.CGPath;

 

下麵開始記錄星級評分組件的創建。

下圖為最終效果:

點擊星星的左右半邊會決定填充一半還是全部內容。還可以設置百分比填充內容。支持>5角星。

單個星星的內部設計為:view設置了灰色背景色;view.layer.mask的path為五角星;view.layer添加一個bgShapeLayer,背景為黃色,控制其width實現填充百分比;再添加一個starShapeLayer,path為同樣的五角星,設置路徑顏色作為邊框。

這裡的難點在於計算多角星的交點,如果為五角星,則需要10個關鍵點的坐標。

下麵記錄求交點的演算法:

1.先確定一個初始頂點

2.根據等分弧度和半徑,由三角函數的正餘弦相關公式求得全部外頂點

3.求出內交點的兩條相交直線

4.由二元一次方程求出交點

 

具體實現代碼如下:

- (NSArray *)getStarKeyPoints
{
    CGPoint center = CGPointMake(self.frame.size.width / 2.0, _radius);
    CGFloat sectionAngle = 2 * M_PI / _topPointCount;
    
    NSMutableArray *keyPointsArray = [NSMutableArray array];
    CGPoint firstPoint = CGPointMake(center.x, 0);
    [keyPointsArray addObject:[NSValue valueWithCGPoint:firstPoint]];
    
    //外圍頂點
    for (int i = 1; i < _topPointCount; i++) {
        CGFloat x = cosf(i * sectionAngle - M_PI_2) * _radius;
        CGFloat y = sinf(i * sectionAngle - M_PI_2) * _radius;
        
        CGPoint point = CGPointMake(x + center.x, y + center.y);
        
        [keyPointsArray addObject:[NSValue valueWithCGPoint:point]];
    }
    
    //內交點
    NSMutableArray *crossPointsArray = [NSMutableArray array];

    //採用二元一次方程求解
    //AC點確定直線方程y = kx + b
    //過B點直線y = B.y
    for (int i = 0; i < _topPointCount; i++) {
        CGPoint A = [keyPointsArray[i] CGPointValue];
        
        NSInteger index = i + 1;
        if (index > _topPointCount - 1) {
            index -= _topPointCount;
        }
        CGPoint B = [keyPointsArray[index] CGPointValue];
        
        index = i + 2;
        if (index > _topPointCount - 1) {
            index -= _topPointCount;
        }
        CGPoint C = [keyPointsArray[index] CGPointValue];
        
        index = i - 1;
        if (index < 0) {
            index += _topPointCount;
        }
        CGPoint E = [keyPointsArray[index] CGPointValue];
        
        CGFloat F_x = 0.0, F_y = 0.0, k1 = 0.0, k2 = 0.0, b1 = 0.0, b2 = 0.0;
        
        if (A.x == C.x) {
            F_x = A.x;
        } else {
            k1 = (A.y - C.y) / (A.x - C.x);
            b1 = A.y - k1 * A.x;
        }
        
        if (B.x == E.x) {
            F_x = B.x;
        } else {
            k2 = (B.y - E.y) / (B.x - E.x);
            b2 = B.y - k2 * B.x;
        }
        
        if (A.x == C.x) {
            F_y = k2 * F_x + b2;
        }else if (B.x == E.x) {
            F_y = k1 * F_x + b1;
        }else{
            if (k1 == 0) {
                F_y = A.y;
                F_x = (F_y - b2) / k2;
            } else {
                F_y = (b1 * k2 - b2 * k1) / (k2 - k1);
                F_x = (F_y - b1) / k1;
            }
        }

        CGPoint pointF = CGPointMake(F_x, F_y);
        [crossPointsArray addObject:[NSValue valueWithCGPoint:pointF]];
    }
    
    //合併數據
    for (int i = 0; i < crossPointsArray.count; i++) {
        [keyPointsArray insertObject:crossPointsArray[i] atIndex:(i * 2 + 1)];
    }
    
    return keyPointsArray;
}

 

將關鍵點線段添加到path中,生成多角形路徑,用於mask和邊框layer。

最後添加點擊手勢,根據觸摸點的範圍確定操作。

 

實現單個五角星以後,常見的將五個五角星併排放置,統一管理每個五角星的填充百分比。

 

ALWStarComment已在Base項目中更新:https://github.com/ALongWay/base.git


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如果想讓別人用你的代碼但是又不想暴露你的源碼,可以使用靜態庫的方式 1.新建項目選擇Cocoa Touch Static Libraay 2.把要打包的文件拖入工程裡面 3.選擇targets->Build Phases->點擊加號->選擇New Headers Phase 4.在Headers裡面 ...
  • 開源一個即時通訊類App,支持純文本、語音、地理位置、圖片聊天,同時還加入了好友圈功能,支持分享動態和發送圖片,支持搜索附近的人,使用的百度地圖定位功能;由Bmob後端雲提供伺服器支持,歡迎喜歡的伙伴在我的github上面start和fork。項目地址:https://github.com/tony ...
  • 隊列組 讓隊列里的任務同時執行,當任務都執行完畢時,再以通知的形式告訴程式員。舉例,同時下載兩張圖片,兩張圖片都下載完了,在合成成一張。 代碼: 日誌 效果: 如果不用隊列組,下載第一張圖片、下載第二張圖片、合併兩張圖片,就只能當做一個任務放入隊列中,不能同時下載兩張圖片,耗時幾乎多了一倍。因為,如 ...
  • 說起鏈式編程和函數式編程,小伙伴們千萬不要緊張。 聽著很高大尚,其實也就那麼回事。相信有過C#開發經驗的,或者其他編程經驗的,只要不是OC,一看就知道。 看兩行代碼: 上面的就是鏈式編程+函數式編程。 來個大白話解釋:看到括弧裡面的參數了吧,跟C的函數調用是不是很相似,包括別的語言,都用小括弧傳參, ...
  • 代理這東西,真的不想再談了,估計是個iOS開發人員都能熟練使用,跟Notification和Block一樣,都用的滾瓜爛熟了。 這裡小小的談論一下代理的擴展:隱式代理和多播代理,其實非常簡單。 隱式代理:就是定義協議的屬性時不用再遵守協議了,實現方法的類也不用在遵守協議了,因為協議方法定義在NSOb ...
  • (以下圖片在IE瀏覽器中可能無法顯示) 在開始筆記之前先加點之前記下的小知識點: UIView的常見屬性和方法: 1.@property(nonatomic,radonly)UIView *superview; 獲得自己的父控制項對象 2.@property (nonatomic,radonly,co ...
  • 動畫效果可以大大提高界面的交互效果,因此,動畫在移動開發中的應用場景較為普遍。掌握基本的動畫效果在成熟的軟體開發中不可或缺。除此之外,用戶對於動畫的接受程度遠高於文字和圖片,利用動畫效果可以加深用戶對於產品的印象。因此本文給出安卓設計中幾種常見的動畫效果。 基礎知識 在介紹安卓中的動畫效果之前,有必 ...
  • 1、簡介 Fresco是Facebook最新推出的一款用於Android應用中展示圖片的強大圖片庫,可以從網路、本地存儲和本地資源中載入圖片。相對於ImageLoader,擁有更快的圖片下載速度以及可以載入和顯示gif圖等諸多優勢,是個很好的圖片框架。 2、特點 1)記憶體管理 在5.0以下系統,Fr ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...