Эх сурвалжийг харах

1.修改iOS Apex Mobile引入KPI并修改Homer界面增加KPI。

Pen Li 8 жил өмнө
parent
commit
be983c3060
35 өөрчлөгдсөн 3751 нэмэгдсэн , 21 устгасан
  1. 82 0
      Apex Mobile/Apex Mobile.xcodeproj/project.pbxproj
  2. 123 2
      Apex Mobile/Apex Mobile/HomeViewController.m
  3. 86 0
      Apex Mobile/Apex Mobile/KPI.json
  4. 13 0
      Apex Mobile/Apex Mobile/KPIButton.h
  5. 37 0
      Apex Mobile/Apex Mobile/KPIButton.m
  6. 25 0
      Apex Mobile/Apex Mobile/KPICell.h
  7. 264 0
      Apex Mobile/Apex Mobile/KPICell.m
  8. 25 0
      Apex Mobile/Apex Mobile/KPIPieChartCell.h
  9. 255 0
      Apex Mobile/Apex Mobile/KPIPieChartCell.m
  10. 94 0
      Apex Mobile/Apex Mobile/KPIPieChartCell.xib
  11. 199 19
      Apex Mobile/Apex Mobile/Main.storyboard
  12. 23 0
      Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/Contents.json
  13. BIN
      Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/nextItem.png
  14. BIN
      Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/nextItem@2x.png
  15. BIN
      Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/nextItem@3x.png
  16. 23 0
      Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/Contents.json
  17. BIN
      Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/preItem.png
  18. BIN
      Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/preItem@2x.png
  19. BIN
      Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/preItem@3x.png
  20. 6 0
      Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/Contents.json
  21. 21 0
      Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/center_white.imageset/Contents.json
  22. BIN
      Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/center_white.imageset/center_white.png
  23. 23 0
      Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/Contents.json
  24. BIN
      Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/dot.png
  25. BIN
      Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/dot@2x.png
  26. BIN
      Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/dot@3x.png
  27. 29 0
      Apex Mobile/Apex Mobile/PieChart/XYCommon.h
  28. 19 0
      Apex Mobile/Apex Mobile/PieChart/XYCommon.m
  29. 67 0
      Apex Mobile/Apex Mobile/PieChart/XYPieChartView.h
  30. 516 0
      Apex Mobile/Apex Mobile/PieChart/XYPieChartView.m
  31. 104 0
      Apex Mobile/Apex Mobile/PieChart/XYRenderView.h
  32. 780 0
      Apex Mobile/Apex Mobile/PieChart/XYRenderView.m
  33. 79 0
      Apex Mobile/Apex Mobile/PieChart/XYRotatedView.h
  34. 433 0
      Apex Mobile/Apex Mobile/PieChart/XYRotatedView.m
  35. 425 0
      Apex Mobile/Apex Mobile/fake_home.json

+ 82 - 0
Apex Mobile/Apex Mobile.xcodeproj/project.pbxproj

@@ -9,6 +9,16 @@
 /* Begin PBXBuildFile section */
 		4235C30320229F7200A99D04 /* Result.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4235C30220229F7200A99D04 /* Result.xib */; };
 		4235C3052022A60A00A99D04 /* ResultCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4235C3042022A60A00A99D04 /* ResultCell.xib */; };
+		4253900E2079B7C700ECF982 /* KPIPieChartCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4253900C2079B7C700ECF982 /* KPIPieChartCell.m */; };
+		4253900F2079B7C700ECF982 /* KPIPieChartCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4253900D2079B7C700ECF982 /* KPIPieChartCell.xib */; };
+		425390202079B99B00ECF982 /* XYCommon.m in Sources */ = {isa = PBXBuildFile; fileRef = 425390172079B99A00ECF982 /* XYCommon.m */; };
+		425390212079B99B00ECF982 /* PieChart.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 425390192079B99B00ECF982 /* PieChart.xcassets */; };
+		425390222079B99B00ECF982 /* XYRotatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4253901B2079B99B00ECF982 /* XYRotatedView.m */; };
+		425390232079B99B00ECF982 /* XYPieChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4253901C2079B99B00ECF982 /* XYPieChartView.m */; };
+		425390242079B99B00ECF982 /* XYRenderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4253901E2079B99B00ECF982 /* XYRenderView.m */; };
+		425390262079B9B500ECF982 /* KPI.json in Resources */ = {isa = PBXBuildFile; fileRef = 425390252079B9B400ECF982 /* KPI.json */; };
+		42539029207A159300ECF982 /* KPIButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 42539028207A159300ECF982 /* KPIButton.m */; };
+		42541ACF207C49610072BC5A /* fake_home.json in Resources */ = {isa = PBXBuildFile; fileRef = 42541ACE207C49610072BC5A /* fake_home.json */; };
 		425660DB202015E1002DB0CA /* Launch.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 425660DA202015E1002DB0CA /* Launch.storyboard */; };
 		425CF096201EB2B500750E32 /* JLRefreshFooter.m in Sources */ = {isa = PBXBuildFile; fileRef = 425CF08C201EB2B500750E32 /* JLRefreshFooter.m */; };
 		425CF097201EB2B500750E32 /* JLRefreshHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 425CF08F201EB2B500750E32 /* JLRefreshHeader.m */; };
@@ -29,6 +39,7 @@
 		427CF5E6202454750041472A /* GoogleMapsBase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 427CF5E3202454750041472A /* GoogleMapsBase.framework */; };
 		427CF5E7202454750041472A /* GoogleMapsCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 427CF5E4202454750041472A /* GoogleMapsCore.framework */; };
 		427CF5E9202454860041472A /* GoogleMaps.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 427CF5E8202454860041472A /* GoogleMaps.bundle */; };
+		42BFD2D2207B697800DA9038 /* KPICell.m in Sources */ = {isa = PBXBuildFile; fileRef = 42BFD2D1207B697800DA9038 /* KPICell.m */; };
 		7101BEC82031389A00CC6E3A /* DetailCellKVNew.m in Sources */ = {isa = PBXBuildFile; fileRef = 7101BEC72031389A00CC6E3A /* DetailCellKVNew.m */; };
 		711BA6C1191E0525002EDE6F /* MessageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 711BA6C0191E0525002EDE6F /* MessageViewController.m */; };
 		711BA6C4191E0553002EDE6F /* MessageItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 711BA6C3191E0553002EDE6F /* MessageItem.m */; };
@@ -174,6 +185,22 @@
 /* Begin PBXFileReference section */
 		4235C30220229F7200A99D04 /* Result.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Result.xib; path = ../../common/customUI/Result.xib; sourceTree = "<group>"; };
 		4235C3042022A60A00A99D04 /* ResultCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ResultCell.xib; path = ../../common/customUI/ResultCell.xib; sourceTree = "<group>"; };
+		4253900B2079B7C700ECF982 /* KPIPieChartCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPIPieChartCell.h; sourceTree = "<group>"; };
+		4253900C2079B7C700ECF982 /* KPIPieChartCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KPIPieChartCell.m; sourceTree = "<group>"; };
+		4253900D2079B7C700ECF982 /* KPIPieChartCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KPIPieChartCell.xib; sourceTree = "<group>"; };
+		425390172079B99A00ECF982 /* XYCommon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XYCommon.m; sourceTree = "<group>"; };
+		425390182079B99A00ECF982 /* XYRotatedView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XYRotatedView.h; sourceTree = "<group>"; };
+		425390192079B99B00ECF982 /* PieChart.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = PieChart.xcassets; sourceTree = "<group>"; };
+		4253901A2079B99B00ECF982 /* XYPieChartView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XYPieChartView.h; sourceTree = "<group>"; };
+		4253901B2079B99B00ECF982 /* XYRotatedView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XYRotatedView.m; sourceTree = "<group>"; };
+		4253901C2079B99B00ECF982 /* XYPieChartView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XYPieChartView.m; sourceTree = "<group>"; };
+		4253901D2079B99B00ECF982 /* XYRenderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XYRenderView.h; sourceTree = "<group>"; };
+		4253901E2079B99B00ECF982 /* XYRenderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XYRenderView.m; sourceTree = "<group>"; };
+		4253901F2079B99B00ECF982 /* XYCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XYCommon.h; sourceTree = "<group>"; };
+		425390252079B9B400ECF982 /* KPI.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = KPI.json; sourceTree = "<group>"; };
+		42539027207A159300ECF982 /* KPIButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPIButton.h; sourceTree = "<group>"; };
+		42539028207A159300ECF982 /* KPIButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KPIButton.m; sourceTree = "<group>"; };
+		42541ACE207C49610072BC5A /* fake_home.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = fake_home.json; sourceTree = "<group>"; };
 		425660DA202015E1002DB0CA /* Launch.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Launch.storyboard; sourceTree = "<group>"; };
 		425CF08B201EB2B500750E32 /* JLRefreshFooter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JLRefreshFooter.h; sourceTree = "<group>"; };
 		425CF08C201EB2B500750E32 /* JLRefreshFooter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JLRefreshFooter.m; sourceTree = "<group>"; };
@@ -206,6 +233,8 @@
 		427CF5E3202454750041472A /* GoogleMapsBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleMapsBase.framework; sourceTree = "<group>"; };
 		427CF5E4202454750041472A /* GoogleMapsCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleMapsCore.framework; sourceTree = "<group>"; };
 		427CF5E8202454860041472A /* GoogleMaps.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = GoogleMaps.bundle; path = GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle; sourceTree = "<group>"; };
+		42BFD2D0207B697800DA9038 /* KPICell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPICell.h; sourceTree = "<group>"; };
+		42BFD2D1207B697800DA9038 /* KPICell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KPICell.m; sourceTree = "<group>"; };
 		7101BEC62031389A00CC6E3A /* DetailCellKVNew.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DetailCellKVNew.h; sourceTree = "<group>"; };
 		7101BEC72031389A00CC6E3A /* DetailCellKVNew.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DetailCellKVNew.m; sourceTree = "<group>"; };
 		711BA6BF191E0525002EDE6F /* MessageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageViewController.h; sourceTree = "<group>"; };
@@ -477,6 +506,44 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		425390072079B73800ECF982 /* KPI */ = {
+			isa = PBXGroup;
+			children = (
+				425390152079B7EA00ECF982 /* Cell */,
+			);
+			name = KPI;
+			sourceTree = "<group>";
+		};
+		425390152079B7EA00ECF982 /* Cell */ = {
+			isa = PBXGroup;
+			children = (
+				4253900B2079B7C700ECF982 /* KPIPieChartCell.h */,
+				4253900C2079B7C700ECF982 /* KPIPieChartCell.m */,
+				4253900D2079B7C700ECF982 /* KPIPieChartCell.xib */,
+				42539027207A159300ECF982 /* KPIButton.h */,
+				42539028207A159300ECF982 /* KPIButton.m */,
+				42BFD2D0207B697800DA9038 /* KPICell.h */,
+				42BFD2D1207B697800DA9038 /* KPICell.m */,
+			);
+			name = Cell;
+			sourceTree = "<group>";
+		};
+		425390162079B94300ECF982 /* PieChart */ = {
+			isa = PBXGroup;
+			children = (
+				425390192079B99B00ECF982 /* PieChart.xcassets */,
+				4253901F2079B99B00ECF982 /* XYCommon.h */,
+				425390172079B99A00ECF982 /* XYCommon.m */,
+				4253901A2079B99B00ECF982 /* XYPieChartView.h */,
+				4253901C2079B99B00ECF982 /* XYPieChartView.m */,
+				4253901D2079B99B00ECF982 /* XYRenderView.h */,
+				4253901E2079B99B00ECF982 /* XYRenderView.m */,
+				425390182079B99A00ECF982 /* XYRotatedView.h */,
+				4253901B2079B99B00ECF982 /* XYRotatedView.m */,
+			);
+			path = PieChart;
+			sourceTree = "<group>";
+		};
 		425CF088201EAF8800750E32 /* History */ = {
 			isa = PBXGroup;
 			children = (
@@ -581,6 +648,7 @@
 		715643B820198A6000B04267 /* new */ = {
 			isa = PBXGroup;
 			children = (
+				425390072079B73800ECF982 /* KPI */,
 				716027CE204D3302003CA085 /* share */,
 				7162546A201C3AF1009E3A41 /* readme.txt */,
 				7157099A2021591F00EFE5C5 /* config.h */,
@@ -701,6 +769,8 @@
 		7162546E201C51DC009E3A41 /* fake data */ = {
 			isa = PBXGroup;
 			children = (
+				42541ACE207C49610072BC5A /* fake_home.json */,
+				425390252079B9B400ECF982 /* KPI.json */,
 				7162546F201C5205009E3A41 /* fake_container_list.json */,
 				71807B972021965B00E1F1DD /* fake_tracking.json */,
 				71807B9D2021ACE500E1F1DD /* fake_search.json */,
@@ -934,6 +1004,7 @@
 			isa = PBXGroup;
 			children = (
 				427994B120300E7300746EDC /* Apex Mobile.entitlements */,
+				425390162079B94300ECF982 /* PieChart */,
 				426E8AB4202163EB0073BA5D /* Alert */,
 				425CF089201EB2B500750E32 /* Refresh */,
 				715643B820198A6000B04267 /* new */,
@@ -1160,6 +1231,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				42541ACF207C49610072BC5A /* fake_home.json in Resources */,
 				71625470201C5205009E3A41 /* fake_container_list.json in Resources */,
 				7162546B201C3AF1009E3A41 /* readme.txt in Resources */,
 				427CF5E9202454860041472A /* GoogleMaps.bundle in Resources */,
@@ -1167,7 +1239,9 @@
 				715643DC201C117300B04267 /* search.json in Resources */,
 				4235C30320229F7200A99D04 /* Result.xib in Resources */,
 				719EF8F418BB839F00EFFF5F /* Main_iPhone.storyboard in Resources */,
+				425390212079B99B00ECF982 /* PieChart.xcassets in Resources */,
 				715709BC20215E0000EFE5C5 /* LICENSE in Resources */,
+				4253900F2079B7C700ECF982 /* KPIPieChartCell.xib in Resources */,
 				71E0D1D92022AB7E009A08EB /* Result.storyboard in Resources */,
 				715643DE201C1AE600B04267 /* my.json in Resources */,
 				71807B982021965B00E1F1DD /* fake_tracking.json in Resources */,
@@ -1176,6 +1250,7 @@
 				714C39BF19234065004F045B /* Localizable.strings in Resources */,
 				427CF5D02023F5560041472A /* NewImages.xcassets in Resources */,
 				425660DB202015E1002DB0CA /* Launch.storyboard in Resources */,
+				425390262079B9B500ECF982 /* KPI.json in Resources */,
 				715643DA201C079F00B04267 /* tools.json in Resources */,
 				715643D5201AD2AB00B04267 /* StaticModelistViewController.xib in Resources */,
 				71807B9E2021ACE500E1F1DD /* fake_search.json in Resources */,
@@ -1211,6 +1286,7 @@
 				71F67CFC19066375004E8462 /* PulldownMenu.m in Sources */,
 				71406DD118C36A6E000914C4 /* TableCellDate.m in Sources */,
 				717D772F18C84E3F0070302D /* PageData.m in Sources */,
+				425390202079B99B00ECF982 /* XYCommon.m in Sources */,
 				715709BB20215E0000EFE5C5 /* NSData+Base64.m in Sources */,
 				71375C8F18D96EDE00EBA026 /* TabBarController.m in Sources */,
 				71951E6F18C6A9A5005024BD /* TouchLabel.m in Sources */,
@@ -1218,9 +1294,11 @@
 				425CF099201EB2B500750E32 /* UIScrollView+JLRefresh.m in Sources */,
 				71A01D7C18C9AE97003307A9 /* DetailCellList.m in Sources */,
 				71807B9C2021979A00E1F1DD /* DetailCellTracking.m in Sources */,
+				42539029207A159300ECF982 /* KPIButton.m in Sources */,
 				71DA74A618BDDD31003B46A6 /* AboutViewController.m in Sources */,
 				715643C42019B58400B04267 /* OrderHistoryViewController.m in Sources */,
 				712CBA0318CF38DB00C61394 /* RTLabel.m in Sources */,
+				425390242079B99B00ECF982 /* XYRenderView.m in Sources */,
 				71CEE3D718CC559B00052C63 /* ApexMobileNavigationController.m in Sources */,
 				426F39822033D0930025C568 /* ResultCell.m in Sources */,
 				715709922021574D00EFE5C5 /* RAConvertor.m in Sources */,
@@ -1233,6 +1311,7 @@
 				718BE8B4190F9D970046EA6A /* MySuggestion.m in Sources */,
 				715709A520215B5100EFE5C5 /* zip.c in Sources */,
 				715709AE20215CB000EFE5C5 /* RANetwork.m in Sources */,
+				425390222079B99B00ECF982 /* XYRotatedView.m in Sources */,
 				719EF8FD18BB839F00EFFF5F /* ApexMobileSecondViewController.m in Sources */,
 				715709BA20215E0000EFE5C5 /* NSString+Base64.m in Sources */,
 				71AE427318C47AF900B8EC3D /* SearchViewController.m in Sources */,
@@ -1253,6 +1332,7 @@
 				715643C72019BB6700B04267 /* StaticModelistViewController.m in Sources */,
 				7101BEC82031389A00CC6E3A /* DetailCellKVNew.m in Sources */,
 				71E0D1D82022AB7E009A08EB /* ResultViewController.m in Sources */,
+				42BFD2D2207B697800DA9038 /* KPICell.m in Sources */,
 				7157098E2021572600EFE5C5 /* NetworkUtils.m in Sources */,
 				719EF8F118BB839F00EFFF5F /* AppDelegate.m in Sources */,
 				714C39B81922FEE1004F045B /* NewsDetailViewController.m in Sources */,
@@ -1285,6 +1365,7 @@
 				719EF8ED18BB839F00EFFF5F /* main.m in Sources */,
 				717D76EB18C7F8120070302D /* Reachability.m in Sources */,
 				715709A720215B5100EFE5C5 /* ioapi.c in Sources */,
+				4253900E2079B7C700ECF982 /* KPIPieChartCell.m in Sources */,
 				715643CA2019BC4C00B04267 /* SearchlistViewController.m in Sources */,
 				7120DD0418BE273900E7546F /* LocationViewController.m in Sources */,
 				71308AFA191E7B2A0024B2B0 /* MessageDetailViewController.m in Sources */,
@@ -1300,6 +1381,7 @@
 				715709A820215B5100EFE5C5 /* mztools.c in Sources */,
 				719A51A918C5A5D30080C075 /* SimpleGridDataSource.m in Sources */,
 				718BE8B3190F9D970046EA6A /* MyAutocompletionCellFactory.m in Sources */,
+				425390232079B99B00ECF982 /* XYPieChartView.m in Sources */,
 				71570999202157BD00EFE5C5 /* RANetworkTaskDelegate.m in Sources */,
 				71A565DF18C212EA00CDAC07 /* Constant.m in Sources */,
 				718BE8B0190F9D970046EA6A /* MyAutocompleteView.m in Sources */,

+ 123 - 2
Apex Mobile/Apex Mobile/HomeViewController.m

@@ -12,17 +12,24 @@
 #import "ApexMobileDB.h"
 #import "DetailTabBarController.h"
 #import "RAUtils.h"
+#import "KPICell.h"
 
 #define SHIP_CELL_IDENTIFIER @"ShippingStatusCell"
+#define KPI_CELL_IDENTIFIER @"KPICell"
 
-@interface HomeViewController () <UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate>
+@interface HomeViewController () <UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,KPIDelegate>
 
+@property (strong, nonatomic) IBOutlet UISegmentedControl *segmentControl;
 @property (strong, nonatomic) IBOutlet UITableView *shipTableView;
 @property (strong, nonatomic) IBOutlet UISearchBar *shipSearchBar;
 @property (nonatomic,strong) NSMutableArray *shipArray;
 @property (strong, nonatomic) IBOutlet UIButton *emptyBtn;
 @property (nonatomic,strong) UIRefreshControl *refreshControl;
 @property (strong, nonatomic) IBOutlet UIActivityIndicatorView *loadIndicator;
+@property (strong, nonatomic) IBOutlet UICollectionView *KPICollectionView;
+
+@property (nonatomic,strong) NSMutableArray *KPIArray;
+@property (nonatomic,strong) NSArray *monthArray;
 
 @end
 
@@ -45,6 +52,7 @@
     
     [self.loadIndicator stopAnimating];
     
+    [self configureCollectionView];
     [self configureTableView];
     self.shipSearchBar.delegate =self;
     
@@ -105,6 +113,10 @@
     self.shipTableView.tableFooterView = [UIView new];
     
     [self.shipTableView registerNib:[UINib nibWithNibName:@"ShippingStatusCell" bundle:nil] forCellReuseIdentifier:SHIP_CELL_IDENTIFIER];
+    [self.shipTableView registerNib:[UINib nibWithNibName:@"KPIPieChartCell" bundle:nil] forCellReuseIdentifier:KPI_CELL_IDENTIFIER];
+    
+//    self.shipTableView.canCancelContentTouches = NO;//是否可以中断touches
+//    self.shipTableView.delaysContentTouches = NO;//是否延迟touches事件
     
     UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
     refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"loading data..."];
@@ -113,6 +125,12 @@
     self.refreshControl = refresh;
 }
 
+- (void)configureCollectionView {
+    
+    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.KPICollectionView.collectionViewLayout;
+    layout.estimatedItemSize = self.KPICollectionView.bounds.size;
+}
+
 - (void)logout {
     [self.shipArray removeAllObjects];
     [self.shipTableView reloadData];
@@ -127,6 +145,13 @@
     return _shipArray;
 }
 
+- (NSMutableArray *)KPIArray {
+    if (!_KPIArray) {
+        _KPIArray = [NSMutableArray array];
+    }
+    return _KPIArray;
+}
+
 - (void)loadData {
 //    NSString *path = [[NSBundle mainBundle] pathForResource:@"fake_container_list.json" ofType:nil];
 //    NSData *data = [[NSData alloc] initWithContentsOfFile:path];
@@ -140,8 +165,10 @@
     __weak typeof(self) weakSelf = self;
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
-        NSDictionary *json = [RANetwork requestHome];
+//        NSDictionary *json = [RANetwork requestHome];
         
+        NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"fake_home.json" ofType:nil]];
+        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
         dispatch_async(dispatch_get_main_queue(), ^{
             
             if (self.refreshControl.isRefreshing) {
@@ -154,10 +181,22 @@
             
             int result = [[json objectForKey:@"result"] intValue];
             if (result == RESULT_TRUE) {
+                
+                self.monthArray = [json objectForKey:@"month"];
+                
                 [self.shipArray removeAllObjects];
                 [self.shipArray addObjectsFromArray:[json objectForKey:@"container_list"]];
                 [self.shipTableView reloadData];
                 
+                [self.KPIArray removeAllObjects];
+                [self.KPIArray addObjectsFromArray:[json objectForKey:@"KPI"]];
+//                NSDictionary *firstItem = [[self.KPIArray objectAtIndex:0] mutableCopy];
+//                NSDictionary *lastItem = [[self.KPIArray lastObject] mutableCopy];
+//                [self.KPIArray addObject:firstItem];
+//                [self.KPIArray insertObject:lastItem atIndex:0];
+                [self.KPICollectionView reloadData];
+//                [self.KPICollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:1 inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
+                
             } else {
                 NSString *msg = [json objectForKey:@"err_msg"];
                 [RAUtils message_alert:msg title:@"Warning" controller:weakSelf];
@@ -190,6 +229,17 @@
     [self loadData];
 }
 
+- (IBAction)modeSegmentClick:(UISegmentedControl *)sender {
+    
+    if (sender.selectedSegmentIndex == 1) {
+        self.shipTableView.hidden = YES;
+        self.KPICollectionView.hidden = NO;
+    } else {
+        self.KPICollectionView.hidden = YES;
+        self.shipTableView.hidden = NO;
+    }
+}
+
 #pragma mark - TableView DataSource && Delegate
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
@@ -293,4 +343,75 @@
 //    return NO;
 //}
 
+#pragma mark - CollectionView DataSource & Delegate
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
+    return 1;
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    return self.KPIArray.count;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    
+    KPICell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:KPI_CELL_IDENTIFIER forIndexPath:indexPath];
+    NSMutableDictionary *item = [[self.KPIArray objectAtIndex:indexPath.item] mutableCopy];
+    [item setObject:self.monthArray forKey:@"month"];
+    [cell setInfoDic:item];
+    cell.delegate = self;
+    return cell;
+}
+
+#pragma mark - FlowLayout Delegate
+
+- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
+    return collectionView.bounds.size;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
+    return 5.0f;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
+    return 5.0f;
+}
+
+#pragma mark - ScrollViewDelegate
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+//    if (scrollView == self.KPICollectionView) {
+//        CGFloat w = scrollView.bounds.size.width;
+//        CGFloat offsetX = scrollView.contentOffset.x;
+//        if (offsetX < w && offsetX >= 0) {
+//            [self.KPICollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:self.KPIArray.count - 2 inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
+//        } else if (offsetX < (self.KPIArray.count * w) && offsetX >= ((self.KPIArray.count - 1) * w)) {
+//            [self.KPICollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:1 inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
+//        }
+//
+//    }
+}
+
+#pragma mark - KPIDelegate
+
+- (void)KPIWillShowPreItem {
+    NSInteger index = [[self.KPICollectionView indexPathsForVisibleItems] firstObject].item;
+    if (index == 0) {
+        index = self.KPIArray.count - 1;
+    } else {
+        index--;
+    }
+    [self.KPICollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
+}
+
+- (void)KPIWillShowNextItem {
+    NSInteger index = [[self.KPICollectionView indexPathsForVisibleItems] firstObject].item;
+    if (index == self.KPIArray.count - 1) {
+        index = 0;
+    } else {
+        index++;
+    }
+    [self.KPICollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
+}
+
 @end

+ 86 - 0
Apex Mobile/Apex Mobile/KPI.json

@@ -0,0 +1,86 @@
+{
+    "name": "Shipment",
+    "total": 13423,
+    "arr_val": [
+             {
+             "title": "P7D",
+                "display":true,
+             "full_title": "Previous 7 Days",
+             "CP_val": "33.2",
+             "A_val": "2201",
+             "color": "0x440000"
+             },
+             {
+                "display":true,
+             "title": "0D",
+             "full_title": "Today",
+             "CP_val": "33.2",
+             "A_val": "325",
+             "color": "0x445500"
+             },
+             {
+             "title": "1D",
+                "display":true,
+             "full_title": "1 Day",
+             "CP_val": "33.2",
+             "A_val": "229",
+             "color": "0x045006"
+             },
+             {
+             "title": "2D",
+                "display":true,
+             "full_title": "2 Days",
+             "CP_val": "33.2",
+             "A_val": "233",
+             "color": "0x44ff66"
+             },
+             {
+             "title": "3D",
+                "display":true,
+             "full_title": "3 Days",
+             "CP_val": "33.2",
+             "A_val": "406",
+             "color": "0x005566"
+             },
+             {
+             "title": "4D",
+                "display":true,
+             "full_title": "4 Days",
+             "CP_val": "33.2",
+             "A_val": "454",
+             "color": "0x000066"
+             },
+             {
+             "title": "5D",
+                "display":true,
+             "full_title": "5 Days",
+             "CP_val": "33.2",
+             "A_val": "325",
+             "color": "0x005500"
+             },
+             {
+             "title": "6D",
+                "display":true,
+             "full_title": "6 Days",
+             "CP_val": "33.2",
+             "A_val": "342",
+             "color": "0x440066"
+             },
+             {
+             "title": "7D",
+                "display":true,
+             "full_title": "7 Days",
+             "CP_val": "33.2",
+             "A_val": "413",
+             "color": "0x4455ff"
+             },
+             {
+                "display":true,
+             "title": "O7D",
+             "full_title": "Over 7 Days",
+             "CP_val": "33.2",
+             "A_val": "8495",
+             "color": "0xff55ff"
+             }
+             ]
+}

+ 13 - 0
Apex Mobile/Apex Mobile/KPIButton.h

@@ -0,0 +1,13 @@
+//
+//  KPIButton.h
+//  Apex Mobile
+//
+//  Created by Jack on 2018/4/8.
+//  Copyright © 2018年 United Software Applications, Inc. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface KPIButton : UIButton
+
+@end

+ 37 - 0
Apex Mobile/Apex Mobile/KPIButton.m

@@ -0,0 +1,37 @@
+//
+//  KPIButton.m
+//  Apex Mobile
+//
+//  Created by Jack on 2018/4/8.
+//  Copyright © 2018年 United Software Applications, Inc. All rights reserved.
+//
+
+#import "KPIButton.h"
+
+
+
+@implementation KPIButton
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+- (CGRect)imageRectForContentRect:(CGRect)contentRect {
+//    CGFloat w = CGRectGetWidth(contentRect);
+    CGFloat h = CGRectGetHeight(contentRect);
+    
+    return CGRectMake(5, (h - 10) * 0.5, 10, 10);
+}
+
+- (CGRect)titleRectForContentRect:(CGRect)contentRect {
+    CGFloat w = CGRectGetWidth(contentRect);
+    CGFloat h = CGRectGetHeight(contentRect);
+    
+    return CGRectMake(20, 0, w - 20, h);
+}
+
+@end

+ 25 - 0
Apex Mobile/Apex Mobile/KPICell.h

@@ -0,0 +1,25 @@
+//
+//  KPICell.h
+//  Apex Mobile
+//
+//  Created by Jack on 2018/4/9.
+//  Copyright © 2018年 United Software Applications, Inc. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@protocol KPIDelegate <NSObject>
+
+@required
+
+- (void)KPIWillShowPreItem;
+- (void)KPIWillShowNextItem;
+
+@end
+
+@interface KPICell : UICollectionViewCell
+
+@property (nonatomic,strong) NSMutableDictionary *infoDic;
+@property (nonatomic,weak) id<KPIDelegate> delegate;
+
+@end

+ 264 - 0
Apex Mobile/Apex Mobile/KPICell.m

@@ -0,0 +1,264 @@
+//
+//  KPICell.m
+//  Apex Mobile
+//
+//  Created by Jack on 2018/4/9.
+//  Copyright © 2018年 United Software Applications, Inc. All rights reserved.
+//
+
+#import "KPICell.h"
+#import "XYPieChartView.h"
+#import "KPIButton.h"
+#import "XYCommon.h"
+
+#define TAG_INDEX 1024
+
+@interface KPICell () <PieChartDelegate>
+
+@property (strong, nonatomic) IBOutlet UILabel *shipmentLB;
+@property (strong, nonatomic) IBOutlet UILabel *containerLB;
+@property (strong, nonatomic) IBOutlet UILabel *teuLB;
+@property (strong, nonatomic) IBOutlet UILabel *TitleLB;
+@property (strong, nonatomic) IBOutlet UILabel *nameLB;
+@property (strong, nonatomic) IBOutlet UILabel *countLB;
+@property (strong, nonatomic) IBOutlet UILabel *percentLB;
+@property (strong, nonatomic) IBOutlet XYPieChartView *KPIView;
+@property (strong, nonatomic) IBOutlet UIView *itemsContainer;
+@property (strong, nonatomic) IBOutlet NSLayoutConstraint *KPIHeightConstraint;
+
+
+@end
+
+@implementation KPICell
+
+- (void)setInfoDic:(NSMutableDictionary *)infoDic {
+    _infoDic = infoDic;
+    [self.KPIView setPieChartData:infoDic];
+    [self reload];
+}
+
+- (void)reload {
+    
+    NSArray *subViews = [self.itemsContainer.subviews mutableCopy];
+    for (UIView *subView in subViews) {
+        [subView removeFromSuperview];
+    }
+    
+    NSArray *month = [self.infoDic objectForKey:@"month"];
+    for (NSDictionary *monthItem in month) {
+        
+        NSString *key = [monthItem objectForKey:@"key"];
+        NSString *val = [monthItem objectForKey:@"val"];
+        NSString *color = [monthItem objectForKey:@"color"];
+        
+        unsigned long fcolor = strtoul([color UTF8String],0,16);
+        UIColor *textColor = UIColorFromRGB(fcolor);
+        
+        if ([key isEqualToString:@"Shipment"]) {
+            
+            self.shipmentLB.text = [NSString stringWithFormat:@"%@:%@",key,val];
+            self.shipmentLB.textColor = textColor;
+            
+        } else if ([key isEqualToString:@"Container"]) {
+            
+            self.containerLB.text = [NSString stringWithFormat:@"%@:%@",key,val];
+            self.containerLB.textColor = textColor;
+            
+        } else if ([key isEqualToString:@"TEU"]) {
+            
+            self.teuLB.text = [NSString stringWithFormat:@"%@:%@",key,val];
+            self.teuLB.textColor = textColor;
+        }
+    }
+    
+//    NSString *name = [self.infoDic objectForKey:@"name"];
+//    self.TitleLB.text = name;
+    
+    NSInteger colCount = 2;
+    CGFloat vInterval = 5.0f, hInterval = 5.0f;
+    CGFloat w = (CGRectGetWidth(self.bounds) - hInterval * (colCount + 1)) / colCount;
+    CGFloat h = 20.0f;
+    
+    NSDictionary *json = _infoDic;
+    NSArray * itemsArr = json[@"arr_val"];
+    
+    for(int i = 0; i < itemsArr.count; i++) {
+        
+        NSMutableDictionary* item = [itemsArr objectAtIndex:i];
+        NSInteger row = i / colCount;
+        NSInteger col = i % colCount;
+        CGRect frame = CGRectMake(hInterval + (w + hInterval) * col, (h + vInterval) * row, w, h);
+        [self createKPIButtonWithItem:item Frame:frame Index:i];
+    }
+    
+    // 刷新加载
+    [self.KPIView reloadChart];
+}
+
+- (void)createKPIButtonWithItem:(NSDictionary *)item Frame:(CGRect)frame Index:(NSInteger)index {
+    
+    NSString* scolor =item[@"color"];
+    BOOL display = [[item objectForKey:@"display"] boolValue];
+    
+    if(scolor==nil)
+        scolor=@"";
+    unsigned long fcolor = strtoul([scolor UTF8String],0,16);
+    UIImage* colordot = [self createImageWithColor:UIColorFromRGB(fcolor)];
+    UIImage *selectedDot = [self createImageWithColor:[UIColor lightGrayColor]];
+    float percent =[item[@"CP_val"] floatValue];
+    
+    
+    KPIButton* btn = [[KPIButton alloc ] initWithFrame: frame];
+    [btn setImage:colordot forState:UIControlStateSelected];
+    [btn setImage:selectedDot forState:UIControlStateNormal];
+    
+    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
+    [btn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
+    
+    [btn setTitle:[NSString stringWithFormat:@"%@(%.2f%%)",item[@"title"],percent] forState:UIControlStateSelected];
+    [btn setTitle:[NSString stringWithFormat:@"%@",item[@"title"]] forState:UIControlStateNormal];
+    
+    btn.titleLabel.font = [UIFont systemFontOfSize:14];
+    btn.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
+    btn.selected = display;
+    btn.tag = TAG_INDEX + index;
+    [btn addTarget:self action:@selector(labelClicked:) forControlEvents:UIControlEventTouchUpInside];
+    
+    
+    [self.itemsContainer addSubview:btn];
+}
+
+- (void)labelClicked:(UIButton *)sender {
+    NSInteger index = sender.tag - TAG_INDEX;
+    NSDictionary *json = _infoDic;
+    NSMutableArray * itemsArr = [json[@"arr_val"] mutableCopy];
+    NSMutableDictionary* item = [itemsArr objectAtIndex:index];
+    
+    sender.selected = !sender.selected;
+    [item setObject:@(sender.selected) forKey:@"display"];
+    [itemsArr replaceObjectAtIndex:index withObject:item];
+    [self.infoDic setObject:itemsArr forKey:@"arr_val"];
+    [self setInfoDic:self.infoDic];
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    
+    // 当有一项数据的百分比小于你所校验的数值时,会将该项数值百分比移出饼图展示(校验数值从0~100)
+    [self.KPIView setCheckLessThanPercent:10];
+    self.KPIView.delegate = self;
+    
+    self.shipmentLB.text = nil;
+    self.containerLB.text = nil;
+    self.teuLB.text = nil;
+    
+    self.TitleLB.text = nil;
+    self.nameLB.text = nil;
+    self.countLB.text = nil;
+    self.percentLB.text = nil;
+    
+    CGFloat w = self.bounds.size.width;
+    CGFloat h = self.bounds.size.height;
+    if (MAX(w, h) <= 568) {
+        self.KPIHeightConstraint.constant = 180;
+        [self layoutIfNeeded];
+    }
+}
+
+#pragma mark - Action
+
+- (IBAction)preItemBtnClick:(UIButton *)sender {
+    if (self.delegate) {
+        [self.delegate KPIWillShowPreItem];
+    }
+}
+
+- (IBAction)nextItemBtnClick:(UIButton *)sender {
+    if (self.delegate) {
+        [self.delegate KPIWillShowNextItem];
+    }
+}
+
+#pragma mark - <选中扇形回调>
+
+- (void)selectedFinish:(XYPieChartView *)pieChartView index:(NSInteger)index selectedType:(NSDictionary *)selectedType {
+    
+//    if(selectedType == nil)
+//    {
+//        self.nameLB.text = nil;
+//        self.countLB.text = nil;
+//        self.percentLB.text = nil;
+//        return;
+//    }
+//    self.nameLB.text = selectedType[@"full_title"];
+    NSLog(@"selected finish");
+    
+}
+-(void) showDetail:(XYPieChartView *)pieChartView index:(NSInteger)index selectedType:(NSDictionary *)selectedType {
+    if(selectedType == nil)
+    {
+        self.nameLB.text = nil;
+        self.countLB.text = nil;
+        self.percentLB.text = nil;
+        return;
+    }
+    
+    self.nameLB.text = selectedType[@"full_title"];
+    self.countLB.text = selectedType[@"A_val"];
+    self.percentLB.text = [NSString stringWithFormat:@"%@%%",selectedType[@"CP_val"]];
+    
+}
+
+#pragma mark - <点击扇形同心圆回调>
+- (void)onCenterClick:(XYPieChartView *)PieChartView {
+    
+    NSLog(@"点击了圆心");
+}
+
+- (void)pieChartView:(XYPieChartView *)chartView didBeginTouch:(NSSet<UITouch *> *)touch {
+//    UIScrollView *scrollView = (UIScrollView *)self.superview;
+//    scrollView.scrollEnabled = NO;
+}
+
+- (void)pieChartView:(XYPieChartView *)chartView didEndTouch:(NSSet<UITouch *> *)touch {
+//    UIScrollView *scrollView = (UIScrollView *)self.superview;
+//    scrollView.scrollEnabled = YES;
+}
+
+#pragma mark - Utils
+
+//生成圆角UIIamge 的方法
+- (UIImage *)imageWithRoundedCornersSize:(float)cornerRadius image:(UIImage*)image
+{
+    UIImage *original = image;
+    CGRect frame = CGRectMake(0, 0, original.size.width, original.size.height);
+    // 开始一个Image的上下文
+    UIGraphicsBeginImageContextWithOptions(original.size, NO, [UIScreen mainScreen].scale);
+    // 添加圆角
+    [[UIBezierPath bezierPathWithRoundedRect:frame
+                                cornerRadius:cornerRadius] addClip];
+    // 绘制图片
+    [original drawInRect:frame];
+    // 接受绘制成功的图片
+    UIImage *rimage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return rimage;
+}
+
+- (UIImage *)createImageWithColor:(UIColor *)color
+{
+    //设置长宽
+    CGRect rect = CGRectMake(0.0f, 0.0f, 10.0f, 10.0f);
+    UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    CGContextSetFillColorWithColor(context, [color CGColor]);
+    CGContextFillRect(context, rect);
+    UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    
+    return [self imageWithRoundedCornersSize:5 image:resultImage];
+    //    return resultImage;
+}
+
+@end

+ 25 - 0
Apex Mobile/Apex Mobile/KPIPieChartCell.h

@@ -0,0 +1,25 @@
+//
+//  KPIPieChartCell.h
+//  Apex Mobile
+//
+//  Created by Jack on 2018/4/8.
+//  Copyright © 2018年 United Software Applications, Inc. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@protocol KPIPieChartDelegate <NSObject>
+
+@required
+// Animation
+- (void)pieChartAnimationBegin;
+- (void)pieChartAnimationEnd;
+
+@end
+
+@interface KPIPieChartCell : UITableViewCell
+
+@property (nonatomic,weak) id <KPIPieChartDelegate> delegate;
+@property (nonatomic,strong) NSMutableDictionary *infoDic;
+
+@end

+ 255 - 0
Apex Mobile/Apex Mobile/KPIPieChartCell.m

@@ -0,0 +1,255 @@
+//
+//  KPIPieChartCell.m
+//  Apex Mobile
+//
+//  Created by Jack on 2018/4/8.
+//  Copyright © 2018年 United Software Applications, Inc. All rights reserved.
+//
+
+#import "KPIPieChartCell.h"
+#import "XYPieChartView.h"
+#import "XYCommon.h"
+#import "KPIButton.h"
+
+#define TAG_INDEX 1024
+
+@interface KPIPieChartCell () <PieChartDelegate>
+
+@property (strong, nonatomic) IBOutlet UILabel *selectedTitleLabel;
+@property (strong, nonatomic) IBOutlet UILabel *selectedValueLabel;
+@property (strong, nonatomic) IBOutlet UILabel *selectedPercentLabel;
+@property (strong, nonatomic) IBOutlet XYPieChartView *pieChartView;
+@property (strong, nonatomic) IBOutlet UIView *ItemContainerView;
+@property (strong, nonatomic) IBOutlet UIView *BottomItemContainer;
+
+
+@end
+
+@implementation KPIPieChartCell
+
+- (void)setInfoDic:(NSMutableDictionary *)infoDic {
+    _infoDic = infoDic;
+    [self.pieChartView setPieChartData:infoDic];
+    [self reload];
+}
+
+- (void)reload {
+    
+    NSArray *subViews = [self.ItemContainerView.subviews mutableCopy];
+    for (UIView *subView in subViews) {
+        [subView removeFromSuperview];
+    }
+    
+    NSArray *bottomSubViews = [self.BottomItemContainer.subviews mutableCopy];
+    for (UIView *subView in bottomSubViews) {
+        [subView removeFromSuperview];
+    }
+    
+    CGFloat w = (CGRectGetWidth(self.bounds) - 5.0 * 4) / 3;
+    CGFloat h = 20.0f;
+    
+    NSDictionary *json = _infoDic;
+    NSArray * itemsArr = json[@"arr_val"];
+    
+    NSInteger row = 0, col = 0;
+    // left
+    CGFloat rowH = 5.0f + h; // 每行间隙最小为5
+    CGFloat leftH = 210.0f;
+    NSInteger leftRow = (NSInteger)(leftH / rowH);
+    CGFloat vInterval = (leftH - (20.f * leftRow)) / leftRow;
+    
+    for(int i = 0; i < itemsArr.count; i++)
+    {
+        NSMutableDictionary* item = [itemsArr objectAtIndex:i];
+        CGRect frame = CGRectZero;
+        BOOL bottom = NO;
+        if (i < leftRow) {
+            frame = CGRectMake(0, (vInterval + h) * i, w, h);
+            bottom = NO;
+        } else {
+            bottom = YES;
+            row = (i - leftRow) / 3;
+            col = (i - leftRow) % 3;
+            frame = CGRectMake((w + 5.0f) * col, (h + vInterval) * row, w, h);
+        }
+        [self createKPIButtonWithItem:item Frame:frame Index:i InBottom:bottom];
+        
+    }
+    
+    // 刷新加载
+    [self.pieChartView reloadChart];
+}
+
+- (void)createKPIButtonWithItem:(NSDictionary *)item Frame:(CGRect)frame Index:(NSInteger)index InBottom:(BOOL)bottom {
+    
+    NSString* scolor =item[@"color"];
+    BOOL display = [[item objectForKey:@"display"] boolValue];
+    
+    if(scolor==nil)
+        scolor=@"";
+    unsigned long fcolor = strtoul([scolor UTF8String],0,16);
+    UIImage* colordot = [self createImageWithColor:UIColorFromRGB(fcolor)];
+    UIImage *selectedDot = [self createImageWithColor:[UIColor lightGrayColor]];
+    float percent =[item[@"CP_val"] floatValue];
+    
+    
+    KPIButton* btn = [[KPIButton alloc ] initWithFrame: frame];
+    [btn setImage:colordot forState:UIControlStateSelected];
+    [btn setImage:selectedDot forState:UIControlStateNormal];
+    
+    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
+    [btn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
+    
+    [btn setTitle:[NSString stringWithFormat:@"%@(%.2f%%)",item[@"title"],percent] forState:UIControlStateSelected];
+    [btn setTitle:[NSString stringWithFormat:@"%@",item[@"title"]] forState:UIControlStateNormal];
+    
+    btn.titleLabel.font = [UIFont systemFontOfSize:14];
+    btn.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
+    btn.selected = display;
+    btn.tag = TAG_INDEX + index;
+    [btn addTarget:self action:@selector(labelClicked:) forControlEvents:UIControlEventTouchUpInside];
+    
+    
+    if (bottom) {
+        [self.BottomItemContainer addSubview:btn];
+    } else {
+        [self.ItemContainerView addSubview:btn];
+    }
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    
+    // 当有一项数据的百分比小于你所校验的数值时,会将该项数值百分比移出饼图展示(校验数值从0~100)
+    [self.pieChartView setCheckLessThanPercent:10];
+    self.pieChartView.delegate = self;
+    
+    self.selectedTitleLabel.text = nil;
+    self.selectedValueLabel.text = nil;
+    self.selectedPercentLabel.text = nil;
+    
+}
+
+- (void)prepareForReuse {
+    [super prepareForReuse];
+    
+//    self.infoDic = nil;
+}
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+- (void)labelClicked:(UIButton *)sender {
+    NSInteger index = sender.tag - TAG_INDEX;
+    NSDictionary *json = _infoDic;
+    NSMutableArray * itemsArr = [json[@"arr_val"] mutableCopy];
+    NSMutableDictionary* item = [itemsArr objectAtIndex:index];
+    
+    sender.selected = !sender.selected;
+    [item setObject:@(sender.selected) forKey:@"display"];
+    [itemsArr replaceObjectAtIndex:index withObject:item];
+    [self.infoDic setObject:itemsArr forKey:@"arr_val"];
+    [self setInfoDic:self.infoDic];
+}
+
+#pragma mark - <选中扇形回调>
+
+- (void)selectedFinish:(XYPieChartView *)pieChartView index:(NSInteger)index selectedType:(NSDictionary *)selectedType {
+    
+//    if(selectedType == nil)
+//    {
+//        self.selectedTitleLabel.text = nil;
+//        self.selectedValueLabel.text=nil;
+//        self.selectedPercentLabel.text=nil;
+//        return;
+//    }
+//    self.titlelabel.text = selectedType[@"full_title"];
+    NSLog(@"selected finish");
+    
+}
+-(void) showDetail:(XYPieChartView *)pieChartView index:(NSInteger)index selectedType:(NSDictionary *)selectedType {
+    if(selectedType == nil)
+    {
+        self.selectedTitleLabel.text = nil;
+        self.selectedValueLabel.text = nil;
+        self.selectedPercentLabel.text = nil;
+        return;
+    }
+    
+    self.selectedTitleLabel.text = selectedType[@"full_title"];
+    self.selectedValueLabel.text = selectedType[@"A_val"];
+    self.selectedPercentLabel.text = [NSString stringWithFormat:@"%@%%",selectedType[@"CP_val"]];
+    
+}
+
+#pragma mark - <点击扇形同心圆回调>
+- (void)onCenterClick:(XYPieChartView *)PieChartView {
+    
+    NSLog(@"点击了圆心");
+}
+
+- (void)pieChartView:(XYPieChartView *)chartView didBeginTouch:(NSSet<UITouch *> *)touch {
+    UIScrollView *scrollView = (UIScrollView *)self.superview;
+    scrollView.scrollEnabled = NO;
+}
+
+- (void)pieChartView:(XYPieChartView *)chartView didEndTouch:(NSSet<UITouch *> *)touch {
+    UIScrollView *scrollView = (UIScrollView *)self.superview;
+    scrollView.scrollEnabled = YES;
+}
+
+#pragma mark - Animation
+
+- (void)pieChartAnimationBegin {
+    if (self.delegate) {
+        [self.delegate pieChartAnimationBegin];
+    }
+}
+
+- (void)pieChartAnimationEnd {
+    if (self.delegate) {
+        [self.delegate pieChartAnimationEnd];
+    }
+}
+
+
+#pragma mark - Utils
+
+//生成圆角UIIamge 的方法
+- (UIImage *)imageWithRoundedCornersSize:(float)cornerRadius image:(UIImage*)image
+{
+    UIImage *original = image;
+    CGRect frame = CGRectMake(0, 0, original.size.width, original.size.height);
+    // 开始一个Image的上下文
+    UIGraphicsBeginImageContextWithOptions(original.size, NO, [UIScreen mainScreen].scale);
+    // 添加圆角
+    [[UIBezierPath bezierPathWithRoundedRect:frame
+                                cornerRadius:cornerRadius] addClip];
+    // 绘制图片
+    [original drawInRect:frame];
+    // 接受绘制成功的图片
+    UIImage *rimage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return rimage;
+}
+
+- (UIImage *)createImageWithColor:(UIColor *)color
+{
+    //设置长宽
+    CGRect rect = CGRectMake(0.0f, 0.0f, 10.0f, 10.0f);
+    UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    CGContextSetFillColorWithColor(context, [color CGColor]);
+    CGContextFillRect(context, rect);
+    UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    
+    return [self imageWithRoundedCornersSize:5 image:resultImage];
+    //    return resultImage;
+}
+
+@end

+ 94 - 0
Apex Mobile/Apex Mobile/KPIPieChartCell.xib

@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" rowHeight="230" id="KGk-i7-Jjw" customClass="KPIPieChartCell">
+            <rect key="frame" x="0.0" y="0.0" width="421" height="250"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
+                <rect key="frame" x="0.0" y="0.0" width="421" height="249.5"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bUH-aT-onx">
+                        <rect key="frame" x="256" y="10.5" width="33.5" height="19.5"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                        <nil key="textColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Value" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ihL-pf-MFr">
+                        <rect key="frame" x="299.5" y="10.5" width="42" height="19.5"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                        <nil key="textColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Percent" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="L9E-CI-ZE7">
+                        <rect key="frame" x="351.5" y="10" width="59.5" height="19.5"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="19.5" id="4nc-Oj-peT"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                        <nil key="textColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Yzt-NO-VtB" customClass="XYPieChartView">
+                        <rect key="frame" x="211" y="39.5" width="200" height="200"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="200" id="GR5-uq-9cH"/>
+                            <constraint firstAttribute="width" constant="200" id="Ymq-RE-sMB"/>
+                        </constraints>
+                    </view>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qlx-3l-Usv">
+                        <rect key="frame" x="10" y="249.5" width="401" height="0.0"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </view>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iI1-qR-quK">
+                        <rect key="frame" x="10" y="40" width="191" height="209.5"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstItem="qlx-3l-Usv" firstAttribute="trailing" secondItem="Yzt-NO-VtB" secondAttribute="trailing" id="32V-c0-tJC"/>
+                    <constraint firstItem="iI1-qR-quK" firstAttribute="top" secondItem="Yzt-NO-VtB" secondAttribute="top" id="4de-ZS-jZY"/>
+                    <constraint firstItem="bUH-aT-onx" firstAttribute="centerY" secondItem="ihL-pf-MFr" secondAttribute="centerY" id="OCl-HQ-Bcv"/>
+                    <constraint firstItem="Yzt-NO-VtB" firstAttribute="leading" secondItem="iI1-qR-quK" secondAttribute="trailing" constant="10" id="QtE-VA-bBI"/>
+                    <constraint firstItem="iI1-qR-quK" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="10" id="Sbt-rP-vEF"/>
+                    <constraint firstItem="qlx-3l-Usv" firstAttribute="top" secondItem="iI1-qR-quK" secondAttribute="bottom" id="U1S-Dt-Lcu"/>
+                    <constraint firstItem="Yzt-NO-VtB" firstAttribute="trailing" secondItem="L9E-CI-ZE7" secondAttribute="trailing" id="VWY-4R-vic"/>
+                    <constraint firstItem="qlx-3l-Usv" firstAttribute="leading" secondItem="iI1-qR-quK" secondAttribute="leading" id="Yk1-dd-MYf"/>
+                    <constraint firstItem="iI1-qR-quK" firstAttribute="bottom" secondItem="Yzt-NO-VtB" secondAttribute="bottom" constant="10" id="acx-JR-2Lt"/>
+                    <constraint firstItem="ihL-pf-MFr" firstAttribute="centerY" secondItem="L9E-CI-ZE7" secondAttribute="centerY" id="bfE-Jm-A4M"/>
+                    <constraint firstItem="bUH-aT-onx" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="10" id="ep9-Fa-awg"/>
+                    <constraint firstItem="ihL-pf-MFr" firstAttribute="height" secondItem="L9E-CI-ZE7" secondAttribute="height" id="eqP-OW-WHY"/>
+                    <constraint firstItem="L9E-CI-ZE7" firstAttribute="leading" secondItem="ihL-pf-MFr" secondAttribute="trailing" constant="10" id="eqa-AN-EMd"/>
+                    <constraint firstItem="Yzt-NO-VtB" firstAttribute="top" secondItem="L9E-CI-ZE7" secondAttribute="bottom" constant="10" id="hBO-nn-dep"/>
+                    <constraint firstAttribute="bottom" secondItem="qlx-3l-Usv" secondAttribute="bottom" id="l5P-Hk-cMl"/>
+                    <constraint firstAttribute="trailing" secondItem="L9E-CI-ZE7" secondAttribute="trailing" constant="10" id="m39-rS-KWH"/>
+                    <constraint firstItem="L9E-CI-ZE7" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="ngh-Gn-och"/>
+                    <constraint firstItem="ihL-pf-MFr" firstAttribute="leading" secondItem="bUH-aT-onx" secondAttribute="trailing" constant="10" id="vYp-OT-FYP"/>
+                    <constraint firstItem="bUH-aT-onx" firstAttribute="height" secondItem="ihL-pf-MFr" secondAttribute="height" id="z0d-DO-VS8"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
+            <connections>
+                <outlet property="BottomItemContainer" destination="qlx-3l-Usv" id="tNu-I4-bwP"/>
+                <outlet property="ItemContainerView" destination="iI1-qR-quK" id="0Qi-Hx-FFZ"/>
+                <outlet property="pieChartView" destination="Yzt-NO-VtB" id="hBU-KH-ODr"/>
+                <outlet property="selectedPercentLabel" destination="L9E-CI-ZE7" id="2oj-jd-4su"/>
+                <outlet property="selectedTitleLabel" destination="bUH-aT-onx" id="zNF-Yx-UBx"/>
+                <outlet property="selectedValueLabel" destination="ihL-pf-MFr" id="Sy3-M0-sFq"/>
+            </connections>
+            <point key="canvasLocation" x="-70.5" y="-55.5"/>
+        </tableViewCell>
+    </objects>
+</document>

+ 199 - 19
Apex Mobile/Apex Mobile/Main.storyboard

@@ -6,6 +6,8 @@
     <dependencies>
         <deployment version="2304" identifier="iOS"/>
         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
+        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
+        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -286,8 +288,156 @@
                         <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
+                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" bouncesZoom="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="BMV-js-RbK">
+                                <rect key="frame" x="0.0" y="94" width="375" height="524"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="bgx-ah-Ujy">
+                                    <size key="itemSize" width="374" height="527"/>
+                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                </collectionViewFlowLayout>
+                                <cells>
+                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="KPICell" id="hOk-Q6-U2Y" customClass="KPICell">
+                                        <rect key="frame" x="0.0" y="-1.5" width="374" height="527"/>
+                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
+                                            <rect key="frame" x="0.0" y="0.0" width="374" height="527"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shipment:5868" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HR2-MW-QBD">
+                                                    <rect key="frame" x="0.0" y="31" width="113" height="19.5"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="19.5" id="hDC-6j-Te0"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="TEU:16436" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SiU-f3-vg5">
+                                                    <rect key="frame" x="237" y="31" width="82" height="19.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Fzk-UY-Jay">
+                                                    <rect key="frame" x="0.0" y="287" width="374" height="240"/>
+                                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                </view>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="7 Days" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="a70-xK-8Gt">
+                                                    <rect key="frame" x="220.5" y="57.5" width="49" height="19.5"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="19.5" id="77T-V5-J6j"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This Month" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TdU-EN-0bl">
+                                                    <rect key="frame" x="5" y="8" width="86" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Container:9035" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5BU-lo-4qt">
+                                                    <rect key="frame" x="118" y="31" width="114" height="19.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3855" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZTm-4z-LAb">
+                                                    <rect key="frame" x="274.5" y="57.5" width="39" height="19.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="48.5%" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nqS-Pj-374">
+                                                    <rect key="frame" x="318.5" y="57.5" width="45.5" height="19.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aTr-Mi-Mg3" customClass="XYPieChartView">
+                                                    <rect key="frame" x="87" y="82" width="200" height="200"/>
+                                                    <color key="backgroundColor" red="0.31186315860000002" green="0.73688559149999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" secondItem="aTr-Mi-Mg3" secondAttribute="height" multiplier="1:1" id="Huw-mu-fRN"/>
+                                                        <constraint firstAttribute="height" constant="200" id="VQp-Nn-Hkb"/>
+                                                    </constraints>
+                                                </view>
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5at-hb-Z6F">
+                                                    <rect key="frame" x="5" y="82" width="30" height="200"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="30" id="zSs-uv-rnc"/>
+                                                    </constraints>
+                                                    <state key="normal" image="preItem"/>
+                                                    <connections>
+                                                        <action selector="preItemBtnClick:" destination="hOk-Q6-U2Y" eventType="touchUpInside" id="LlV-0C-94q"/>
+                                                    </connections>
+                                                </button>
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NEW-gP-kfO">
+                                                    <rect key="frame" x="339" y="82" width="30" height="200"/>
+                                                    <state key="normal" image="nextItem"/>
+                                                    <connections>
+                                                        <action selector="nextItemBtnClick:" destination="hOk-Q6-U2Y" eventType="touchUpInside" id="jah-g3-sSG"/>
+                                                    </connections>
+                                                </button>
+                                            </subviews>
+                                        </view>
+                                        <constraints>
+                                            <constraint firstItem="nqS-Pj-374" firstAttribute="leading" secondItem="ZTm-4z-LAb" secondAttribute="trailing" constant="5" id="0x8-cx-doQ"/>
+                                            <constraint firstItem="ZTm-4z-LAb" firstAttribute="leading" secondItem="a70-xK-8Gt" secondAttribute="trailing" constant="5" id="1WX-Hv-nRD"/>
+                                            <constraint firstAttribute="bottom" secondItem="Fzk-UY-Jay" secondAttribute="bottom" id="1Y6-qV-4be"/>
+                                            <constraint firstAttribute="trailing" secondItem="Fzk-UY-Jay" secondAttribute="trailing" id="4ue-Uk-9c4"/>
+                                            <constraint firstItem="TdU-EN-0bl" firstAttribute="top" secondItem="hOk-Q6-U2Y" secondAttribute="topMargin" id="8Dy-Pp-5Km"/>
+                                            <constraint firstItem="NEW-gP-kfO" firstAttribute="top" secondItem="aTr-Mi-Mg3" secondAttribute="top" id="9xq-aY-fVG"/>
+                                            <constraint firstItem="HR2-MW-QBD" firstAttribute="top" secondItem="TdU-EN-0bl" secondAttribute="bottom" constant="2" id="E4C-4y-I88"/>
+                                            <constraint firstItem="5at-hb-Z6F" firstAttribute="leading" secondItem="hOk-Q6-U2Y" secondAttribute="leading" constant="5" id="FoZ-9C-sc9"/>
+                                            <constraint firstItem="SiU-f3-vg5" firstAttribute="height" secondItem="5BU-lo-4qt" secondAttribute="height" id="HDa-AP-k8s"/>
+                                            <constraint firstItem="NEW-gP-kfO" firstAttribute="bottom" secondItem="aTr-Mi-Mg3" secondAttribute="bottom" id="IF9-dO-PCB"/>
+                                            <constraint firstItem="nqS-Pj-374" firstAttribute="top" secondItem="SiU-f3-vg5" secondAttribute="bottom" constant="7" id="K1A-lf-3l3"/>
+                                            <constraint firstItem="aTr-Mi-Mg3" firstAttribute="centerX" secondItem="hOk-Q6-U2Y" secondAttribute="centerX" id="NJD-sL-lZu"/>
+                                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="SiU-f3-vg5" secondAttribute="trailing" id="Oqq-Mo-cDQ"/>
+                                            <constraint firstItem="nqS-Pj-374" firstAttribute="height" secondItem="ZTm-4z-LAb" secondAttribute="height" id="P83-8U-2dM"/>
+                                            <constraint firstItem="NEW-gP-kfO" firstAttribute="width" secondItem="5at-hb-Z6F" secondAttribute="width" id="Pt4-h9-f63"/>
+                                            <constraint firstItem="TdU-EN-0bl" firstAttribute="leading" secondItem="hOk-Q6-U2Y" secondAttribute="leading" constant="5" id="RCu-sb-u2d"/>
+                                            <constraint firstItem="5BU-lo-4qt" firstAttribute="centerY" secondItem="HR2-MW-QBD" secondAttribute="centerY" id="aJp-oe-BEb"/>
+                                            <constraint firstItem="ZTm-4z-LAb" firstAttribute="centerY" secondItem="a70-xK-8Gt" secondAttribute="centerY" id="b4F-fq-tih"/>
+                                            <constraint firstItem="HR2-MW-QBD" firstAttribute="leading" secondItem="hOk-Q6-U2Y" secondAttribute="leading" id="c5e-3z-YkJ"/>
+                                            <constraint firstItem="SiU-f3-vg5" firstAttribute="centerY" secondItem="5BU-lo-4qt" secondAttribute="centerY" id="cUe-lI-M8w"/>
+                                            <constraint firstItem="5BU-lo-4qt" firstAttribute="height" secondItem="HR2-MW-QBD" secondAttribute="height" id="epV-Od-GWW"/>
+                                            <constraint firstItem="Fzk-UY-Jay" firstAttribute="top" secondItem="aTr-Mi-Mg3" secondAttribute="bottom" constant="5" id="jpV-Oc-1y7"/>
+                                            <constraint firstAttribute="trailing" secondItem="nqS-Pj-374" secondAttribute="trailing" constant="10" id="lhw-nz-wbA"/>
+                                            <constraint firstItem="5at-hb-Z6F" firstAttribute="bottom" secondItem="aTr-Mi-Mg3" secondAttribute="bottom" id="nie-Ua-1Nc"/>
+                                            <constraint firstItem="ZTm-4z-LAb" firstAttribute="height" secondItem="a70-xK-8Gt" secondAttribute="height" id="nl5-T3-U8t"/>
+                                            <constraint firstItem="nqS-Pj-374" firstAttribute="centerY" secondItem="ZTm-4z-LAb" secondAttribute="centerY" id="oIx-OR-2oK"/>
+                                            <constraint firstItem="Fzk-UY-Jay" firstAttribute="leading" secondItem="hOk-Q6-U2Y" secondAttribute="leading" id="qeg-tq-EXd"/>
+                                            <constraint firstItem="aTr-Mi-Mg3" firstAttribute="top" secondItem="a70-xK-8Gt" secondAttribute="bottom" constant="5" id="t98-6j-bka"/>
+                                            <constraint firstItem="5at-hb-Z6F" firstAttribute="top" secondItem="aTr-Mi-Mg3" secondAttribute="top" id="tTr-R5-M9c"/>
+                                            <constraint firstItem="5BU-lo-4qt" firstAttribute="leading" secondItem="HR2-MW-QBD" secondAttribute="trailing" constant="5" id="xRF-a6-woN"/>
+                                            <constraint firstAttribute="trailing" secondItem="NEW-gP-kfO" secondAttribute="trailing" constant="5" id="yZV-ui-z0C"/>
+                                            <constraint firstItem="SiU-f3-vg5" firstAttribute="leading" secondItem="5BU-lo-4qt" secondAttribute="trailing" constant="5" id="ydy-jS-Fh6"/>
+                                        </constraints>
+                                        <connections>
+                                            <outlet property="KPIHeightConstraint" destination="VQp-Nn-Hkb" id="Mkc-e4-eDe"/>
+                                            <outlet property="KPIView" destination="aTr-Mi-Mg3" id="vVK-Al-vdn"/>
+                                            <outlet property="containerLB" destination="5BU-lo-4qt" id="oEX-rp-eq2"/>
+                                            <outlet property="countLB" destination="ZTm-4z-LAb" id="qWj-zE-3Nv"/>
+                                            <outlet property="itemsContainer" destination="Fzk-UY-Jay" id="Ywd-mh-Ztp"/>
+                                            <outlet property="nameLB" destination="a70-xK-8Gt" id="bLJ-Xt-ca1"/>
+                                            <outlet property="percentLB" destination="nqS-Pj-374" id="tXU-zD-s2Q"/>
+                                            <outlet property="shipmentLB" destination="HR2-MW-QBD" id="Wxb-do-sCz"/>
+                                            <outlet property="teuLB" destination="SiU-f3-vg5" id="9Pn-rA-bkJ"/>
+                                        </connections>
+                                    </collectionViewCell>
+                                </cells>
+                                <connections>
+                                    <outlet property="dataSource" destination="ucJ-C2-JJ8" id="AFv-ml-oCs"/>
+                                    <outlet property="delegate" destination="ucJ-C2-JJ8" id="gT6-zp-Mu8"/>
+                                </connections>
+                            </collectionView>
                             <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="iIl-j9-7oa">
-                                <rect key="frame" x="0.0" y="50" width="375" height="568"/>
+                                <rect key="frame" x="0.0" y="94" width="375" height="524"/>
                                 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                                 <inset key="separatorInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                                 <connections>
@@ -296,13 +446,13 @@
                                 </connections>
                             </tableView>
                             <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RDS-rb-8d8">
-                                <rect key="frame" x="64.5" y="304" width="245" height="60"/>
+                                <rect key="frame" x="64.5" y="326" width="245" height="60"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="60" id="71k-hL-Hln"/>
                                     <constraint firstAttribute="width" constant="245" id="I9Y-XO-Wcn"/>
                                 </constraints>
                                 <fontDescription key="fontDescription" type="system" pointSize="20"/>
-                                <state key="normal" title="No Recent Tracking Record">
+                                <state key="normal" title="No Data">
                                     <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
                                 </state>
                                 <state key="highlighted">
@@ -313,20 +463,25 @@
                                 </connections>
                             </button>
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3xo-DP-qWN">
-                                <rect key="frame" x="0.0" y="20" width="375" height="30"/>
+                                <rect key="frame" x="0.0" y="64" width="375" height="30"/>
                                 <subviews>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Recent" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ouQ-Yg-iZI">
-                                        <rect key="frame" x="10" y="5" width="54" height="21"/>
-                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
+                                    <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="6ie-Rf-Nau">
+                                        <rect key="frame" x="0.0" y="0.0" width="375" height="31"/>
+                                        <segments>
+                                            <segment title="Recent"/>
+                                            <segment title="KPI"/>
+                                        </segments>
+                                        <connections>
+                                            <action selector="modeSegmentClick:" destination="ucJ-C2-JJ8" eventType="valueChanged" id="IfB-dt-avx"/>
+                                        </connections>
+                                    </segmentedControl>
                                 </subviews>
-                                <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
                                 <constraints>
-                                    <constraint firstItem="ouQ-Yg-iZI" firstAttribute="centerY" secondItem="3xo-DP-qWN" secondAttribute="centerY" id="LEb-qr-SVl"/>
-                                    <constraint firstItem="ouQ-Yg-iZI" firstAttribute="leading" secondItem="3xo-DP-qWN" secondAttribute="leading" constant="10" id="PPM-oF-8FH"/>
+                                    <constraint firstAttribute="trailing" secondItem="6ie-Rf-Nau" secondAttribute="trailing" id="P0l-RC-5fs"/>
                                     <constraint firstAttribute="height" constant="30" id="bFZ-hk-yg5"/>
+                                    <constraint firstItem="6ie-Rf-Nau" firstAttribute="leading" secondItem="3xo-DP-qWN" secondAttribute="leading" id="pnN-ct-5IP"/>
+                                    <constraint firstAttribute="bottom" secondItem="6ie-Rf-Nau" secondAttribute="bottom" id="ufs-EU-z70"/>
+                                    <constraint firstItem="6ie-Rf-Nau" firstAttribute="top" secondItem="3xo-DP-qWN" secondAttribute="top" id="wFw-qc-77U"/>
                                 </constraints>
                             </view>
                             <activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="WyF-Pl-7ix">
@@ -340,10 +495,14 @@
                             <constraint firstItem="WyF-Pl-7ix" firstAttribute="centerX" secondItem="ifC-vl-u6I" secondAttribute="centerX" id="0Dt-hM-q3g"/>
                             <constraint firstItem="3xo-DP-qWN" firstAttribute="top" secondItem="70L-ql-L3f" secondAttribute="bottom" id="7dN-EO-3Yh"/>
                             <constraint firstItem="iIl-j9-7oa" firstAttribute="trailing" secondItem="ifC-vl-u6I" secondAttribute="trailing" id="9jR-8W-zYM"/>
+                            <constraint firstItem="BMV-js-RbK" firstAttribute="top" secondItem="3xo-DP-qWN" secondAttribute="bottom" id="CCx-SX-Rkz"/>
                             <constraint firstAttribute="trailing" secondItem="3xo-DP-qWN" secondAttribute="trailing" id="Gvc-tU-QdZ"/>
                             <constraint firstItem="iIl-j9-7oa" firstAttribute="top" secondItem="3xo-DP-qWN" secondAttribute="bottom" id="JZI-44-qDk"/>
                             <constraint firstItem="RDS-rb-8d8" firstAttribute="centerX" secondItem="iIl-j9-7oa" secondAttribute="centerX" id="Ta8-8u-MVg"/>
+                            <constraint firstItem="6yV-PD-KCp" firstAttribute="top" secondItem="BMV-js-RbK" secondAttribute="bottom" id="cln-1K-IE0"/>
+                            <constraint firstItem="BMV-js-RbK" firstAttribute="leading" secondItem="ifC-vl-u6I" secondAttribute="leading" id="d5k-6n-t6t"/>
                             <constraint firstItem="WyF-Pl-7ix" firstAttribute="centerY" secondItem="ifC-vl-u6I" secondAttribute="centerY" id="ga0-M2-tYJ"/>
+                            <constraint firstAttribute="trailing" secondItem="BMV-js-RbK" secondAttribute="trailing" id="jnX-4Q-CQl"/>
                             <constraint firstItem="iIl-j9-7oa" firstAttribute="leading" secondItem="ifC-vl-u6I" secondAttribute="leading" id="lPc-7m-bBJ"/>
                             <constraint firstItem="3xo-DP-qWN" firstAttribute="leading" secondItem="ifC-vl-u6I" secondAttribute="leading" id="mui-fH-ZHN"/>
                             <constraint firstItem="iIl-j9-7oa" firstAttribute="bottom" secondItem="6yV-PD-KCp" secondAttribute="top" id="nZz-HM-ESm"/>
@@ -351,16 +510,35 @@
                         </constraints>
                     </view>
                     <tabBarItem key="tabBarItem" title="Home" image="tab_home" id="OC9-MV-8nf"/>
+                    <navigationItem key="navigationItem" id="giR-co-TyJ"/>
                     <simulatedTabBarMetrics key="simulatedBottomBarMetrics"/>
                     <connections>
+                        <outlet property="KPICollectionView" destination="BMV-js-RbK" id="19x-Mk-965"/>
                         <outlet property="emptyBtn" destination="RDS-rb-8d8" id="Hvx-vb-hoW"/>
                         <outlet property="loadIndicator" destination="WyF-Pl-7ix" id="smN-0v-oSv"/>
+                        <outlet property="segmentControl" destination="6ie-Rf-Nau" id="q6N-98-j6F"/>
                         <outlet property="shipTableView" destination="iIl-j9-7oa" id="vsk-WU-ScI"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="Smq-yU-AsP" userLabel="First Responder" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="657" y="1047"/>
+            <point key="canvasLocation" x="1141.5999999999999" y="1046.6266866566718"/>
+        </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="KXC-qa-Wld">
+            <objects>
+                <navigationController id="gyT-VU-jPB" sceneMemberID="viewController">
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="khw-eC-lAN">
+                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                    </navigationBar>
+                    <connections>
+                        <segue destination="ucJ-C2-JJ8" kind="relationship" relationship="rootViewController" id="ZQi-kb-0Bk"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="BEV-vx-WPF" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="273" y="1047"/>
         </scene>
         <!--Tools-->
         <scene sceneID="xt7-Ft-PVv">
@@ -1653,7 +1831,7 @@
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fv6-ui-cri">
-                                                    <rect key="frame" x="15" y="8" width="345" height="28"/>
+                                                    <rect key="frame" x="15" y="8" width="345" height="29"/>
                                                     <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                                     <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                     <nil key="highlightedColor"/>
@@ -1699,7 +1877,7 @@
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <webView contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="a2k-TN-pCa">
-                                                    <rect key="frame" x="0.0" y="0.0" width="375" height="163"/>
+                                                    <rect key="frame" x="0.0" y="0.0" width="375" height="164"/>
                                                     <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                                     <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                     <dataDetectorType key="dataDetectorTypes" link="YES"/>
@@ -1721,18 +1899,18 @@
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FbJ-O5-B1Q" customClass="LineView">
-                                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                                    <rect key="frame" x="0.0" y="0.0" width="375" height="45"/>
                                                     <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                                     <subviews>
                                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Vu-9P-I7w" customClass="MDHTMLLabel">
-                                                            <rect key="frame" x="158" y="8" width="209" height="28"/>
+                                                            <rect key="frame" x="158" y="8" width="209" height="29"/>
                                                             <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" heightSizable="YES"/>
                                                             <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                             <nil key="textColor"/>
                                                             <nil key="highlightedColor"/>
                                                         </label>
                                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vER-xh-qBc" customClass="MDHTMLLabel">
-                                                            <rect key="frame" x="8" y="8" width="134" height="28"/>
+                                                            <rect key="frame" x="8" y="8" width="134" height="29"/>
                                                             <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
                                                             <fontDescription key="fontDescription" type="boldSystem" pointSize="13"/>
                                                             <nil key="textColor"/>
@@ -1787,6 +1965,8 @@
         <image name="ic_pdf128" width="48" height="48"/>
         <image name="ic_setting" width="30" height="30"/>
         <image name="map (1)" width="32" height="32"/>
+        <image name="nextItem" width="30" height="100"/>
+        <image name="preItem" width="30" height="100"/>
         <image name="rect_market_news" width="48" height="48"/>
         <image name="tab_history" width="30" height="30"/>
         <image name="tab_home" width="30" height="30"/>

+ 23 - 0
Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "nextItem.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "nextItem@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "nextItem@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/nextItem.png


BIN
Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/nextItem@2x.png


BIN
Apex Mobile/Apex Mobile/NewImages.xcassets/nextItem.imageset/nextItem@3x.png


+ 23 - 0
Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "preItem.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "preItem@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "preItem@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/preItem.png


BIN
Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/preItem@2x.png


BIN
Apex Mobile/Apex Mobile/NewImages.xcassets/preItem.imageset/preItem@3x.png


+ 6 - 0
Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 21 - 0
Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/center_white.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "center_white.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/center_white.imageset/center_white.png


+ 23 - 0
Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "dot.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "dot@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "dot@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/dot.png


BIN
Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/dot@2x.png


BIN
Apex Mobile/Apex Mobile/PieChart/PieChart.xcassets/dot.imageset/dot@3x.png


+ 29 - 0
Apex Mobile/Apex Mobile/PieChart/XYCommon.h

@@ -0,0 +1,29 @@
+//
+//  XYCommon.h
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#define ScreenWidth [UIScreen mainScreen].bounds.size.width    //屏幕宽度
+#define ScreenHeight [UIScreen mainScreen].bounds.size.height   //屏幕高度
+
+
+
+/* 定义RGBCOLOR*/
+#define ColorRGBA(r, g, b, a) [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:(a)]
+#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
+
+@interface XYCommon : NSObject
+
+UIKIT_EXTERN CGFloat const CenterTitleWidth;
+
+UIKIT_EXTERN CGFloat const AmountWidth;
+
+UIKIT_EXTERN CGFloat const AmountHeight;
+
+@end

+ 19 - 0
Apex Mobile/Apex Mobile/PieChart/XYCommon.m

@@ -0,0 +1,19 @@
+//
+//  XYCommon.m
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import "XYCommon.h"
+
+@implementation XYCommon
+
+CGFloat const CenterTitleWidth = 70;
+
+CGFloat const AmountWidth = 70;
+
+CGFloat const AmountHeight = 22;
+
+@end

+ 67 - 0
Apex Mobile/Apex Mobile/PieChart/XYPieChartView.h

@@ -0,0 +1,67 @@
+//
+//  XYPieChartView.h
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@class XYPieChartView;
+@protocol PieChartDelegate <NSObject>
+
+@required
+/**
+ * 选中扇形的回调数据
+ */
+- (void)selectedFinish:(XYPieChartView *)pieChartView index:(NSInteger)index selectedType:(NSDictionary *)selectedType;
+- (void)showDetail:(XYPieChartView *)pieChartView index:(NSInteger)index selectedType:(NSDictionary *)selectedType;
+
+// 点击事件处理
+- (void)pieChartView:(XYPieChartView *)chartView didBeginTouch:(NSSet<UITouch *> *)touch;
+- (void)pieChartView:(XYPieChartView *)chartView didEndTouch:(NSSet<UITouch *> *)touch;
+
+//// Animation
+//- (void)pieChartAnimationBegin;
+//- (void)pieChartAnimationEnd;
+
+@optional
+/**
+ * 点击中心按钮的回调
+ */
+- (void)onCenterClick:(XYPieChartView *)PieChartView;
+
+@end
+
+@interface XYPieChartView : UIView
+
+@property (nonatomic, assign) id<PieChartDelegate> delegate;
+
+/**
+ * param:{frame:位置, AssetTypeArray:数据的数组, PercentArray:百分比数值 colorArr:颜色的数组}
+ */
+//- (id)initWithFrame:(CGRect)frame withPieChartTypeArray:(NSMutableArray *)pieChartTypeArray withPercentArray:(NSMutableArray *)percentArray withColorArray:(NSMutableArray *)colorArray;
+- (id)initWithFrame:(CGRect)frame withPieChartData:(NSMutableDictionary *)pieChartData;
+/**
+ * 总标题信息
+ */
+- (void)setAmountText:(NSString *)text;
+
+/**
+ * 总金额 
+ */
+- (void)setTitleText:(NSMutableAttributedString *)text;
+
+/**
+ * 刷新chart
+ */
+- (void)reloadChart;
+
+/**
+ * 校验小于百分比时,另外的展现形式
+ */
+- (void)setCheckLessThanPercent:(CGFloat)lessPerent;
+
+-(void) setPieChartData:(NSMutableDictionary*)pieChartData;
+@end

+ 516 - 0
Apex Mobile/Apex Mobile/PieChart/XYPieChartView.m

@@ -0,0 +1,516 @@
+//
+//  XYPieChartView.m
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import "XYPieChartView.h"
+#import "XYRotatedView.h"
+#import "XYCommon.h"
+
+@interface XYPieChartView()<RotatedViewDelegate>
+
+
+// 旋转视图
+@property (nonatomic,strong)XYRotatedView *rotatedView;
+
+// 中心圆的按钮
+@property (nonatomic,strong) UIButton *centerButton;
+
+// 中心圆数值(总金额)
+@property (nonatomic,strong) UILabel *centerAmount;
+
+// 中心圆标题
+@property (nonatomic, strong) UILabel *centerTitle;
+
+// 数据数组
+@property (nonatomic, strong) NSMutableArray *selectedTypeList;
+
+
+// 颜色数组
+@property(nonatomic, strong) NSMutableArray *mColorArray;
+
+// 百分比数组
+@property(nonatomic, strong) NSMutableArray *percentArray;
+
+//所有的数据结构
+@property (nonatomic, strong) NSMutableDictionary *pieChartData;
+
+
+
+@end
+//@property (nonatomic, strong) NSMutableDictionary *chartData;
+@implementation XYPieChartView
+
+
+-(void) setPieChartData:(NSMutableDictionary*)pieChartData
+{
+    _pieChartData = pieChartData;
+    self.mColorArray = [NSMutableArray new];
+    self.percentArray = [NSMutableArray new];
+    self.selectedTypeList = [NSMutableArray new];
+    float total=0;
+    NSMutableArray* arr_data =[pieChartData[@"arr_val"] mutableCopy];
+    for(int i=0;i<arr_data.count;i++)
+//    for(NSMutableDictionary* item in pieChartData[@"arr_val"] )
+    {
+        NSMutableDictionary* item =[arr_data[i] mutableCopy];
+        if([item[@"display"] boolValue])
+        {
+            NSString* scolor =item[@"color"];//[DefaultAppearance get_noneappearance_value:@"DefaultTableHeaderView" valuename:@"title_text_color"];
+            
+            if(scolor==nil)
+                scolor=@"";
+            unsigned long fcolor = strtoul([scolor UTF8String],0,16);
+            
+            [self.mColorArray addObject:UIColorFromRGB(fcolor)];
+            
+            total+=[item[@"A_val"] floatValue];
+            
+            [self.selectedTypeList addObject:item];
+        }
+    }
+    
+    for(int i=0;i<arr_data.count;i++ )
+        {
+            
+            NSMutableDictionary* item =[arr_data[i] mutableCopy];
+            if([item[@"display"] boolValue]==true)
+            {
+            float percent =[item[@"A_val"] floatValue] /total *100;
+                item[@"CP_val"] = [NSNumber numberWithFloat:percent];
+                arr_data[i] = item;
+            [self.percentArray addObject:[NSNumber numberWithFloat:percent]];
+            }
+        }
+    pieChartData[@"arr_val"] = arr_data;
+    
+    // 给RotatedView 百分比数组赋值
+    self.rotatedView.percentArray = self.percentArray;
+    
+    // 给RotatedView 颜色数组赋值
+    self.rotatedView.mColorArray = self.mColorArray;
+    
+    NSString * piechart_name= self.pieChartData[@"name"];
+    if(piechart_name==nil)
+        piechart_name = @"";
+    NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:piechart_name];
+    
+    
+    // 设置圆心标题(NSMutableAttributedString类型)
+    [self setTitleText:str];
+    
+    NSString * piechart_total=[NSString stringWithFormat:@"%@",self.pieChartData[@"total"]];
+    if(piechart_total==nil)
+        piechart_total = @"";
+    
+    // 设置圆心标题(NSMutableAttributedString类型)
+    [self setAmountText:piechart_total];
+}
+
+- (void)setup {
+    
+    CGRect frame = self.bounds;
+//    self.pieChartData = pieChartData;
+    //        self.selectedTypeList = pieChartData[@"arr_val"];
+    
+    // 初始化RotatedView
+    self.rotatedView = [[XYRotatedView alloc]initWithFrame:self.bounds];
+    
+    // 给RotatedView 百分比数组赋值
+    self.rotatedView.percentArray = self.percentArray;
+    
+    // 给RotatedView 颜色数组赋值
+    self.rotatedView.mColorArray = self.mColorArray;
+    
+    // 接收代理方法
+    self.rotatedView.delegate = self;
+    
+    // 添加RotatedView
+    [self addSubview:self.rotatedView];
+    
+    // 初始化中心圆按钮
+    self.centerButton = [UIButton buttonWithType:UIButtonTypeCustom];
+    
+    // 移除点击事件
+    [self.centerButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
+    
+    // 是否接收事件
+    self.centerButton.userInteractionEnabled = YES;
+    
+    // 设置按钮点击事件
+    [self.centerButton addTarget:self action:@selector(changeInOut:) forControlEvents:UIControlEventTouchUpInside];
+    
+    // 中心圆图片
+    UIImage *centerImage = [UIImage imageNamed:@"center_white"];
+    
+    // 图片尺寸
+    CGSize centerImageSize = centerImage.size;
+    
+    if (centerImageSize.height == 0 && centerImageSize.width == 0) {
+        
+        // 如果图片尺寸为0,默认赋值width = 80, Height = 80
+        centerImageSize = CGSizeMake(80, 80);
+    }
+    
+    // 设置按钮普通状态下的背景图片
+    [self.centerButton setBackgroundImage:centerImage forState:UIControlStateNormal];
+    
+    // 设置按钮高亮状态下的背景图片
+    [self.centerButton setBackgroundImage:centerImage forState:UIControlStateHighlighted];
+    
+    // 设置按钮位置、尺寸 (frame)
+    self.centerButton.frame = CGRectMake((frame.size.width - centerImageSize.width/2)/2, (frame.size.height - centerImageSize.height/2)/2, centerImageSize.width/2, centerImageSize.height/2);
+    
+    [self.centerButton.layer setMasksToBounds:YES];
+    
+    // 将按钮设置成圆形
+    [self.centerButton.layer setCornerRadius:self.centerButton.frame.size.width/2];
+    
+    
+    /** 中心圆上展示的标题和总金额 **/
+    
+    // 标题宽
+    CGFloat centerTitleWidth = CenterTitleWidth;
+    
+    // 标题高
+    CGFloat centerTitleHeight = CenterTitleWidth;
+    
+    // 设置标题位置
+    self.centerTitle = [[UILabel alloc]initWithFrame:CGRectMake((centerImageSize.width/2 - centerTitleWidth)/2, (centerImageSize.height/2 - 75)/2, centerTitleWidth, centerTitleHeight)];
+    
+//    NSString * piechart_name= self.pieChartData[@"name"];
+//    if(piechart_name==nil)
+//        piechart_name = @"";
+//    NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:piechart_name];
+//
+//
+//    // 设置圆心标题(NSMutableAttributedString类型)
+//    [self setTitleText:str];
+    
+    
+    // 标题背景色
+    self.centerTitle.backgroundColor = [UIColor clearColor];
+    
+    // 字体居中
+    self.centerTitle.textAlignment = NSTextAlignmentCenter;
+    
+    // 字体大小
+    self.centerTitle.font = [UIFont systemFontOfSize:14.0f];
+    
+    self.centerTitle.numberOfLines = 2;
+    
+    // 字体颜色
+    self.centerTitle.textColor = [UIColor blackColor];
+    
+    // 添加标题
+    [self.centerButton addSubview:self.centerTitle];
+    
+    /** 总金额 **/
+    
+    // 金额宽度
+    CGFloat amountWidth = AmountWidth;
+    
+    // 金额宽度
+    CGFloat amountHeight = AmountHeight;
+    
+    // 初始化金额Label 设置位置、大小
+    self.centerAmount = [[UILabel alloc]initWithFrame:CGRectMake((centerImageSize.width/2 - amountWidth)/2, (centerImageSize.height/2 - 75)/2+53, amountWidth, amountHeight)];
+    
+//    NSString * piechart_total=[NSString stringWithFormat:@"%@",self.pieChartData[@"total"]];
+//    if(piechart_total==nil)
+//        piechart_total = @"";
+//    //        NSMutableAttributedString * str1 = [[NSMutableAttributedString alloc] initWithString:piechart_name];
+//    //
+//    //
+//    // 设置圆心标题(NSMutableAttributedString类型)
+//    [self setAmountText:piechart_total];
+    
+    // 金额背景色
+    self.centerAmount.backgroundColor = [UIColor clearColor];
+    
+    // 字体居中
+    self.centerAmount.textAlignment = NSTextAlignmentCenter;
+    
+    // 字体大小
+    self.centerAmount.font = [UIFont boldSystemFontOfSize:21];
+    
+    // 字体颜色
+    self.centerAmount.textColor = [UIColor blackColor];
+    
+    // 字体大小宽度自适应
+    [self.centerAmount setAdjustsFontSizeToFitWidth:YES];
+    
+    // 添加金额Label
+    [self.centerButton addSubview:self.centerAmount];
+    
+    // 添加中心圆的按钮
+    [self addSubview:self.centerButton];
+    
+    self.backgroundColor = [UIColor clearColor];
+}
+
+- (id)initWithFrame:(CGRect)frame withPieChartData:(NSMutableDictionary *)pieChartData
+{
+    
+    
+    if (self = [super initWithFrame:frame]) {
+        [self setup];
+    }
+    return self;
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    
+    [self setup];
+}
+
+/**
+ *
+ * 初始化方法
+ * param:{frame:位置, pieChartTypeArray:数据的数组, PercentArray:百分比数值 colorArr:颜色的数组}
+ *
+ */
+- (id)initWithFrame:(CGRect)frame withPieChartTypeArray:(NSMutableArray *)pieChartTypeArray withPercentArray:(NSMutableArray *)percentArray withColorArray:(NSMutableArray *)colorArray
+{
+    
+    if (self = [super initWithFrame:frame]) {
+        
+        self.selectedTypeList = pieChartTypeArray;
+        
+        // 初始化RotatedView
+        self.rotatedView = [[XYRotatedView alloc]initWithFrame:self.bounds];
+ 
+        
+        // 给RotatedView 百分比数组赋值
+        self.rotatedView.percentArray = percentArray;
+        
+        // 给RotatedView 颜色数组赋值
+        self.rotatedView.mColorArray = colorArray;
+        
+        // 接收代理方法
+        self.rotatedView.delegate = self;
+        
+        // 添加RotatedView
+        [self addSubview:self.rotatedView];
+        
+        // 初始化中心圆按钮
+        self.centerButton = [UIButton buttonWithType:UIButtonTypeCustom];
+        
+        // 移除点击事件
+        [self.centerButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
+        
+        // 是否接收事件
+        self.centerButton.userInteractionEnabled = YES;
+        
+        // 设置按钮点击事件
+        [self.centerButton addTarget:self action:@selector(changeInOut:) forControlEvents:UIControlEventTouchUpInside];
+        
+        // 中心圆图片
+        UIImage *centerImage = [UIImage imageNamed:@"center_white"];
+        
+        // 图片尺寸
+        CGSize centerImageSize = centerImage.size;
+        
+        if (centerImageSize.height == 0 && centerImageSize.width == 0) {
+            
+            // 如果图片尺寸为0,默认赋值width = 80, Height = 80
+            centerImageSize = CGSizeMake(80, 80);
+        }
+        
+        // 设置按钮普通状态下的背景图片
+        [self.centerButton setBackgroundImage:centerImage forState:UIControlStateNormal];
+        
+        // 设置按钮高亮状态下的背景图片
+        [self.centerButton setBackgroundImage:centerImage forState:UIControlStateHighlighted];
+        
+        // 设置按钮位置、尺寸 (frame)
+        self.centerButton.frame = CGRectMake((frame.size.width - centerImageSize.width/2)/2, (frame.size.height - centerImageSize.height/2)/2, centerImageSize.width/2, centerImageSize.height/2);
+        
+        [self.centerButton.layer setMasksToBounds:YES];
+        
+        // 将按钮设置成圆形
+        [self.centerButton.layer setCornerRadius:self.centerButton.frame.size.width/2];
+        
+        
+        /** 中心圆上展示的标题和总金额 **/
+        
+        // 标题宽
+        CGFloat centerTitleWidth = CenterTitleWidth;
+        
+        // 标题高
+        CGFloat centerTitleHeight = CenterTitleWidth;
+        
+        // 设置标题位置
+        self.centerTitle = [[UILabel alloc]initWithFrame:CGRectMake((centerImageSize.width/2 - centerTitleWidth)/2, (centerImageSize.height/2 - 75)/2, centerTitleWidth, centerTitleHeight)];
+        
+        // 标题背景色
+        self.centerTitle.backgroundColor = [UIColor clearColor];
+        
+        // 字体居中
+        self.centerTitle.textAlignment = NSTextAlignmentCenter;
+        
+        // 字体大小
+        self.centerTitle.font = [UIFont systemFontOfSize:16];
+        
+        self.centerTitle.numberOfLines = 2;
+        
+        // 字体颜色
+        self.centerTitle.textColor = [UIColor blackColor];
+        
+        // 添加标题
+        [self.centerButton addSubview:self.centerTitle];
+        
+        /** 总金额 **/
+        
+        // 金额宽度
+        CGFloat amountWidth = AmountWidth;
+        
+        // 金额宽度
+        CGFloat amountHeight = AmountHeight;
+        
+        // 初始化金额Label 设置位置、大小
+        self.centerAmount = [[UILabel alloc]initWithFrame:CGRectMake((centerImageSize.width/2 - amountWidth)/2, 53, amountWidth, amountHeight)];
+        
+        // 金额背景色
+        self.centerAmount.backgroundColor = [UIColor clearColor];
+        
+        // 字体居中
+        self.centerAmount.textAlignment = NSTextAlignmentCenter;
+        
+        // 字体大小
+        self.centerAmount.font = [UIFont boldSystemFontOfSize:21];
+        
+        // 字体颜色
+        self.centerAmount.textColor = [UIColor blackColor];
+        
+        // 字体大小宽度自适应
+        [self.centerAmount setAdjustsFontSizeToFitWidth:YES];
+        
+        // 添加金额Label
+        [self.centerButton addSubview:self.centerAmount];
+        
+        // 添加中心圆的按钮
+        [self addSubview:self.centerButton];
+        
+        self.backgroundColor = [UIColor clearColor];
+    }
+    return self;
+}
+
+/**
+ * 按钮点击范围的方法
+ */
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
+    
+    //首先调用父类的方法确定点击的区域确实在按钮的区域中
+    BOOL res = [super pointInside:point withEvent:event];
+    if (res) {
+        //绘制一个圆形path
+        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:self.centerButton.frame];
+        if ([path containsPoint:point]) {
+            //如果在path区域内,可以接收交互事件,从而截获父视图的点击事件
+            self.centerButton.userInteractionEnabled = YES;
+            return YES;
+            
+        } else {
+            
+            //如果不在path区域内,不可以接收交互事件,从而将事件传给父视图接收
+            self.centerButton.userInteractionEnabled = NO;
+            return YES;
+        }
+        
+    }
+    return NO;
+}
+/**
+ * 中心圆按钮的点击事件
+ */
+- (void)changeInOut:(id)sender {
+    // 触发点击回调方法
+    if ([self.delegate respondsToSelector:@selector(onCenterClick:)]) {
+        [self.delegate onCenterClick:self];
+    }
+}
+
+/**
+ * 设置标中心圆标题
+ */
+- (void)setTitleText:(NSMutableAttributedString *)text {
+    [self.centerTitle setAttributedText:text];
+}
+
+/**
+ * 设置标中心圆金额
+ */
+- (void)setAmountText:(NSString *)text {
+    [self.centerAmount setText:text];
+}
+
+- (void)setCheckLessThanPercent:(CGFloat)lessPerent {
+
+    [self.rotatedView lessThanPercent:lessPerent];
+}
+/**
+ * 刷新PiaChart视图
+ */
+- (void)reloadChart {
+    [self.rotatedView reloadPie];
+}
+
+/**
+ * RotatedView 选中视图的delegate方法
+ */
+- (void)selectedFinish:(XYRotatedView *)rotatedView index:(NSInteger)index percent:(float)per {
+    // 触发本视图的delegate方法
+    if ([self.delegate respondsToSelector:@selector(selectedFinish:index:selectedType: )]) {
+        
+        [self.delegate selectedFinish:self index:index selectedType:self.selectedTypeList[index]];
+    }
+    
+}
+-(void)showDetail:(XYRotatedView *)rotatedView index:(NSInteger)index
+{
+    if ([self.delegate respondsToSelector:@selector(showDetail:index:selectedType: )]) {
+        NSDictionary* selectedTypeList;
+        if(index<0 || index>self.selectedTypeList.count-1)
+            selectedTypeList=nil;
+        else
+            selectedTypeList =self.selectedTypeList[index];
+        
+        [self.delegate showDetail:self index:index selectedType:selectedTypeList];
+    }
+}
+
+#pragma mark - Touch
+
+- (void)pieChartView:(XYRotatedView *)chartView didBeginTouch:(NSSet<UITouch *> *)touch {
+    if (self.delegate && [self.delegate respondsToSelector:@selector(pieChartView:didBeginTouch:)]) {
+        [self.delegate pieChartView:self didBeginTouch:touch];
+    }
+}
+
+- (void)pieChartView:(XYRotatedView *)chartView didEndTouch:(NSSet<UITouch *> *)touch {
+    if (self.delegate && [self.delegate respondsToSelector:@selector(pieChartView:didEndTouch:)]) {
+        [self.delegate pieChartView:self didEndTouch:touch];
+    }
+}
+
+#pragma mark - Animation
+
+- (void)pieChartAnimationBegin {
+//    if (self.delegate) {
+//        [self.delegate pieChartAnimationBegin];
+//    }
+}
+
+- (void)pieChartAnimationEnd {
+//    if (self.delegate) {
+//        [self.delegate pieChartAnimationEnd];
+//    }
+}
+
+@end

+ 104 - 0
Apex Mobile/Apex Mobile/PieChart/XYRenderView.h

@@ -0,0 +1,104 @@
+//
+//  XYRenderView.h
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@class XYRenderView;
+
+@protocol RenderViewDataSource <NSObject>
+
+@required
+
+// 数据源方法 饼图共有几个区域
+- (NSUInteger)numberOfSlicesInPieChart:(XYRenderView *)pieChart;
+
+// 选中的区域索引
+- (CGFloat)pieChart:(XYRenderView *)pieChart valueForSliceAtIndex:(NSUInteger)index;
+
+@optional
+// 选中的区域颜色
+- (UIColor *)pieChart:(XYRenderView *)pieChart colorForSliceAtIndex:(NSUInteger)index;
+
+@end
+
+@protocol RenderViewtDelegate <NSObject>
+
+@required
+
+- (void)pieChartAnimationBegin;
+
+- (void)pieChartAnimationEnd;
+
+@optional
+
+// will Select
+- (void)pieChart:(XYRenderView *)pieChart willSelectSliceAtIndex:(NSUInteger)index;
+
+// did Select
+- (void)pieChart:(XYRenderView *)pieChart didSelectSliceAtIndex:(NSUInteger)index;
+
+// will Deselect
+- (void)pieChart:(XYRenderView *)pieChart willDeselectSliceAtIndex:(NSUInteger)index;
+
+// did Deselect
+- (void)pieChart:(XYRenderView *)pieChart didDeselectSliceAtIndex:(NSUInteger)index;
+
+// 动画结束
+- (void)animateFinish:(XYRenderView *)pieChart;
+
+@end
+
+@interface XYRenderView : UIView
+
+@property(nonatomic, weak) id<RenderViewDataSource> dataSource;
+
+@property(nonatomic, weak) id<RenderViewtDelegate> delegate;
+
+@property(nonatomic, assign) CGFloat startPieAngle;
+
+@property(nonatomic, assign) CGFloat animationSpeed;
+
+@property(nonatomic, assign) CGPoint pieCenter;
+
+@property(nonatomic, assign) CGFloat pieRadius;
+
+@property(nonatomic, assign) BOOL showLabel;
+
+@property(nonatomic, strong) UIFont *labelFont;
+
+@property(nonatomic, assign) CGFloat labelRadius;
+
+@property(nonatomic, assign) CGFloat selectedSliceStroke;
+
+@property(nonatomic, assign) CGFloat selectedSliceOffsetRadius;
+
+@property(nonatomic, assign) BOOL showPercentage;
+
+@property (strong, nonatomic) NSMutableArray *textLayerArray;
+
+@property (nonatomic, assign) CGFloat textAngle;
+
+@property (nonatomic, assign) CGFloat textrelativeTheta;
+
+@property (nonatomic, strong) CATextLayer *textLayer;
+
+@property (nonatomic, strong) CALayer *lineLayer;
+
+@property (nonatomic, assign) CGFloat checkLessPercent;
+
+- (id)initWithFrame:(CGRect)frame Center:(CGPoint)center Radius:(CGFloat)radius;
+
+- (void)reloadData;
+
+- (void)setPieBackgroundColor:(UIColor *)color;
+
+- (void)pieSelected:(NSInteger)selIndex;
+- (void)pieHightlight:(NSInteger)selIndex;
+
+- (void)checkLessPercent:(CGFloat)lessPercent;
+@end

+ 780 - 0
Apex Mobile/Apex Mobile/PieChart/XYRenderView.m

@@ -0,0 +1,780 @@
+//
+//  XYRenderView.m
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import "XYRenderView.h"
+#import <QuartzCore/QuartzCore.h>
+#import "XYCommon.h"
+
+@interface SliceLayer : CAShapeLayer
+
+@property (nonatomic, assign) CGFloat value;
+
+@property (nonatomic, assign) CGFloat percentage;
+
+@property (nonatomic, assign) double startAngle;
+
+@property (nonatomic, assign) double endAngle;
+
+@property (nonatomic, assign) BOOL isSelected;
+
+- (void)createArcAnimationForKey:(NSString *)key fromValue:(NSNumber *)from toValue:(NSNumber *)to Delegate:(id)delegate;
+
+@end
+
+@implementation SliceLayer
+
+- (NSString*)description {
+    return @"";
+}
+
++ (BOOL)needsDisplayForKey:(NSString *)key {
+    if ([key isEqualToString:@"startAngle"] || [key isEqualToString:@"endAngle"]) {
+        return YES;
+    }
+    else {
+        return [super needsDisplayForKey:key];
+    }
+}
+
+- (id)initWithLayer:(id)layer {
+    if (self = [super initWithLayer:layer])
+    {
+        if ([layer isKindOfClass:[SliceLayer class]]) {
+            self.startAngle = [(SliceLayer *)layer startAngle];
+            self.endAngle = [(SliceLayer *)layer endAngle];
+        }
+    }
+    return self;
+}
+
+- (void)createArcAnimationForKey:(NSString *)key fromValue:(NSNumber *)from toValue:(NSNumber *)to Delegate:(id)delegate {
+    CABasicAnimation *arcAnimation = [CABasicAnimation animationWithKeyPath:key];
+    
+    NSNumber *currentAngle = [[self presentationLayer] valueForKey:key];
+    
+    if(!currentAngle) currentAngle = from;
+    
+    [arcAnimation setFromValue:currentAngle];
+    
+    [arcAnimation setToValue:to];
+    
+    [arcAnimation setDelegate:delegate];
+    
+    [arcAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
+    
+    [self addAnimation:arcAnimation forKey:key];
+    
+    [self setValue:to forKey:key];
+}
+
+@end
+
+@interface XYRenderView ()
+
+- (void)updateTimerFired:(NSTimer *)timer;
+
+- (SliceLayer *)createSliceLayer;
+
+- (void)updateLabelForLayer:(SliceLayer *)pieLayer value:(CGFloat)value;
+
+- (void)notifyDelegateOfSelectionChangeFrom:(NSUInteger)previousSelection to:(NSUInteger)newSelection;
+
+@end
+
+@implementation XYRenderView
+{
+    NSInteger _selectedSliceIndex;
+    //pie view, contains all slices
+    UIView  *_pieView;
+    
+    //animation control
+    NSTimer *_animationTimer;
+    
+    NSMutableArray *_animations;
+    
+}
+static NSUInteger kDefaultSliceZOrder = 100;
+
+static CGPathRef CGPathCreateArc(CGPoint center, CGFloat radius, CGFloat startAngle, CGFloat endAngle) {
+    CGMutablePathRef path = CGPathCreateMutable();
+    
+    CGPathMoveToPoint(path, NULL, center.x, center.y);
+    
+    CGPathAddArc(path, NULL, center.x, center.y, radius, startAngle, endAngle, 0);
+    
+    CGPathCloseSubpath(path);
+    
+    return path;
+}
+
+- (id)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame])
+    {
+        self.backgroundColor = [UIColor clearColor];
+        
+        _pieView = [[UIView alloc] initWithFrame:frame];
+        
+        [_pieView setBackgroundColor:[UIColor clearColor]];
+        
+        [self addSubview:_pieView];
+        
+        _selectedSliceIndex = -1;
+        
+        _animations = [[NSMutableArray alloc] init];
+        
+        _animationSpeed = 0.5;
+        
+        _startPieAngle = M_PI_2*2;
+        
+        _selectedSliceStroke = 3.0;
+        
+        self.pieRadius = MIN(frame.size.width/2, frame.size.height/2);
+        
+        self.pieCenter = CGPointMake(frame.size.width/2, frame.size.height/2);
+        
+        self.labelFont = [UIFont boldSystemFontOfSize:MAX((int)self.pieRadius/10, 5)];
+        
+        _labelRadius = _pieRadius/2;
+        
+        _selectedSliceOffsetRadius = MAX(10, _pieRadius/10);
+        
+        _showLabel = YES;
+        
+        _showPercentage = YES;
+        
+    }
+    return self;
+}
+
+- (id)initWithFrame:(CGRect)frame Center:(CGPoint)center Radius:(CGFloat)radius {
+    if (self = [super initWithFrame:frame]) {
+        self.pieCenter = center;
+        self.pieRadius = radius;
+    }
+    return self;
+}
+
+- (id)initWithCoder:(NSCoder *)aDecoder {
+    if(self = [super initWithCoder:aDecoder]) {
+        _pieView = [[UIView alloc] initWithFrame:self.bounds];
+        [_pieView setBackgroundColor:[UIColor clearColor]];
+        [self insertSubview:_pieView atIndex:0];
+        
+        _selectedSliceIndex = -1;
+        _animations = [[NSMutableArray alloc] init];
+        
+        _animationSpeed = 0.5;
+        _startPieAngle = M_PI_2*2;
+        _selectedSliceStroke = 3.0;
+        
+        CGRect bounds = [[self layer] bounds];
+        self.pieRadius = MIN(bounds.size.width/2, bounds.size.height/2) - 10;
+        self.pieCenter = CGPointMake(bounds.size.width/2, bounds.size.height/2);
+        self.labelFont = [UIFont boldSystemFontOfSize:MAX((int)self.pieRadius/10, 5)];
+        _labelRadius = _pieRadius/2;
+        _selectedSliceOffsetRadius = MAX(10, _pieRadius/10);
+        
+        _showLabel = YES;
+        _showPercentage = YES;
+        
+    }
+    return self;
+}
+
+- (void)setPieCenter:(CGPoint)pieCenter {
+    [_pieView setCenter:pieCenter];
+    
+    _pieCenter = CGPointMake(_pieView.frame.size.width/2, _pieView.frame.size.height/2);
+}
+
+- (void)setPieRadius:(CGFloat)pieRadius {
+    _pieRadius = pieRadius;
+    
+    CGRect frame = CGRectMake(_pieCenter.x-pieRadius, _pieCenter.y-pieRadius, pieRadius*2, pieRadius*2);
+    
+    _pieCenter = CGPointMake(frame.size.width/2, frame.size.height/2);
+    
+    [_pieView setFrame:frame];
+    
+    [_pieView.layer setCornerRadius:_pieRadius];
+}
+
+- (void)setPieBackgroundColor:(UIColor *)color {
+    [_pieView setBackgroundColor:color];
+}
+
+#pragma mark - manage settings
+#pragma mark 显示扇形百分比
+- (void)setShowPercentage:(BOOL)showPercentage {
+    _showPercentage = showPercentage;
+    
+    for(SliceLayer *layer in _pieView.layer.sublayers)
+    {
+        CATextLayer *textLayer = (CATextLayer*)[[layer sublayers] objectAtIndex:0];
+        
+        [textLayer setHidden:!_showLabel];
+        
+        if(!_showLabel) return;
+        
+        NSString *label;
+        
+        if(_showPercentage){
+            
+            label = [NSString stringWithFormat:@"%0.0f", layer.percentage*100];
+        } else {
+            label = [NSString stringWithFormat:@"%0.0f", layer.value];
+        }
+        
+        NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:13]};
+        
+        CGSize infoSize = CGSizeMake(10, 20);
+        
+        CGSize size = [label boundingRectWithSize:infoSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
+        
+        if(M_PI*2*_labelRadius*layer.percentage < MAX(size.width,size.height))
+        {
+            [textLayer setString:@""];
+        }
+        else
+        {
+            [textLayer setString:label];
+            [textLayer setBounds:CGRectMake(0, 0, size.width, size.height)];
+        }
+    }
+}
+
+#pragma mark - 计算选中的扇形滑出的位置和角度
+- (void)setSliceSelectedAtIndex:(NSInteger)index {
+    if(_selectedSliceOffsetRadius <= 0) {
+        
+        return;
+    }
+    
+    SliceLayer *layer = (SliceLayer*)[_pieView.layer.sublayers objectAtIndex:index];
+    
+    if (layer) {
+        
+        float adjust = 0.5;
+        
+        CGPoint currPos = layer.position;
+        
+        double middleAngle = (layer.startAngle + layer.endAngle)/2.0;
+        
+        // 此处是选中的扇形滑出的位置
+        CGPoint newPos = CGPointMake(currPos.x + _selectedSliceOffsetRadius*cos(middleAngle)*adjust, currPos.y + _selectedSliceOffsetRadius*sin(middleAngle)*adjust);
+        
+        layer.position = newPos;
+        
+        layer.isSelected = YES;
+    }
+}
+
+#pragma mark - 计算扇形取消选中后滑出的位置和角度
+- (void)setSliceDeselectedAtIndex:(NSInteger)index {
+    if(_selectedSliceOffsetRadius <= 0) {
+        
+        return;
+    }
+    
+    SliceLayer *layer = (SliceLayer*)[_pieView.layer.sublayers objectAtIndex:index];
+    
+    if (layer) {
+        
+        layer.position = CGPointMake(0, 0);
+        layer.isSelected = NO;
+    }
+}
+
+#pragma mark - Pie Reload Data With Animation
+- (void)reloadData {
+    
+    if (_animationTimer) {
+        [_animationTimer invalidate];
+        _animationTimer = nil;
+    }
+    
+    NSArray *sublayers = [[_pieView.layer sublayers] mutableCopy];
+    for (CALayer *layer in sublayers) {
+        if ([layer isKindOfClass:[SliceLayer class]]) {
+            [layer removeFromSuperlayer];
+        }
+    }
+    
+    if (_dataSource && !_animationTimer)
+    {
+        CALayer *parentLayer = [_pieView layer];
+        NSArray *slicelayers = [parentLayer sublayers];
+        
+        _selectedSliceIndex = -1;
+        [slicelayers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+            SliceLayer *layer = (SliceLayer *)obj;
+            if(layer.isSelected)
+            [self setSliceDeselectedAtIndex:idx];
+        }];
+        
+        double startToAngle = 0.0;
+        double endToAngle = startToAngle;
+        
+        NSUInteger sliceCount = [_dataSource numberOfSlicesInPieChart:self];
+        
+        double sum = 0.0;
+        double values[sliceCount];
+        for (int index = 0; index < sliceCount; index++) {
+            values[index] = [_dataSource pieChart:self valueForSliceAtIndex:index];
+            sum += values[index];
+        }
+        
+        double angles[sliceCount];
+        for (int index = 0; index < sliceCount; index++) {
+            double div;
+            if (sum == 0)
+            div = 0;
+            else
+            div = values[index] / sum;
+            angles[index] = M_PI * 2 * div;
+        }
+        
+        [CATransaction begin];
+        [CATransaction setAnimationDuration:_animationSpeed];
+        
+        [_pieView setUserInteractionEnabled:NO];
+        
+        __block NSMutableArray *layersToRemove = nil;
+        [CATransaction setCompletionBlock:^{
+            
+            [layersToRemove enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+                [obj removeFromSuperlayer];
+            }];
+            
+            [layersToRemove removeAllObjects];
+            
+            for(SliceLayer *layer in _pieView.layer.sublayers)
+            {
+                [layer setZPosition:kDefaultSliceZOrder];
+            }
+            
+            [_pieView setUserInteractionEnabled:YES];
+            if([_delegate respondsToSelector:@selector(animateFinish:)]){
+                [_delegate animateFinish:self];
+            }
+        }];
+        
+        BOOL isOnStart = ([slicelayers count] == 0 && sliceCount);
+        NSInteger diff = sliceCount - [slicelayers count];
+        layersToRemove = [NSMutableArray arrayWithArray:slicelayers];
+        
+        BOOL isOnEnd = ([slicelayers count] && (sliceCount == 0 || sum <= 0));
+        if(isOnEnd)
+        {
+            for(SliceLayer *layer in _pieView.layer.sublayers){
+                [self updateLabelForLayer:layer value:0];
+                [layer createArcAnimationForKey:@"startAngle"
+                                      fromValue:[NSNumber numberWithDouble:_startPieAngle]
+                                        toValue:[NSNumber numberWithDouble:_startPieAngle]
+                                       Delegate:self];
+                [layer createArcAnimationForKey:@"endAngle"
+                                      fromValue:[NSNumber numberWithDouble:_startPieAngle]
+                                        toValue:[NSNumber numberWithDouble:_startPieAngle]
+                                       Delegate:self];
+            }
+            [CATransaction commit];
+            return;
+        }
+
+        for(int index = 0; index < sliceCount; index ++)
+        {
+            SliceLayer *layer;
+            double angle = angles[index];
+            endToAngle += angle;
+            double startFromAngle = _startPieAngle + startToAngle;
+            double endFromAngle = _startPieAngle + endToAngle;
+            
+            if( index >= [slicelayers count] )
+            {
+                layer = [self createSliceLayer];
+                if (isOnStart)
+                startFromAngle = endFromAngle = _startPieAngle;
+                [parentLayer addSublayer:layer];
+                diff--;
+            }
+            else
+            {
+                SliceLayer *onelayer = [slicelayers objectAtIndex:index];
+                if(diff == 0 || onelayer.value == (CGFloat)values[index])
+                {
+                    layer = onelayer;
+                    [layersToRemove removeObject:layer];
+                }
+                else if(diff > 0)
+                {
+                    layer = [self createSliceLayer];
+                    [parentLayer insertSublayer:layer atIndex:index];
+                    diff--;
+                }
+                else if(diff < 0)
+                {
+                    while(diff < 0)
+                    {
+                        [onelayer removeFromSuperlayer];
+                        [parentLayer addSublayer:onelayer];
+                        diff++;
+                        onelayer = [slicelayers objectAtIndex:index];
+                        if(onelayer.value == (CGFloat)values[index] || diff == 0)
+                        {
+                            layer = onelayer;
+                            [layersToRemove removeObject:layer];
+                            break;
+                        }
+                    }
+                }
+            }
+            
+            layer.value = values[index];
+            layer.percentage = (sum)?layer.value:0;
+            UIColor *color = nil;
+            if([_dataSource respondsToSelector:@selector(pieChart:colorForSliceAtIndex:)])
+            {
+                color = [_dataSource pieChart:self colorForSliceAtIndex:index];
+            }
+            
+            if(!color)
+            {
+                // 如果没有设置扇形颜色这是默认颜色
+                color = [UIColor colorWithHue:((index/8)%20)/20.0+0.02 saturation:(index%8+3)/10.0 brightness:91/100.0 alpha:1];
+            }
+            
+            [layer setFillColor:color.CGColor];
+            if (sliceCount > 1) {
+                [layer setStrokeColor:ColorRGBA(255, 255, 255, 1).CGColor];
+                [layer setLineWidth:3.0];
+            }
+            
+            [self updateLabelForLayer:layer value:values[index]];
+            [layer createArcAnimationForKey:@"startAngle"
+                                  fromValue:[NSNumber numberWithDouble:startFromAngle]
+                                    toValue:[NSNumber numberWithDouble:startToAngle+_startPieAngle]
+                                   Delegate:self];
+            [layer createArcAnimationForKey:@"endAngle"
+                                  fromValue:[NSNumber numberWithDouble:endFromAngle]
+                                    toValue:[NSNumber numberWithDouble:endToAngle+_startPieAngle]
+                                   Delegate:self];
+            startToAngle = endToAngle;
+        }
+        [CATransaction setDisableActions:YES];
+        for(SliceLayer *layer in layersToRemove)
+        {
+            [layer setFillColor:[self backgroundColor].CGColor];
+            [layer setDelegate:nil];
+            [layer setZPosition:0];
+            CATextLayer *textLayer = (CATextLayer*)[[layer sublayers] objectAtIndex:0];
+            [textLayer setHidden:YES];
+        }
+        [CATransaction setDisableActions:NO];
+        [CATransaction commit];
+    }
+}
+
+#pragma mark - Animation Delegate + Run Loop Timer
+
+- (void)updateTimerFired:(NSTimer *)timer;
+{
+    CALayer *parentLayer = [_pieView layer];
+    NSArray *pieLayers = [parentLayer sublayers];
+    
+    [pieLayers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        SliceLayer *layer = (SliceLayer *)obj;
+        
+        NSNumber *presentationLayerStartAngle = [[obj presentationLayer] valueForKey:@"startAngle"];
+        CGFloat interpolatedStartAngle = [presentationLayerStartAngle doubleValue];
+        
+        NSNumber *presentationLayerEndAngle = [[obj presentationLayer] valueForKey:@"endAngle"];
+        CGFloat interpolatedEndAngle = [presentationLayerEndAngle doubleValue];
+        
+        CGPathRef path = CGPathCreateArc(_pieCenter, _pieRadius, interpolatedStartAngle, interpolatedEndAngle);
+        [obj setPath:path];
+        CFRelease(path);
+        
+        {
+            CATextLayer *labelLayer = (CATextLayer*)[[obj sublayers] objectAtIndex:0];
+            CAShapeLayer *lineLayer = (CAShapeLayer*)[[obj sublayers] objectAtIndex:1];
+            CGFloat interpolatedMidAngle = (interpolatedEndAngle + interpolatedStartAngle) / 2;
+            [CATransaction setDisableActions:YES];
+            
+            if (layer.percentage < self.checkLessPercent) {
+                labelLayer.hidden = true;
+                //小于百分比不绘制
+//
+//                [labelLayer setForegroundColor:[UIColor grayColor].CGColor];
+//
+//                float labelLayerX = _pieCenter.x + ((_labelRadius + 70) * cos(interpolatedMidAngle));
+//
+//                float labelLayerY = _pieCenter.y + ((_labelRadius + 70) * sin(interpolatedMidAngle));
+//
+//                UIBezierPath *linePath = [UIBezierPath bezierPath];
+//                // 起点
+//                [linePath moveToPoint:CGPointMake(_pieCenter.x + ((_labelRadius+ 35) * cos(interpolatedMidAngle)), _pieCenter.y + ((_labelRadius + 35) * sin(interpolatedMidAngle)))];
+//                // 终点
+//                [linePath addLineToPoint:CGPointMake(_pieCenter.x + ((_labelRadius+ 50) * cos(interpolatedMidAngle)), _pieCenter.y + ((_labelRadius + 50) * sin(interpolatedMidAngle)))];
+//
+//                lineLayer.path = linePath.CGPath;
+//
+//                [labelLayer setPosition:CGPointMake(labelLayerX * 1, labelLayerY * 1)];
+            } else {
+
+                float labelLayerX = _pieCenter.x + (_labelRadius * cos(interpolatedMidAngle));
+
+                float labelLayerY = _pieCenter.y + (_labelRadius * sin(interpolatedMidAngle));
+
+                [labelLayer setPosition:CGPointMake(labelLayerX * 1, labelLayerY * 1)];
+
+            }
+
+            [CATransaction setDisableActions:NO];
+        }
+    }];
+}
+
+- (void)animationDidStart:(CAAnimation *)anim {
+    if (_animationTimer == nil) {
+        static float timeInterval = 1.0/60.0;
+        _animationTimer= [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(updateTimerFired:) userInfo:nil repeats:YES];
+        // 修复在ScrollView中滚动时Timer失效
+        [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSRunLoopCommonModes];
+//        [[NSRunLoop currentRunLoop] run];
+    }
+    
+    [_animations addObject:anim];
+    
+    if (self.delegate) {
+        [self.delegate pieChartAnimationBegin];
+    }
+}
+
+- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)animationCompleted {
+    [_animations removeObject:anim];
+    
+    if ([_animations count] == 0) {
+        [_animationTimer invalidate];
+        _animationTimer = nil;
+    }
+    
+    if (self.delegate) {
+        [self.delegate pieChartAnimationEnd];
+    }
+}
+
+#pragma mark - Touch Handing (Selection Notification) 选中扇形的索引
+- (NSInteger)getCurrentSelectedOnTouch:(CGPoint)point {
+    __block NSUInteger selectedIndex = -1;
+    
+    CGAffineTransform transform = CGAffineTransformIdentity;
+    
+    CALayer *parentLayer = [_pieView layer];
+    NSArray *pieLayers = [parentLayer sublayers];
+    
+    [pieLayers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        SliceLayer *pieLayer = (SliceLayer *)obj;
+        CGPathRef path = [pieLayer path];
+        
+        if (CGPathContainsPoint(path, &transform, point, 0)) {
+            [pieLayer setLineWidth:_selectedSliceStroke];
+            [pieLayer setStrokeColor:[UIColor whiteColor].CGColor];
+            [pieLayer setLineJoin:kCALineJoinBevel];
+            [pieLayer setZPosition:MAXFLOAT];
+            selectedIndex = idx;
+        } else {
+            [pieLayer setZPosition:kDefaultSliceZOrder];
+            [pieLayer setLineWidth:0.0];
+        }
+    }];
+    return selectedIndex;
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+    [self touchesMoved:touches withEvent:event];
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+    UITouch *touch = [touches anyObject];
+    CGPoint point = [touch locationInView:_pieView];
+    [self getCurrentSelectedOnTouch:point];
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+    UITouch *touch = [touches anyObject];
+    CGPoint point = [touch locationInView:_pieView];
+    NSInteger selectedIndex = [self getCurrentSelectedOnTouch:point];
+    [self notifyDelegateOfSelectionChangeFrom:_selectedSliceIndex to:selectedIndex];
+    [self touchesCancelled:touches withEvent:event];
+}
+
+#pragma mark - 选中事件
+- (void)pieSelected:(NSInteger)selIndex {
+    [self notifyDelegateOfSelectionChangeFrom:_selectedSliceIndex to:selIndex];
+    [self touchesCancelled:[NSSet set] withEvent:nil];
+}
+- (void)pieHightlight:(NSInteger)selIndex {
+    [self notifyDelegateOfSelectionChangeFrom:_selectedSliceIndex to:selIndex];
+//    [self touchesCancelled:[NSSet set] withEvent:nil];
+}
+#pragma marK - 点击旋转事件结束后
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+    CALayer *parentLayer = [_pieView layer];
+    NSArray *pieLayers = [parentLayer sublayers];
+    
+    for (SliceLayer *pieLayer in pieLayers) {
+        
+        [pieLayer setZPosition:kDefaultSliceZOrder];
+        [self createSliceLayer];
+        if (pieLayers.count > 1) {
+            [pieLayer setLineWidth:3.0];
+        }
+    }
+    
+}
+
+#pragma mark - Selection Notification
+- (void)notifyDelegateOfSelectionChangeFrom:(NSUInteger)previousSelection to:(NSUInteger)newSelection {
+    
+    NSLog(@"notifyDelegateOfSelectionChangeFrom");
+    // 将上一次选中的Selection和最新选中的Selection做比较
+    if (previousSelection != newSelection)
+    {
+        NSLog(@"!!!!!!!!!!!!!!!!!!!!!");
+        if (previousSelection != -1 && [_delegate respondsToSelector:@selector(pieChart:willDeselectSliceAtIndex:)])
+        {
+            [_delegate pieChart:self willDeselectSliceAtIndex:previousSelection];
+        }
+        
+        _selectedSliceIndex = newSelection;
+        
+        if (newSelection != -1)
+        {
+            if([_delegate respondsToSelector:@selector(pieChart:willSelectSliceAtIndex:)])
+            [_delegate pieChart:self willSelectSliceAtIndex:newSelection];
+            if(previousSelection != -1 && [_delegate respondsToSelector:@selector(pieChart:didDeselectSliceAtIndex:)])
+            [_delegate pieChart:self didDeselectSliceAtIndex:previousSelection];
+            if([_delegate respondsToSelector:@selector(pieChart:didSelectSliceAtIndex:)])
+            [_delegate pieChart:self didSelectSliceAtIndex:newSelection];
+            [self setSliceSelectedAtIndex:newSelection];
+        }
+        
+        if(previousSelection != -1)
+        {
+            [self setSliceDeselectedAtIndex:previousSelection];
+            if([_delegate respondsToSelector:@selector(pieChart:didDeselectSliceAtIndex:)])
+            [_delegate pieChart:self didDeselectSliceAtIndex:previousSelection];
+        }
+    }
+    else if (newSelection != -1)
+    {
+        SliceLayer *layer = (SliceLayer*)[_pieView.layer.sublayers objectAtIndex:newSelection];
+        if(_selectedSliceOffsetRadius > 0 && layer){
+            
+            if (layer.isSelected) {
+                NSLog(@"layer.isSelected");
+//                if ([_delegate respondsToSelector:@selector(pieChart:willDeselectSliceAtIndex:)])
+//                [_delegate pieChart:self willDeselectSliceAtIndex:newSelection];
+//                [self setSliceDeselectedAtIndex:newSelection];
+//                if (newSelection != -1 && [_delegate respondsToSelector:@selector(pieChart:didDeselectSliceAtIndex:)])
+//                [_delegate pieChart:self didDeselectSliceAtIndex:newSelection];
+            }
+            else {
+                if ([_delegate respondsToSelector:@selector(pieChart:willSelectSliceAtIndex:)])
+                [_delegate pieChart:self willSelectSliceAtIndex:newSelection];
+                [self setSliceSelectedAtIndex:newSelection];
+                if (newSelection != -1 && [_delegate respondsToSelector:@selector(pieChart:didSelectSliceAtIndex:)])
+                [_delegate pieChart:self didSelectSliceAtIndex:newSelection];
+            }
+        }
+    }
+}
+
+#pragma mark - <扇形中百分比Label的旋转角度>
+- (void)setTextAngle:(CGFloat)textAngle {
+    
+    NSString *angle = [NSString stringWithFormat:@"%0.6f", textAngle];
+    // 将扇形百分比的旋转角度精确到小数点后六位,如果角度是0,则不进行角度旋转
+    if ([angle isEqualToString:@"0.000000"] || [angle isEqualToString:@"-0.000000"]) {
+        
+        return;
+    }
+    CALayer *parentLayer = [_pieView layer];
+    NSArray *pieLayers = [parentLayer sublayers];
+    
+    [pieLayers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        
+        CALayer *labelLayer = [[obj sublayers] objectAtIndex:0];
+        
+        // 扇形中百分比Label的旋转角度
+        labelLayer.transform = CATransform3DMakeRotation(-textAngle, 0, 0, 1);
+    }];
+}
+
+#pragma mark - Pie Layer Creation Method
+- (SliceLayer *)createSliceLayer {
+    SliceLayer *pieLayer = [SliceLayer layer];
+    [pieLayer setZPosition:0];
+    [pieLayer setStrokeColor:NULL];
+    CATextLayer *textLayer = [CATextLayer layer];
+    
+#pragma mark - 这里可以修改整扇形title字体
+    // 扇形百分比字体
+    [textLayer setFontSize:self.labelFont.pointSize - 2];
+    // 扇形百分比颜色
+    [textLayer setForegroundColor:[UIColor whiteColor].CGColor];
+    [textLayer setAnchorPoint:CGPointMake(0.5, 0.5)];
+    // 扇形百分比字体居中
+    [textLayer setAlignmentMode:kCAAlignmentCenter];
+    // 扇形百分比字体清晰度
+    [textLayer setContentsScale:[UIScreen mainScreen].scale];
+    // 扇形百分比背景色
+    [textLayer setBackgroundColor:[UIColor clearColor].CGColor];
+    
+    // 当百分比过小时,划线显示百分比
+    CAShapeLayer *lineLayer = [CAShapeLayer layer];
+    lineLayer.lineWidth = 1;
+    lineLayer.strokeColor = [UIColor grayColor].CGColor;
+    
+    [CATransaction setDisableActions:NO];
+    [self.textLayerArray addObject:textLayer];
+    self.textLayer = textLayer;
+    [pieLayer addSublayer:textLayer];
+    [pieLayer addSublayer:lineLayer];
+    return pieLayer;
+    
+}
+
+- (void)updateLabelForLayer:(SliceLayer *)pieLayer value:(CGFloat)value {
+    CATextLayer *textLayer = (CATextLayer*)[[pieLayer sublayers] objectAtIndex:0];
+    [textLayer setHidden:!_showLabel];
+    if(!_showLabel) return;
+    NSString *label;
+   
+    // 百分比预留小数点后一位
+    label = [NSString stringWithFormat:@"%.1f%%", pieLayer.percentage];
+    
+    NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:13]};
+    
+    CGSize infoSize = CGSizeMake(10, 20);
+    
+    CGSize size = [label boundingRectWithSize:infoSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
+    
+    [CATransaction setDisableActions:YES];
+
+    [textLayer setString:label];
+    
+    [textLayer setBounds:CGRectMake(0, 0, size.width + 30, size.height)];
+    [CATransaction setDisableActions:NO];
+}
+
+- (void)checkLessPercent:(CGFloat)lessPercent {
+
+    _checkLessPercent = lessPercent;
+}
+@end

+ 79 - 0
Apex Mobile/Apex Mobile/PieChart/XYRotatedView.h

@@ -0,0 +1,79 @@
+//
+//  XYRotatedView.h
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "XYRenderView.h"
+
+@class XYRotatedView;
+@protocol RotatedViewDelegate <NSObject>
+
+@optional
+// 选中的回调
+- (void)selectedFinish:(XYRotatedView *)rotatedView index:(NSInteger)index percent:(float)percent;
+- (void)showDetail:(XYRotatedView *)rotatedView index:(NSInteger)index ;
+
+@required
+// 点击事件处理
+- (void)pieChartView:(XYRotatedView *)chartView didBeginTouch:(NSSet<UITouch *> *)touch;
+- (void)pieChartView:(XYRotatedView *)chartView didEndTouch:(NSSet<UITouch *> *)touch;
+
+// Animation
+- (void)pieChartAnimationBegin;
+- (void)pieChartAnimationEnd;
+
+@end
+
+@interface XYRotatedView : UIView<RenderViewDataSource,RenderViewtDelegate>
+
+@property(nonatomic, assign) float mZeroAngle;
+
+@property(nonatomic, assign) int touch_index;
+
+// 颜色数组
+@property(nonatomic, strong) NSMutableArray *mColorArray;
+
+// 百分比数组
+@property(nonatomic, strong) NSMutableArray *percentArray;
+
+// 角度数组
+@property(nonatomic, strong) NSMutableArray *mThetaArray;
+
+@property(nonatomic, assign) BOOL isAnimating;
+@property(nonatomic, assign) BOOL isTapStopped;
+@property(nonatomic, assign) BOOL isAutoRotation;
+
+@property(nonatomic, assign) float mAbsoluteTheta;
+@property(nonatomic, assign) float mRelativeTheta;
+
+@property(nonatomic,retain) UITextView *mInfoTextView;
+
+@property(nonatomic, assign) float mDragSpeed;
+@property(nonatomic, strong) NSDate *mDragBeforeDate;
+@property(nonatomic, assign) float mDragBeforeTheta;
+@property(nonatomic, strong) NSTimer *mDecelerateTimer;
+
+@property(nonatomic, assign) id<RotatedViewDelegate> delegate;
+
+@property (nonatomic)float fracValue;
+
+@property (nonatomic, assign) BOOL showPercent;
+
+@property (nonatomic, assign) CGFloat checkLessPercent;
+
+/**
+ * 开始动画
+ */
+- (void)startedAnimate;
+
+/**
+ * 刷新pie
+ */
+- (void)reloadPie;
+
+- (void)lessThanPercent:(CGFloat)lessThanPercent;
+@end

+ 433 - 0
Apex Mobile/Apex Mobile/PieChart/XYRotatedView.m

@@ -0,0 +1,433 @@
+//
+//  XYRotatedView.m
+//  PieChart
+//
+//  Created by GMY on 17/6/1.
+//  Copyright © 2017年 com.gmy. All rights reserved.
+//
+
+#import "XYRotatedView.h"
+#import "XYRenderView.h"
+#import <QuartzCore/QuartzCore.h>
+#include <math.h>
+#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))
+
+#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
+#define K_EPSINON        (1e-127)
+#define IS_ZERO_FLOAT(X) (X < K_EPSINON && X > -K_EPSINON)
+#define K_MAX_SPEED             12.0f
+#define K_POINTER_ANGLE         (M_PI / 2)
+
+@interface XYRotatedView()
+
+@property (nonatomic,assign) NSInteger selectedIndex;
+
+@property (strong, nonatomic) XYRenderView *pieChart;
+
+@property (nonatomic, assign) BOOL canLayerOpen;
+
+@end
+
+@implementation XYRotatedView
+
+/**
+ * RotatedView 初始化
+ */
+- (id)initWithFrame:(CGRect)frame {
+    
+    if ((self = [super initWithFrame:frame])) {
+        
+        self.touch_index = -1;
+        
+        // 视图背景色
+        self.backgroundColor = [UIColor clearColor];
+        
+        _mRelativeTheta = 0.0;
+        
+        // 动画是否开始
+        _isAnimating = NO;
+        
+        // 点击是否结束
+        _isTapStopped = NO;
+        
+        // 环形图初始化 位置\尺寸
+        self.pieChart = [[XYRenderView alloc]initWithFrame:frame];
+        
+        // 环形图数据源方法
+        self.pieChart.dataSource = self;
+        
+        // 环形图代理方法
+        self.pieChart.delegate = self;
+        
+        // 开始的角度
+        [self.pieChart setStartPieAngle:DEGREES_TO_RADIANS(-90)];
+        
+        // 绘制环形图所需的动画时间
+        [self.pieChart setAnimationSpeed:1.0];
+        
+        // 环状图上Label(百分比)所处的半径
+        CGFloat radius = frame.size.width * 0.4;
+        
+        [self.pieChart setLabelRadius:radius];
+        
+        // 环形图上标题的字体大小
+        [self.pieChart setLabelFont:[UIFont fontWithName:@"DBLCDTempBlack" size:15]];
+        
+        // 环形图中心点
+        [self.pieChart setPieCenter:CGPointMake(frame.size.width/2, frame.size.height/2)];
+        
+        // 环形图是否接受触摸事件
+        [self.pieChart setUserInteractionEnabled:NO];
+        
+        // 添加pieChart
+        [self addSubview:self.pieChart];
+    }
+    
+    return self;
+}
+
+/**
+ * 刷新视图方法
+ */
+- (void)reloadPie {
+    _isAutoRotation = YES;
+    
+    // 修复数据源变化后,Touch取得的Index导致数组越界
+    [self setNeedsDisplay];
+    
+    // 调用渲染视图的数据刷新方法
+    [self.pieChart reloadData];
+}
+
+- (void)lessThanPercent:(CGFloat)lessThanPercent {
+
+    // 校验最小百分比
+    [self.pieChart checkLessPercent:lessThanPercent];
+}
+/**
+ * 系统绘画方法
+ */
+- (void)drawRect:(CGRect)rect {
+    
+    NSInteger wedges = [_percentArray count];
+    if (wedges > [_mColorArray count]) {
+        
+        for (NSInteger i= _mColorArray.count; i<wedges; ++i) {
+            [_mColorArray addObject:[UIColor whiteColor]];
+        }
+    }
+    
+    _mThetaArray = [[NSMutableArray alloc] initWithCapacity:wedges];
+    
+    float sum = 0.0;
+    for (int i = 0; i < wedges; ++i) {
+        sum += [[_percentArray objectAtIndex:i] floatValue];
+    }
+    
+    float frac = 2.0 * M_PI / sum;
+    self.fracValue = frac;
+    
+//    float startAngle = _mZeroAngle;
+    float endAngle   = -M_PI_2;
+    for (int i = 0; i < wedges; ++i) {
+        
+//        startAngle = endAngle;
+        endAngle  += [[_percentArray objectAtIndex:i] floatValue] * frac;
+        [_mThetaArray addObject:[NSNumber numberWithFloat:endAngle]];
+    }
+}
+
+
+- (void)startedAnimate {
+    [self performSelector:@selector(delayAnimate) withObject:nil afterDelay:0.0f];
+}
+
+#pragma mark -
+#pragma mark handle rotation angle
+- (float)thetaForX:(float)x andY:(float)y {
+    if (IS_ZERO_FLOAT(y)) {
+        if (x < 0) {
+            return M_PI;
+        } else {
+            return 0;
+        }
+    }
+    
+    float theta = atan(y / x);
+    if (x < 0 && y > 0) {
+//        NSLog(@"x<0,y>0");
+        theta = M_PI + theta;
+    }
+    else if (x < 0 && y < 0) {
+        theta = M_PI + theta;
+    }
+//    else if (x > 0 && y < 0) {
+//        theta = 2 * M_PI + theta;
+//    }
+    return theta;
+}
+
+/* 计算将当前以相对角度为单位的触摸点旋转到绝对角度为newTheta的位置所需要旋转到的角度 */
+- (float)rotationThetaForNewTheta:(float)newTheta {
+    float rotationTheta;
+    if (_mRelativeTheta > (3 * M_PI / 2) && (newTheta < M_PI / 2)) {
+        rotationTheta = newTheta + (2 * M_PI - _mRelativeTheta);
+    } else {
+        rotationTheta = newTheta - _mRelativeTheta;
+    }
+    // 返回最后旋转的角度
+    return rotationTheta;
+}
+
+- (float)thetaForTouch:(UITouch *)touch onView:view {
+    CGPoint location = [touch locationInView:view];
+    float xOffset    = self.bounds.size.width / 2;
+    float yOffset    = self.bounds.size.height / 2;
+    float centeredX  = location.x - xOffset;
+    float centeredY  = location.y - yOffset;
+    
+    return [self thetaForX:centeredX andY:centeredY];
+}
+
+#pragma mark -
+#pragma mark Private & handle rotation
+- (void)timerStop {
+    [_mDecelerateTimer invalidate];
+    _mDecelerateTimer = nil;
+    _mDragSpeed = 0;
+    _isAnimating = NO;
+    
+    [self performSelector:@selector(delayAnimate) withObject:nil afterDelay:0.0f];
+    return;
+}
+
+- (void)delayAnimate {
+    return ;
+    double tan2 = atan2(self.transform.b, self.transform.a);
+    
+    //根据旋转角度判断当前在那个扇区中
+    float curTheta = M_PI_2/2 - tan2;
+    curTheta = curTheta > 0?curTheta:M_PI*2+curTheta;
+    int selIndex = 0;
+    for (;selIndex < [_mThetaArray count]; selIndex++) {
+        if (curTheta < [[_mThetaArray objectAtIndex:selIndex] floatValue]) {
+            break;
+        }
+    }
+    
+    //根据当前旋转弧度和选中扇区的起止弧度,判断居中需要旋转的弧度
+    float calTheta = [[_mThetaArray objectAtIndex:selIndex] floatValue] - curTheta;
+    float fanTheta = [[_percentArray objectAtIndex:selIndex] floatValue] * self.fracValue;
+    float rotateTheta = fanTheta/2 - calTheta;
+    
+    //设置动画 选中后扇形外滑的动画
+    [UIView animateWithDuration:0.42 animations:^{
+        
+        self.transform = CGAffineTransformRotate(self.transform,rotateTheta);
+        self.pieChart.textAngle = rotateTheta;
+        
+    } completion:^(BOOL finished) {
+        
+            [self outPie];
+    }];
+    
+        [self delayAnimateStop:selIndex];
+}
+-(void) highlightPie:(int) index
+{
+    [self.pieChart pieHightlight:index];
+}
+- (void)outPie {
+    NSLog(@"out pie %@",self.selectedIndex);
+    [self.pieChart pieSelected:self.selectedIndex];
+    self.canLayerOpen = YES;
+}
+
+- (void)delayAnimateStop:(NSInteger)index {
+    float sum = 0.0;
+    for (int i = 0; i < [_percentArray count]; ++i) {
+        sum += [[_percentArray objectAtIndex:i] floatValue];
+    }
+    float percent = [[_percentArray objectAtIndex:index] floatValue]/sum;
+    self.selectedIndex = index;
+    
+    if ([self.delegate respondsToSelector:@selector(selectedFinish:index:percent:)]) {
+        [self.delegate selectedFinish:self index:index percent:percent];
+    }
+}
+
+- (void)animationDidStop:(NSString*)str finished:(NSNumber*)flag context:(void*)context {
+    _isAutoRotation = NO;
+    [self delayAnimate];
+}
+
+- (int)touchIndex {
+    int index;
+    
+    for (index = 0; index < [_mThetaArray count]; index++) {
+        if (_mRelativeTheta < [[_mThetaArray objectAtIndex:index] floatValue]) {
+            break;
+        }
+    }
+    
+    return index;
+}
+
+#pragma mark - 点击结束,触发旋转方法
+- (void)tapStopped {
+    return;
+    int tapAreaIndex = [self touchIndex];
+    
+    if (tapAreaIndex == 0) {
+        _mRelativeTheta = [[_mThetaArray objectAtIndex:0] floatValue] / 2;
+    } else {
+        _mRelativeTheta = [[_mThetaArray objectAtIndex:tapAreaIndex] floatValue]
+        - (([[_mThetaArray objectAtIndex:tapAreaIndex] floatValue]
+            - [[_mThetaArray objectAtIndex:tapAreaIndex - 1] floatValue]) / 2);
+    }
+    self.pieChart.textrelativeTheta = _mRelativeTheta;
+    if (tapAreaIndex != self.selectedIndex) {
+        if (self.canLayerOpen) {
+            [self.pieChart pieSelected:self.selectedIndex];
+            self.canLayerOpen = NO;
+        }
+        _isAutoRotation = YES;
+        [UIView beginAnimations:@"tap stopped" context:nil];
+        
+#pragma mark- 点击旋转速度
+        [UIView setAnimationDuration:0.5];
+        [UIView setAnimationDelegate:self];
+        [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
+        self.pieChart.textAngle = [self rotationThetaForNewTheta:K_POINTER_ANGLE];
+        self.transform = CGAffineTransformMakeRotation([self rotationThetaForNewTheta:K_POINTER_ANGLE]);
+        [UIView commitAnimations];
+    }
+    
+    return;
+}
+
+#pragma mark -
+#pragma mark Responder
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(pieChartView:didBeginTouch:)]) {
+        [self.delegate pieChartView:self didBeginTouch:touches];
+    }
+    
+    NSLog(@"rotated view touch began");
+    if (_isAutoRotation) {
+        return;
+    }
+    
+    _isTapStopped = IS_ZERO_FLOAT(_mDragSpeed);
+    
+    if ([_mDecelerateTimer isValid]) {
+        [_mDecelerateTimer invalidate];
+        _mDecelerateTimer = nil;
+        _mDragSpeed = 0;
+        _isAnimating = NO;
+    }
+    
+    UITouch *touch   = [touches anyObject];
+    _mAbsoluteTheta   = [self thetaForTouch:touch onView:self.superview];
+    _mRelativeTheta   = [self thetaForTouch:touch onView:self];
+    _mDragBeforeDate  = [NSDate date];
+    _mDragBeforeTheta = 0.0f;
+    
+    return;
+}
+
+-(void) setTouch_index:(int)touch_index
+{
+    _touch_index = touch_index;
+    
+    [self highlightPie:touch_index];
+//    [self outPie];
+    if ([self.delegate respondsToSelector:@selector(showDetail:index:)]) {
+        [self.delegate showDetail:self index:_touch_index];
+    }
+}
+
+- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
+{
+//    [self delayAnimate];
+       UITouch *touch   = [touches anyObject];
+        _mRelativeTheta   = [self thetaForTouch:touch onView:self];
+//        int tapAreaIndex = [self touchIndex];
+    
+    
+    self.touch_index =[self touchIndex];
+    
+   
+//    NSLog(@"touch move %f index %d",_mRelativeTheta,tapAreaIndex);
+    
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(pieChartView:didEndTouch:)]) {
+        [self.delegate pieChartView:self didEndTouch:touches];
+    }
+    
+    self.touch_index = -1;
+    if (_isAutoRotation) {
+        return;
+    }
+    
+    if (IS_ZERO_FLOAT(_mDragSpeed)) {
+        if (_isTapStopped) {
+            [self tapStopped];
+            return;
+        } else {
+            [self delayAnimate];
+            return;
+        }
+    } else if ((fabsf(_mDragSpeed) > K_MAX_SPEED)) {
+        _mDragSpeed = (_mDragSpeed > 0) ? K_MAX_SPEED : -K_MAX_SPEED;
+    }
+
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(pieChartView:didEndTouch:)]) {
+        [self.delegate pieChartView:self didEndTouch:touches];
+    }
+}
+
+#pragma -mark xypieSource
+- (NSUInteger)numberOfSlicesInPieChart:(XYRenderView *)pieChart {
+    return [_percentArray count];
+}
+
+- (CGFloat)pieChart:(XYRenderView *)pieChart valueForSliceAtIndex:(NSUInteger)index {
+    return [[_percentArray objectAtIndex:index] floatValue];
+}
+
+- (UIColor *)pieChart:(XYRenderView *)pieChart colorForSliceAtIndex:(NSUInteger)index {
+    if(index == self.touch_index)
+        return UIColor.orangeColor;
+    else
+        return [_mColorArray objectAtIndex:index];
+}
+
+- (void)animateFinish:(XYRenderView *)pieChart {
+    _isAutoRotation = NO;
+    [self startedAnimate];
+}
+
+#pragma mark - Animation
+
+- (void)pieChartAnimationBegin {
+    if (self.delegate) {
+        [self.delegate pieChartAnimationBegin];
+    }
+}
+
+- (void)pieChartAnimationEnd {
+    if (self.delegate) {
+        [self.delegate pieChartAnimationEnd];
+    }
+}
+
+@end

+ 425 - 0
Apex Mobile/Apex Mobile/fake_home.json

@@ -0,0 +1,425 @@
+{
+  "result": 2,
+  "count": 2,
+  "month": [
+    {
+      "key": "Shipment",
+      "val": "1234",
+      "color": "0x440000"
+    },
+    {
+      "key": "Container",
+      "val": "1234",
+      "color": "0x000066"
+    },
+    {
+      "key": "TEU",
+      "val": "1234",
+      "color": "0x445500"
+    }
+  ],
+  "KPI": [
+    {
+      "name": "Per ETA Shipment",
+      "total": 13423,
+      "arr_val": [
+        {
+          "title": "P7D",
+          "display": true,
+          "full_title": "Previous 7 Days",
+          "CP_val": "33.2",
+          "A_val": "2201",
+          "color": "0x440000"
+        },
+        {
+          "display": true,
+          "title": "0D",
+          "full_title": "Today",
+          "CP_val": "33.2",
+          "A_val": "325",
+          "color": "0x445500"
+        },
+        {
+          "title": "1D",
+          "display": true,
+          "full_title": "1 Day",
+          "CP_val": "33.2",
+          "A_val": "229",
+          "color": "0x045006"
+        },
+        {
+          "title": "2D",
+          "display": true,
+          "full_title": "2 Days",
+          "CP_val": "33.2",
+          "A_val": "233",
+          "color": "0x44ff66"
+        },
+        {
+          "title": "3D",
+          "display": true,
+          "full_title": "3 Days",
+          "CP_val": "33.2",
+          "A_val": "406",
+          "color": "0x005566"
+        },
+        {
+          "title": "4D",
+          "display": true,
+          "full_title": "4 Days",
+          "CP_val": "33.2",
+          "A_val": "454",
+          "color": "0x000066"
+        },
+        {
+          "title": "5D",
+          "display": true,
+          "full_title": "5 Days",
+          "CP_val": "33.2",
+          "A_val": "325",
+          "color": "0x005500"
+        },
+        {
+          "title": "6D",
+          "display": true,
+          "full_title": "6 Days",
+          "CP_val": "33.2",
+          "A_val": "342",
+          "color": "0x440066"
+        },
+        {
+          "title": "7D",
+          "display": true,
+          "full_title": "7 Days",
+          "CP_val": "33.2",
+          "A_val": "413",
+          "color": "0x4455ff"
+        },
+        {
+          "display": true,
+          "title": "O7D",
+          "full_title": "Over 7 Days",
+          "CP_val": "33.2",
+          "A_val": "8495",
+          "color": "0xff55ff"
+        },
+       {
+          "display": true,
+          "title": "12.2018",
+          "full_title": "Over 7 Days",
+          "CP_val": "33.2",
+          "A_val": "8495",
+          "color": "0xff5aaf"
+       }
+      ]
+    },
+    {
+      "name": "Per ETA Container",
+      "total": 13423,
+      "arr_val": [
+        {
+          "title": "P7D",
+          "display": true,
+          "full_title": "Previous 7 Days",
+          "CP_val": "33.2",
+          "A_val": "2201",
+          "color": "0x440000"
+        },
+        {
+          "display": true,
+          "title": "0D",
+          "full_title": "Today",
+          "CP_val": "33.2",
+          "A_val": "325",
+          "color": "0x445500"
+        },
+        {
+          "title": "1D",
+          "display": true,
+          "full_title": "1 Day",
+          "CP_val": "33.2",
+          "A_val": "229",
+          "color": "0x045006"
+        },
+        {
+          "title": "2D",
+          "display": true,
+          "full_title": "2 Days",
+          "CP_val": "33.2",
+          "A_val": "233",
+          "color": "0x44ff66"
+        },
+        {
+          "title": "3D",
+          "display": true,
+          "full_title": "3 Days",
+          "CP_val": "33.2",
+          "A_val": "406",
+          "color": "0x005566"
+        },
+        {
+          "title": "4D",
+          "display": true,
+          "full_title": "4 Days",
+          "CP_val": "33.2",
+          "A_val": "454",
+          "color": "0x000066"
+        },
+        {
+          "title": "5D",
+          "display": true,
+          "full_title": "5 Days",
+          "CP_val": "33.2",
+          "A_val": "325",
+          "color": "0x005500"
+        },
+        {
+          "title": "6D",
+          "display": true,
+          "full_title": "6 Days",
+          "CP_val": "33.2",
+          "A_val": "342",
+          "color": "0x440066"
+        },
+        {
+          "title": "7D",
+          "display": true,
+          "full_title": "7 Days",
+          "CP_val": "33.2",
+          "A_val": "413",
+          "color": "0x4455ff"
+        },
+        {
+          "display": true,
+          "title": "O7D",
+          "full_title": "Over 7 Days",
+          "CP_val": "33.2",
+          "A_val": "8495",
+          "color": "0xff55ff"
+        }
+      ]
+    }
+  ],
+  "container_list": [
+    {
+      "title": "CN - BLUELINX CORP.",
+      "icon": "status_i",
+      "serial_no": "2f8b6e8d7891b5dc2f54329f8b390e5a",
+      "hbol": "A1804370070",
+      "description": "A1804370070(3 containers)",
+      "detail": "Gate in full for a booking; CNFOC (FUZHOU  2018-04-09)",
+      "date": "04/12/2018 - 05/11/2018",
+      "port": "CNFOC - USHOU",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - WISENBAKER BUILDER SERVICES INC",
+      "icon": "status_d",
+      "serial_no": "a709973080a7d3e256b1d279a0722952",
+      "hbol": "A1804380293",
+      "description": "A1804380293(1 containers)",
+      "detail": "Empty Equipment Dispatched; CNXMN (XIAMEN, CHINA  2018-04-09)",
+      "date": "04/12/2018 - 05/09/2018",
+      "port": "CNXMN - USHOU",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - WISENBAKER BUILDER SERVICES INC",
+      "icon": "status_d",
+      "serial_no": "1eeb3dd6f90452bfb14249e56b47e792",
+      "hbol": "A1804380292",
+      "description": "A1804380292(1 containers)",
+      "detail": "Empty Equipment Dispatched; CNXMN (XIAMEN, CHINA  2018-04-09)",
+      "date": "04/12/2018 - 05/09/2018",
+      "port": "CNXMN - USHOU",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - U.S. NONWOVENS CORP.",
+      "icon": "status_i",
+      "serial_no": "39b3630b9519a95a49673c5051eb9aa1",
+      "hbol": "A1804350666",
+      "description": "A1804350666(1 containers)",
+      "detail": "Gate in full for a booking; CNTAO (QINGDAO, CHINA  2018-04-09)",
+      "date": "04/12/2018 - 05/09/2018",
+      "port": "CNTAO - USEWR",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - BUCHANAN GROUP SERVICES LLC",
+      "icon": "status_d",
+      "serial_no": "755dbe28ffaf60340d94d1098dd1eb4a",
+      "hbol": "A1804490234",
+      "description": "A1804490234(1 containers)",
+      "detail": "Empty Equipment Dispatched; CNTXG (XINGANG, CHINA  2018-04-09)",
+      "date": "04/12/2018 - 05/01/2018",
+      "port": "CNTXG - USSPQ",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - SK HOME SUPPLIES,INC",
+      "icon": "status_i",
+      "serial_no": "3ec51a90473cb9c6c4087add585bf249",
+      "hbol": "A1804380233",
+      "description": "A1804380233(1 containers)",
+      "detail": "Gate in full for a booking; CNXMN (XIAMEN, CHINA  2018-04-08)",
+      "date": "04/12/2018 - 04/29/2018",
+      "port": "CNXMN - USLAX",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - INOVATEX,LLC",
+      "icon": "status_ae",
+      "serial_no": "b9fdc7abf9ea611ddbc1233760f67175",
+      "hbol": "A1804393022A",
+      "description": "A1804393022A(1 containers)",
+      "detail": "Container loaded on vessel; CNSHA (SHANGHAI,CHINA  2018-04-09)",
+      "date": "04/09/2018 - 04/19/2018",
+      "port": "CNSHA - USLGB",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - INOVATEX,LLC",
+      "icon": "status_ae",
+      "serial_no": "0bc9739007e6b345b46d54231d0c2e66",
+      "hbol": "A1804393022",
+      "description": "A1804393022(2 containers)",
+      "detail": "Container loaded on vessel; CNSHA (SHANGHAI,CHINA  2018-04-09)",
+      "date": "04/09/2018 - 04/19/2018",
+      "port": "CNSHA - USLGB",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - INOVATEX,LLC",
+      "icon": "status_ae",
+      "serial_no": "520057dd4750d49740a8d331836c3e09",
+      "hbol": "A1804393023",
+      "description": "A1804393023(1 containers)",
+      "detail": "Container loaded on vessel; CNSHA (SHANGHAI,CHINA  2018-04-09)",
+      "date": "04/09/2018 - 04/19/2018",
+      "port": "CNSHA - USLGB",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - PROCON PACIFIC LLC",
+      "icon": "status_d",
+      "serial_no": "b098839261b8078dbcfd13f9e3786a78",
+      "hbol": "A1804394011A",
+      "description": "A1804394011A(1 containers)",
+      "detail": "Empty Equipment Dispatched; CNSHA (SHANGHAI,CHINA  2018-04-09)",
+      "date": "04/12/2018 - 04/24/2018",
+      "port": "CNSHA - USTIW",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - PROCON PACIFIC LLC",
+      "icon": "status_d",
+      "serial_no": "ef3ab0272ae647458c7dbb907e50a297",
+      "hbol": "A1804394011",
+      "description": "A1804394011(1 containers)",
+      "detail": "Empty Equipment Dispatched; CNSHA (SHANGHAI,CHINA  2018-04-09)",
+      "date": "04/12/2018 - 04/24/2018",
+      "port": "CNSHA - USTIW",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - BEATRICE HOME FASHIONS INC",
+      "icon": "status_ae",
+      "serial_no": "70d9a8dfd5eecf04b0f13826f36e921c",
+      "hbol": "A1804390023",
+      "description": "A1804390023(1 containers)",
+      "detail": "Container loaded on vessel; CNSHA (SHANGHAI,CHINA  2018-04-09)",
+      "date": "04/09/2018 - 04/19/2018",
+      "port": "CNSHA - USLGB",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - PEDI SPAS OF AMERICA",
+      "icon": "status_ae",
+      "serial_no": "0e1949c448386497f63f4f91e5873f8d",
+      "hbol": "A1804392007",
+      "description": "A1804392007(1 containers)",
+      "detail": "Container loaded on vessel; CNSHA (SHANGHAI,CHINA  2018-04-09)",
+      "date": "04/09/2018 - 04/19/2018",
+      "port": "CNSHA - USLGB",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - NEW YUNG WAH TRADING LLC",
+      "icon": "status_av",
+      "serial_no": "8f1d50262333cace45883b7798712487",
+      "hbol": "A1803310135",
+      "description": "A1803310135(4 containers)",
+      "detail": "Shipment available for pickup or delivery; USORF (NORFOLK, VA  2018-04-08)",
+      "date": "03/03/2018 - 04/08/2018",
+      "port": "THLCH - USORF",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - ATTURO TIRE CORP",
+      "icon": "status_ae",
+      "serial_no": "7da6a22ea1fc6e1748485d2ab2957c8a",
+      "hbol": "A1803350740",
+      "description": "A1803350740(1 containers)",
+      "detail": "Loaded at Relay Port; KRPUS (PUSAN,KOREA  2018-04-09)",
+      "date": "03/30/2018 - 04/18/2018",
+      "port": "CNTAO - USSEA",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - AKERS INDUSTRIES, INC.",
+      "icon": "status_vd",
+      "serial_no": "2d6d4085c7305e665cf2c125bf350fe8",
+      "hbol": "A1804310048",
+      "description": "A1804310048(1 containers)",
+      "detail": "Vessel Departure; THSGZ (SONGKHLA, THAILAND  2018-04-06)",
+      "date": "04/06/2018 - 05/26/2018",
+      "port": "THSGZ - USBOS",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - MYSTIC APPAREL COMPANY",
+      "icon": "status_i",
+      "serial_no": "491a00000a54f603b8b07c4e53c8e9c0",
+      "hbol": "A1804547045",
+      "description": "A1804547045(2 containers)",
+      "detail": "Gate in full for a booking; CNNGB (NINGBO, PRC  2018-04-09)",
+      "date": "04/12/2018 - 05/08/2018",
+      "port": "CNNGB - USNYC",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - PORT ALLIANCE LOGISTICS INC. (NY)",
+      "icon": "status_i",
+      "serial_no": "9f4555be6e416c741141303e2b8cd6c4",
+      "hbol": "A1804545062",
+      "description": "A1804545062(1 containers)",
+      "detail": "Gate in full for a booking; CNNGB (NINGBO, PRC  2018-04-09)",
+      "date": "04/12/2018 - 05/08/2018",
+      "port": "CNNGB - USNYC",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - MGL USA INC",
+      "icon": "status_i",
+      "serial_no": "0db52c871d00b26ebe62ea38ac594767",
+      "hbol": "A1804545114",
+      "description": "A1804545114(1 containers)",
+      "detail": "Gate in full for a booking; CNNGB (NINGBO, PRC  2018-04-09)",
+      "date": "04/12/2018 - 05/08/2018",
+      "port": "CNNGB - USNYC",
+      "transport_stage": "3"
+    },
+    {
+      "title": "CN - THE BEDA GROUP LLC",
+      "icon": "status_i",
+      "serial_no": "6c4dec1f0524e6f73fed1ca42796c9ea",
+      "hbol": "A1804541036",
+      "description": "A1804541036(1 containers)",
+      "detail": "Gate in full for a booking; CNNGB (NINGBO, PRC  2018-04-09)",
+      "date": "04/12/2018 - 05/08/2018",
+      "port": "CNNGB - USNYC",
+      "transport_stage": "3"
+    }
+  ]
+}