1. 程式人生 > >iOS開發示例————使用CAShapeLayer&UIBezierPath繪製資料餅圖

iOS開發示例————使用CAShapeLayer&UIBezierPath繪製資料餅圖

前言借鑑標哥的部落格部分文章:http://www.henishuo.com/ios-cashapelayer-learning/

CAShapeLayer和drawRect的比較:


drawRect:屬於CoreGraphics框架,佔用CPU,效能消耗大,不建議重寫
CAShapeLayer:屬於CoreAnimation框架,通過GPU來渲染圖形,節省效能。動畫渲染直接提交給手機GPU,不消耗記憶體,這兩者各有各的用途,而不是說有了CAShapeLayer就不需要drawRect。

溫馨提示:drawRect只是一個方法而已,是UIView的方法,重寫此方法可以完成我們的繪製圖形功能。

CAShapeLayer與UIBezierPath的關係:

CAShapeLayer中shape代表形狀的意思,所以需要形狀才能生效
貝塞爾曲線可以建立基於向量的路徑,而UIBezierPath類是對CGPathRef的封裝
貝塞爾曲線給CAShapeLayer提供路徑,CAShapeLayer在提供的路徑中進行渲染。路徑會閉環,所以繪製出了Shape,用於CAShapeLayer的貝塞爾曲線作為path,其path是一個首尾相接的閉環的曲線,即使該貝塞爾曲線不是一個閉環的曲線

示例簡介:

在餅圖上顯示陣列中幾個資料各佔有的百分比,SliceLayer是CAShapeLayer的子類,用於構造餅圖的各個扇面和選中某扇面的動畫效果,PieChart是UIView的子類,用於根據陣列的資料情況來設定餅圖的各個扇面和觸控方法,最後在VC中呼叫即可。

示例程式碼:

#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>

@interface SliceLayer : CAShapeLayer

@property (nonatomic, assign) CGFloat startAngle;
@property (nonatomic, assign) CGFloat endAngle;
@property (nonatomic, assign) CGPoint centerPoint;
@property (nonatomic, assign) CGFloat radius;
@property (nonatomic, assign) BOOL selected;
@property (nonatomic, strong) NSString *text;
@property (nonatomic, assign) NSInteger tag;

- (void)create;

@end

#define RandomColor [UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 255 / 255.0 alpha:1.0]

#import "SliceLayer.h"

@implementation SliceLayer

- (void)create {
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:_centerPoint];
    [path addArcWithCenter:_centerPoint radius:_radius startAngle:_startAngle endAngle:_endAngle clockwise:YES];
    [path closePath];
    self.path = path.CGPath;
    self.strokeColor = [UIColor cyanColor].CGColor;
    self.fillColor = RandomColor.CGColor;
}

- (void)setSelected:(BOOL)selected {
    _selected = selected;
    CGPoint newCenterPoint = _centerPoint;
    if (selected) {
        newCenterPoint = CGPointMake(_centerPoint.x + cosf((_startAngle + _endAngle) / 2) * 30, _centerPoint.y + sinf((_startAngle + _endAngle) / 2) * 30);
    }
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:newCenterPoint];
    [path addArcWithCenter:newCenterPoint radius:_radius startAngle:_startAngle endAngle:_endAngle clockwise:YES];
    [path closePath];
    self.path = path.CGPath;
    
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"path";
    animation.toValue = path;
    animation.duration = 0.5;
    [self addAnimation:animation forKey:nil];
}

@end

#import <UIKit/UIKit.h>
//typedef void(^MyBlock)(CGFloat);

@interface PieChart : UIView

@property (nonatomic, strong) NSArray *datas;
@property (nonatomic, strong) NSMutableArray *sliceLayerArray;
//@property (nonatomic, strong) MyBlock angleBlock;

@end

#import "PieChart.h"
#import "SliceLayer.h"

@implementation PieChart {
    CGFloat percentage;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.sliceLayerArray = @[].mutableCopy;
    }
    return self;
}

- (void)setDatas:(NSArray *)datas {
    _datas = datas;
    CGFloat startAngle = 0;
    CGFloat endAngle = 0;
    for (int i = 0; i < datas.count; i++) {
        percentage = [datas[i] floatValue];
        CGFloat angle = percentage * M_PI * 2;
        endAngle = angle + startAngle;
        
        SliceLayer *sliceLayer = [[SliceLayer alloc] init];
        sliceLayer.startAngle = startAngle;
        sliceLayer.endAngle = endAngle;
        sliceLayer.radius = 100.0f;
        sliceLayer.centerPoint = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
        sliceLayer.tag = i;
        [sliceLayer create];
        [self.layer addSublayer:sliceLayer];
        [self.sliceLayerArray addObject:sliceLayer];
        
        CATextLayer *textLayer = [CATextLayer layer];
        textLayer.frame = CGRectMake(sliceLayer.centerPoint.x + cosf((startAngle + endAngle) / 2) * 50 - 15, sliceLayer.centerPoint.y + sinf((startAngle + endAngle) / 2) * 50 - 10, 40, 20);
        textLayer.string = [NSString stringWithFormat:@"%1.f%%", percentage * 100];
        textLayer.fontSize = 17;
        textLayer.contentsScale = 2;
        
        [sliceLayer addSublayer:textLayer];
        
        startAngle = endAngle;
        
    }
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    CGPoint touchPoint = [[touches anyObject] locationInView:self];
    for (SliceLayer *slice in _sliceLayerArray) {
        //判斷選擇區域
        if (CGPathContainsPoint(slice.path, 0, touchPoint, YES)) {
            slice.selected = YES;
//            self.angleBlock((slice.endAngle - slice.startAngle) / 2 / M_PI);
        } else {
            slice.selected = NO;
        }
    }
}
#import "ViewController.h"
#import "PieChart.h"
@class PieChart;

@interface ViewController () {
    CAShapeLayer *shapeLayer;
    NSTimer *timer;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor blackColor];
    
    PieChart *pieChart = [[PieChart alloc] initWithFrame:self.view.bounds];
    pieChart.datas = @[@0.1, @0.2, @0.3, @0.25, @0.1, @0.05];
    pieChart.backgroundColor = [UIColor orangeColor];
    [self.view addSubview:pieChart];
}


相關推薦

iOS開發示例————使用CAShapeLayer&UIBezierPath繪製資料

前言借鑑標哥的部落格部分文章:http://www.henishuo.com/ios-cashapelayer-learning/ CAShapeLayer和drawRect的比較: drawRect:屬於CoreGraphics框架,佔用CPU,效能消耗大,不建議重寫CA

iOS開發-聊天氣泡的繪製和聊天訊息列表

iOS開發中什麼最重要?流媒體?即時通訊?還是其他什麼技術?其實都不是,最重要的東西誠然只是iOS的基礎,比如畫一個按鈕,封裝一個控制元件,擴充套件一個類等等。這些東西看似簡單,實則很難,所有的技術都基於這些最基礎的東西,今天要說的是聊天氣泡的繪製,和做一個簡單

ios開發中的4種資料持久化方式

iOS中的永久儲存,也就是在關機重新啟動裝置,或者關閉應用時,不會丟失資料。在實際開發應用時,往往需要持久儲存資料的,這樣使用者才能在對應用進行操作後,再次啟動能看到自己更改的結果與痕跡。ios開發中,我們需要資料持久化這一種技術,也需要不斷在實際開發的工作與學習中完善資

iOS開發總結之UITableView表格資料的批量操作

1.效果圖 2.關鍵程式碼 #import "DealsViewController.h" #import "Deal.h" #import "DealCell.h" @interface DealsViewController () <UITableViewD

iOS開發中對JSON解析資料的處理

在網上看到一個例子,對JSON解析出來的資料處理的方法非常簡單,而且通用,把我對它理解的思路寫一下。 首先介紹下JSON解析,JSON解析出來的資料只有陣列和物件兩種結構。 objective - c中用字典來儲存物件資訊。key值對應物件名字,value值對應物件的值。在

iOS開發-------塗鴉板(UIBezierPath 貝賽爾曲線)與 MVC初嘗試

         塗鴉板,顧名思義就是能夠在上面畫點東西,貝賽爾曲線(UIBezierPath),也可以叫做貝賽爾路徑。因為path的直譯就是路徑,看起來很高大上,之前樓主也確實這麼認為的,很高大上,細細瞭解,其實也不難,畢竟難的東西蘋果都給我們封裝好了。初次用MVC模式來

iOS 簡單的使用UIBezierPath繪製

UIBezierPath這個類呢主要用於繪圖。  之前的專案中需要繪圖的部分都是用Core Graphics來繪製,OC是我的第一門語言,所以對於Core Graphics的C語言API不太適應,最近發現原來蘋果的UIKit中已經對Core Graphics做了一些簡單的

iOS開發中,對請求資料出現的一些簡單處理

這裡呢是整理的一位老鳥的東西,好東西得分享 大致實現思路就是迴圈便利做比較,如果發現是NSNull型別的就把值改為空字串;這樣的好處就是當資料請求回來,刪除一下資料裡面為<null>型別的東西,避免在直接取的時候產生程式崩潰問題; 兩個方法,一個返回NSA

iOS開發——定制圓形頭像與照相機庫的使用

agen dem gen 聲明 rom 觀察者 sof one picker 如今的App都很流行圓形的頭像,比方QQ右上角的頭像,今日頭條的頭像等等。這已經成為App設計的趨勢了。今天我們就來簡單實現一下這個功能,我還會把從手機拍照中或者圖庫中取出作為頭

解決使用echarts做動態資料展示中data如何傳值的問題

** 解決使用echarts做動態資料餅圖展示中data如何傳值的問題 ** 如圖,將所查出的資料以餅圖形式展示 下面是頁面data的傳值方法 這是data,請忽略data裡的那些值。那是用來測試用的, 首先將從資料庫查出的資料裝到兩個list裡面,再通過json傳到前臺。

簡單死資料

效果圖: CustomPiechartView繼承View package com.example.piechart.view; import android.content.Context; import android.graphics.Canvas; import an

Android移動開發-使用OpenGL來繪製3D紋理的實現

OpenGL(全寫Open Graphics Library)是指定義了一個跨程式語言、跨平臺的程式設計介面規格的專業的圖形程式介面。它用於三維影象(二維的亦可),是一個功能強大,呼叫方便的底層圖形庫。 OpenGL是行業領域中最為廣泛接納的 2D/

R繪製3D

二維餅圖程式碼如下:#繪製2維餅圖 x=read.delim("C:/Users/a/Desktop/sample.txt",header=FALSE) #讀入文字資料 names(x)=c("word

Android使用j4lChartAndroid外掛繪製3D

圖表是常見的直觀表示資料的途徑,目前在android手機上繪製圖表基本有兩種方法:一是利用java的canvas自己繪製,這種方法自己可操作性強,可以隨心所欲地繪製,但是缺點就是工作量大;二是利用第三方外掛。本文將給大家介紹一下利用第三方外掛j4lChartAndroid如

【視覺化】pandas與matplotlib繪製環形

匯入相關庫 import pandas as pd import matplotlib.pyplot as plt % matplotlib inline 生產測試資料 data = pd.D

iOS開發之初:根據一張gif,返回其中每一幀的圖片陣列(ImageView載入gif))

在APP開發過程中能用到gif圖的地方無非就是重新整理和載入動畫了(等用到小動畫的地方).但是UIImageView是無法直接載入gif圖的,ImageView提供了一個載入動畫圖片陣列的方法..那要有很多幀.png/.jpg的圖片才行…但是像我這種沒有美工的開

iOS圖形繪製 UIBezierPath 繪製折線、柱狀

iOS圖形繪製 UIBezierPath 繪製折線圖、柱狀圖以及餅形圖(感謝Mr_Wendao,如果想檢視餅形圖原始碼請點選連線,餅形圖我借鑑了Mr_Wendao的程式碼學習,再次感謝)。 先看一下程式碼的效果圖 如下圖 下面是主要程式碼 在初始化

iOS開發之Runtime常用示例總結

開發一、構建Runtime測試用例本篇博客的內容是依托於實例的,所以我們在本篇博客中先構建我們的測試類,Runtime將會對該類進行相關的操作。下方就是本篇博客所涉及Demo的目錄,上面的RuntimeKit類是講Runtime常用的功能進行了簡單的封裝,而下方的TestClass以及相關的類目就是我們Run

iOS開發技巧之:獲取ios相簿gif圖片 原資料

<AssetsLibrary/AssetsLibrary.h> 從Safari上儲存了一張動態GIF到本地的相簿中可以確定,儲存到本地相簿的動態GIF沒有問題,只是iPhone的相簿不能顯示動態GIF然後在自己的應用中,要可以選擇GIF圖片上傳到伺服器用UIImagePickerCo

iOS開發技巧之:iOS判斷兩個陣列中資料是否相同

IOS開發之判斷兩個陣列中資料是否相同例項詳解 前言: 工作中遇到的問題,這裡記錄下,也許能幫助到大家 例項程式碼: ? 1