Când lucrați cu aplicații cu intensitate mare de date, un dezvoltator trebuie să facă deseori mai mult decât să arate liste de înregistrări de date într-o vizualizare de tabel. Biblioteca CorePlot vă va permite să adăugați vizualizări uimitoare de date la aplicațiile dvs. Aflați cum în această serie Tuts + Premium!
Ultima dată am trecut pe modul de a personaliza aspectul și stilul unui grafic grafic (sau graficul de scatter) folosind clase precum CPTMutableTextStyle și CPTMutableLineStyle. Am învățat cum să personalizăm incrementele și stilurile de numere ale axelor X și Y utilizând clasele CPTXYAxisSet și CPTXYAxis. De asemenea, am analizat modul de adăugare a mai multor parcele în graficul dvs. și modificarea metodelor sursei de date pentru a furniza datele corecte pentru parcelele potrivite, utilizând identificatorii parcelelor.
Astăzi vom lucra cu un grafic complet nou. Vom crea o diagramă de bare care arată numărul total de elevi din fiecare subiect, fiecare bar reprezentând un subiect. Vom analiza, de asemenea, modul de personalizare a aspectului graficului. Să începem!
În primul rând trebuie să adăugăm clasele relevante în proiectul nostru. Să creați un ViewController numit "STBarGraphViewController" și un "STGraphView". (Asigurați-vă că le puneți în grupurile relevante)
Observați denumirea vederii la "STGraphView" în loc de "STBarGraphView". Mergând înainte, vom folosi această vizualizare pentru a afișa barele și graficele plăcilor.
Înainte de a începe să lucrăm cu orice cod, trebuie să adăugăm un buton în fila Acțiune a vizualizării listei de elevi. Mai întâi deschideți "STStudentListViewController.h" și importați STBarGraphViewController. Adăugați STBarGraphViewControllerDelegate la lista de protocoale înregistrate (protocolul nu există încă, dar îl vom crea ulterior):
@interface STStudentListViewController: UIViewController
Apoi, sariți în fișierul .m și localizați metoda 'graphButtonWasSelected:'. Adăugați "Înscriere după subiect" în lista cu "otherButtonTitles:":
UIActionSheet * graphSelectionActionSheet = [[[UIActionSheet alocare] initWithTitle: @ "Alegeți un delegat grafic": self cancelButtonTitle: @ "Cancel" destructiveButtonTitle: nil otherButtonTitles: @ "Enrollment by time" ;
Acum găsiți metoda "actionSheet: clickedButtonAtIndex:" și modificați-o pentru a funcționa cu buttonIndex == 1:
dacă (buttonIndex == 0) STLineGraphViewController * graphVC = [[STLineGraphViewController alloc] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: auto]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [auto prezentModalViewController: graphVC animat: DA]; [release graphVC]; altfel dacă (buttonIndex == 1) STBarGraphViewController * graphVC = [[STBarGraphViewController alloc] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: auto]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [auto prezentModalViewController: graphVC animat: DA]; [release graphVC];
Din nou, aceasta va afișa câteva avertismente, deoarece nu am implementat încă proprietățile delegate sau managedObjectContext pe STBarGraphViewController.
Acum, sariți în STBarGraphViewController.h. Importați CorePlot-CocoaTouch.h și adăugați următoarea declarație de proprietate:
@ protocol STBarGraphViewControllerDelegate @required - (void) doneButtonWasTapped: (id) expeditor; @Sfârșit
Acum adăugați următoarele proprietăți:
@property (nonatomic, puternic) CPTGraph * grafic; @property (nonatomic, atribuie) iddelega; @property (nonatomic, puternic) NSManagedObjectContext * managedObjectContext;
În cele din urmă, înregistrați că această clasă va urma aceste protocoale:
@ interfață STBarGraphViewController: UIViewController
Observați că, în afară de conformarea la protocoale diferite, această clasă este aceeași ca și STLineViewController. În mod ideal, ați avea o clasă de bază care ar avea aceste proprietăți pe care le-ar subclasa pentru a reduce repetarea codului. Acest tutorial se concentrează doar pe graficul de bază, așa că ne concentrăm doar asupra modului de a lucra cel mai bine cu cadrul CorePlot. Dacă aveți cunoștințele și timpul, nu ezitați să creați clasa de bază și să utilizați moștenirea, dar o vom păstra simplu în exemplul de aici.
Apoi, sariți în fișierul .m, sintetizați proprietățile și eliberați-le în metoda dealloc.
Acum, să conectăm clasa de vizualizare cu vizualizarea controlerului. Importați "STBarGraphView.h" și adăugați următoarea metodă:
- (void) încărcareView [super loadView]; [self setTitle: @ "Înscriere după subiect"]; [auto setView: [[[STGraphView alocare] initWithFrame: self.view.frame] autorelease]]; CPTTheme * defaultTheme = [CPTTheme temăNamed: kCPTPlainWhiteTheme]; [auto setGraph: (CPTGraph *) [defaultTheme newGraph]];
Acum suntem gata să lucrăm cu vederea. Deschideți STGraphView.h, importați cadrul core plot (CorePlot-CocoaTouch.h) și adăugați următoarea declarație de proprietate:
@property (nonatomic, puternic) CPTGraphHostingView * chartHostingView;
Săriți în .m, sintetizați proprietatea și eliberați proprietatea în metoda dealloc. Apoi creați CPTGraphHostingView în metoda "initWithFrame:":
- (id) initWithFrame: Cadrul (CGRect) auto = [super initWithFrame: cadru]; dacă (auto) [auto setChartHostingView: [[[CPTGraphHostingView alin] initWithFrame: CGRectZero] autorelease]]; [chartHostingView setBackgroundColor: [UICcolor purpleColor]]; [self addSubview: chartHostingView]; întoarce-te;
În cele din urmă, creați metoda "layoutSubviews" cu următorul cod:
- (void) layoutSubviews [super layoutSubviews]; float chartHeight = auto.frame.size.height; float chartWidth = auto.frame.size.width; [[diagramă autoHostingView] setFrame: CGRectMake (0, 0, diagramWidth, chartHeight)]; [[auto-diagramăHostingView] setCenter: [centru auto]];
Veți observa că codul utilizat pentru a crea această vizualizare este exact același ca STLineGraphView. Putem folosi această vizualizare de bază pentru a lucra cu toate vizualizările de grafic care merg înainte.
Salutați înapoi în vizualizarea "STBarGraphViewController.m" și găsiți metoda "viewDidLoad". În primul rând, vrem să creăm un CPTBarPlot și să îl adăugăm în graficul nostru:
[[diagramulVizualizare graficăHostingView] setHostedGraph: [auto-grafic]]; CPTBarPlot * subjectBarPlot = [[CPTBarPlot alocare] initWithFrame: [limite grafice]]; [subjectBarPlot setIdentifier: @ "subjectEnrollement"]; [subjectBarPlot setDelegate: self]; [subjectBarPlot setDataSource: auto]; [[graful propriu] addPlot: subjectBarPlot];
În cele din urmă, să adăugăm o bară de navigare cu un buton făcut, astfel încât utilizatorul să poată reveni:
UINavigationItem * navigationItem = [[[UINavigationItem alocare] initWithTitle: self.title] autorelease]; [navigationItem setHidesBackButton: YES]; UINavigationBar * navigationBar = [[[UINavigationBar alocare] initWithFrame: CGRectMake (0, 0, auto.view.frame.size.width, 44.0f)] autorelease]; [navigationBar pushNavigationItem: navigationItem animat: NU]; [self.view addSubview: navigationBar]; [navigationItem setRightBarButtonItem: [[UIBarButtonItem alocat] initWithTitle: @ Stilul "Done": UIBarButtonItemStyleDone target: [auto delegate] acțiune: @selector (doneButtonWasTapped :)] autorelease] animat: NO;
Acum, să începem să lucrăm asupra metodelor sursă de date:
Procesul va fi similar cu modul în care am creat graficul de linie, dar vom face lucrurile un pic mai dinamice. Vom crea metode personalizate care vor oferi un spațiu corespunzător de complot. Vom adăuga, de asemenea, câteva metode sursă de date suplimentare pentru a furniza o anumită culoare pentru fiecare bara, precum și pentru titlurile axelor x.
Înainte de a ne uita la furnizarea datelor grafice, trebuie să configuram axele și intervalele vizibile. Pentru a face acest lucru avem nevoie de două metode care calculează valorile maxime x și maxim y. Declarați următoarele metode în partea de sus a fișierului .m:
[[diagramulVizualizare graficăHostingView] setHostedGraph: [auto-grafic]]; @interface STBarGraphViewController () - (float) getTotalSubjects; - (float) getMaxEnrolled; @Sfârșit
Acum implementați-le după cum urmează:
#pragma mark - Metode private - (float) getTotalSubjects NSError * error = nil; NSFetchRequest * fetchRequest = [[[NSFetchRequest alocare] init] autorelease]; NSEntityDescription * entity = [Entită NSEntityDescriptionForName: @ "STSubject" inManagedObjectContext: managedObjectContext]; [fetchRequest setEntity: entitate]; returnează [managedObjectContext countForFetchRequest: eroare fetchRequest: & eroare]; - (flotare) getMaxEnrolled float maxEnrolled = 0; NSError * eroare = zero; pentru (int i = 0; i < [self getTotalSubjects]; i++) NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"STStudent" inManagedObjectContext:managedObjectContext]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"subjectID == %d", i]; [fetchRequest setEntity:entity]; [fetchRequest setPredicate:predicate]; float subjectMax = [managedObjectContext countForFetchRequest:fetchRequest error:&error]; NSLog(@"enrolled for Subject %d is %f", i, subjectMax); [fetchRequest release]; if (subjectMax > maxEnrolled) maxEnrolled = subjectMax; return maxEnrolled;
"getTotalSubjects" obține pur și simplu un număr de subiecți din magazinul de date de bază. 'getMaxEnrolled' trece prin toate subiectele și caută cel mai mare număr de elevi din fiecare dintre ele și returnează cea mai mare valoare.
Cu ajutorul acestor metode, putem reveni la metoda noastră "viewDidLoad" și adăugăm următorul cod de mai jos unde adăugăm graficul graficului nostru:
CPTXYPlotSpace * studentPlotSpace = (CPTXYPlotSpace *) [grafic defaultPlotSpace]; [studentPlotSpace setXRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) lungimea: CPTDecimalFromInt ([self getTotalSubjects] + 1)]]; [studentPlotSpace setYRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) lungimea: CPTDecimalFromInt ([self getMaxEnrolled] + 1)]]; [[graful plotAreaFrame] setPaddingLeft: 40.0f]; [[graful plotAreaFrame] setPaddingTop: 10.0f]; [[graful plotAreaFrame] setPaddingBottom: 120.0f]; [[graful plotAreaFrame] setPaddingRight: 0.0f]; [[graful plotAreaFrame] setBorderLineStyle: nil]; CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle]; [textStyle setFontSize: 12.0f]; [textStyle setColor: [CPTColor colorWithCGColor: [[UICoror griColor] CGColor]]]; CPTXYAxisSet * axaSet = (CPTXYAxisSet *) [axaSetului grafic]; CPTXYAxis * xAxis = [axaSet xAxis]; [xAxis setMajorIntervalLength: CPTDecimalFromInt (1)]; [xAxis setMinorTickLineStyle: zero]; [xAxis setLabelingPolicy: CPTAxisLabelingPolicyFixedInterval]; [xAxis setLabelTextStyle: textStilă]; CPTXYAxis * yAxis = [axSet yAxis]; [yAceste setMajorIntervalLength: CPTDecimalFromInt (1)]; [yAxis setMinorTickLineStyle: zero]; [yAxis setLabelingPolicy: CPTAxisLabelingPolicyFixedInterval];
Cele mai multe dintre cele de mai sus ar trebui să fie familiare din ultima oară, însă, în loc să setăm valori codate greu pentru lungimea intervalului x și y max, folosim noile noastre metode pentru a crea dinamic valorile. După aceea, am setat doar o formatare a unei axe de bază și am oferit cadrului parcelei câteva plăcuțe, astfel încât axa să fie indicată în mod corespunzător.
Acum trebuie să furnizăm graficul cu datele utilizând metodele sursei de date. Furnizarea numărului de înregistrări este simplă:
#pragma marcaje - CPTBarPlotDataSourceMethods - (NSUInteger) numberOfRecordsForPlot: (CPTPlot *) complot return [self getTotalSubjects];
Acum, pentru a furniza valorile x și y pentru înregistrări:
- (NSNumber *) numărForPlot: (CPTPlot *) câmp complot: (NSUInteger) câmpEnum recordIndex: (NSUInteger) index int x = index + 1; int y = 0; Eroare NSError *; NSFetchRequest * fetchRequest = [[NSFetchRequest alocare] init]; NSEntityDescription * entity = [Entită NSEntityDescriptionForName: @ "STStudent" inManagedObjectContext: managedObjectContext]; NSPredicate * predicate = [N predicție cu predicateWithFormat: @ "subjectID ==% d", index]; [fetchRequest setEntity: entitate]; [fetchRequest setPredicate: predicat]; y = [managedObjectContext countForFetchRequest: eroare fetchRequest: & eroare]; [release fetchRequest]; comutator (fieldEnum) caz CPTScatterPlotFieldX: întoarcere [NSNumber numberWithInt: x]; pauză; cazul CPTScatterPlotFieldY: întoarcere [NSNumber numberWithInt: y]; pauză; prestabilit: pauză; returnați zero;
Metoda de mai sus este foarte asemănătoare cu modul în care furnizăm datele unui complot împrăștiat. Schimbați apelul la magazinul de date, astfel încât să luăm numărul tuturor studenților înscriși într-un subiect. De asemenea, setăm valoarea x la +1. Astfel, bara pornește de la '1' și oferă un pic de umplutură între prima bară și linia axei y.
Salvați și executați proiectul ... ar trebui să vedeți graficul de bare!
Există un pic mai mult pe care îl putem face pentru a face acest lucru mai ușor să te uiți. Vrem să dăm fiecărei bare o culoare diferită și să furnizăm numele subiectului ca etichetă pentru axa x în loc de un număr. Putem face primul cu o metodă CPTBarPlotDataSource numită 'barFillForBarPlot: recordIndex':
-(CPTFill *) barFillForBarPlot: (CPTBarPlot *) indice barPlot recordIndex: (NSUInteger) CPTColor * areaColor = nil; comutator (index) caz 0: areaColor = [CPTColor redColor]; pauză; cazul 1: areaColor = [CPTColor blueColor]; pauză; cazul 2: areaColor = [CPTColor orangeColor]; pauză; cazul 3: areaColor = [CPTColor greenColor]; pauză; implicit: areaColor = [CPTColor purpleColor]; pauză; CPTFill * barFill = [CPTFill fillWithColor: areaColor]; return barFill;
Aceasta va returna o culoare diferită pentru fiecare bar din graficul nostru. Dacă vroiai să o faci și mai elegantă, ai putea să-i faci un gradient. Este, de asemenea, o parte din graficul nostru care nu este pe deplin dinamic, deoarece dacă cineva adaugă un subiect nou, va folosi culoarea implicită. Poate că o modalitate de a face acest lucru într-o aplicație de viață reală ar fi să aveți o culoare atunci când creați un subiect nou stocat în magazinul de date
În sfârșit, să adăugăm câteva titluri personalizate pentru axele x. Pentru a face acest lucru, trebuie să lucrăm cu axa x. Identificați locul în care am creat axa x și modificați codul pentru a face următoarele:
CPTXYAxis * xAxis = [axaSet xAxis]; [xAxis setMajorIntervalLength: CPTDecimalFromInt (1)]; [xAxis setMinorTickLineStyle: zero]; [xAxis setLabelingPolicy: CPTAxisLabelingPolicyNone]; [xAxis setLabelTextStyle: textStilă]; [xAxis setLabelRotare: M_PI / 4]; NSArray * subjectsArray = [auto getSubjectTitlesAsArray]; [xAxis setAxisLabels: [NSSet setWithArray: subjectsArray]];
Există câteva modificări în codul de mai sus. În primul rând, schimbăm politica de etichetare la nici una. Acest lucru va asigura că CorePlot nu imprimă eticheta în sine și va folosi în schimb ceea ce îi oferim. Apoi, setăm rotirea etichetei astfel încât să se alinieze mai bine cu graficul. În cele din urmă, am setat proprietatea "Etichete axă" care ia un NSSet de valori NSString. Creăm NSSet folosind un NSArray creat de metoda 'getSubjectTitlesAsArray'. Această metodă încă nu există, deci să o creăm. Adăugați declarația în partea de sus a fișierului .m și apoi scrieți următoarea implementare:
- (NSArray *) getSubjectTitlesAsArray NSError * eroare = zero; NSFetchRequest * request = [[NSFetchRequest alocare] init]; NSSortDescriptor * sortDescriptor = [NSSortDescriptor sortDescriptorWithKey: @ nume subiect ascendent: YES]; NSEntityDescription * entity = [Entită NSEntityDescriptionForName: @ "STSubject" inManagedObjectContext: managedObjectContext]; [request setEntity: entitate]; [request setSortDescriptors: [NSArray arrayWithObject: sortDescriptor]]; [request setResultType: NSDictionaryResultType]; [request setReturnsDistinctResults: NU]; [cerere setPropertiesToFetch: [NSArray arrayWithObject: @ "subjectName"]]; NSArray * titleStrings = [managedObjectContext executeFetchRequest: eroare cerere: & eroare]; NSMutableArray * labelArray = [array NSMutableArray]; CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle]; [textStyle setFontSize: 10]; pentru (int i = 0; i < [titleStrings count]; i++) NSDictionary *dict = [titleStrings objectAtIndex:i]; CPTAxisLabel *axisLabel = [[CPTAxisLabel alloc] initWithText:[dict objectForKey:@"subjectName"] textStyle:textStyle]; [axisLabel setTickLocation:CPTDecimalFromInt(i + 1)]; [axisLabel setRotation:M_PI/4]; [axisLabel setOffset:0.1]; [labelArray addObject:axisLabel]; [axisLabel release]; return [NSArray arrayWithArray:labelArray];
Se întâmplă multe în codul de mai sus. Pentru a da o etichetă personalizată a graficelor, trebuie să trecem un NSSet care conține obiecte de tipul "CPTAxisLabel". Mai întâi, vom obține o serie de nume de subiecte ordonate de subjectID, astfel încât acestea vor fi în aceeași ordine ca și graficul. Apoi, pentru numarul de nume pe care le primim inapoi, ne strabateam si creem un CPTAxisLabel cu sirul de nume de subiect si un stil de text predefinit. Locația "bifați" este cea pentru care va apărea bifați. Trebuie să adăugăm 1 la valoarea noastră, deoarece începem prima bară la 1 în loc de 0. Am stabilit apoi o rotație și o compensare și o adăugăm într-o matrice. În cele din urmă, returnează matricea axelor.
Dacă salvăm și executăm proiectul, avem un graf complet, colorat, cu etichete personalizate!
Am învățat o sumă corectă pentru CorePlot această sesiune. Am învățat cum să creați un graf de bare, să modificați culorile barei și chiar să adăugați etichete personalizate pe axă.
Data viitoare vom analiza modul de realizare a unei diagrame grozave care arată aceleași date ca și graficul de bare. Prindeți data viitoare!