Bij het werken met gegevensintensieve toepassingen moet een ontwikkelaar vaak meer doen dan alleen lijsten met gegevensrecords weergeven in een tabelweergave. Met de CorePlot-bibliotheek kunt u verbluffende gegevensvisualisaties toevoegen aan uw toepassingen. Ontdek hoe in deze Tuts + Premium-serie!
De laatste keer hebben we ons bezig gehouden met het maken van een staafdiagram, het aanpassen van de staafkleuren en het toevoegen van aangepaste labels aan onze as als we aangepaste tekst willen weergeven in plaats van alleen getallen.
Deze keer bespreken we hoe we de logica van onze controller kunnen abstraheren in een meer herbruikbaar gegevensbronobject. Zodra we dit onder de knie hebben, bespreken we hoe dezelfde gegevens worden weergegeven als het staafdiagram, behalve dat dit dit keer als een cirkeldiagram wordt weergegeven!
Voordat we de datalogica gaan abstraheren, gaan we onze basisklassen voor het cirkeldiagram maken. Net als de vorige keer, moeten we een nieuwe weergavecontroller voor de grafiek maken. Laten we het 'STPieGraphViewController' noemen.
Merk op dat we deze keer geen weergave hoeven te maken omdat we 'STGraphView' kunnen gebruiken. Voordat we beginnen met het opzetten van dingen gaan we naar STStudentListViewController.h en STPieGraphViewController.h importeren. We moeten ons ook conformeren aan het protocol STPieGraphViewControllerDelegate (dat we later zullen maken):
@interface STStudentListViewController: UIViewController
Schakel over naar het .m-bestand. We moeten een knop aan het actielijst toevoegen. Zoek de methode graphButtonWasSelected:. We gaan de tekst van de tweede knop bewerken en een derde toevoegen:
- (void) graphButtonWasSelected: (id) afzender UIActionSheet * graphSelectionActionSheet = [[[UIActionSheet alloc] initWithTitle: @ "Kies een grafiek" delegate: self cancelButtonTitle: @ "Cancel" destructiveButtonTitle: nil otherButtonTitles: @ "Enrollment in time", @ "Betreftstotalen - Bar", @ "Betreft totalen - Pie", nul] autorelease]; [graphSelectionActionSheet showInView: [[UIApplication sharedApplication] keyWindow]];
Spring nu in de actionSheet: clickedButtonAtIndex: methode en voeg een clausule toe voor buttonIndex == 2:
else if (buttonIndex == 2) STPieGraphViewController * graphVC = [[STPieGraphViewController alloc] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: self]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [self presentModalViewController: graphVC geanimeerd: YES]; [graphVC release];
Net als de vorige keer zal het enkele waarschuwingen tonen omdat STPieGraphViewController geen gedelegeerde of managedObjectContext-eigenschap heeft.
Dus spring in STPieGraphViewController.h. Importeer 'CorePlot-CocoaTouch.h' en voeg de volgende eigenschappen en protocolverklaringen toe:
@protocol STPieGraphViewControllerDelegate @required - (void) doneButtonWasTapped: (id) afzender; @end @interface STPieGraphViewController: UIViewController@property (nonatomic, strong) CPTGraph * grafiek; @property (nonatomic, assign) id delegeren; @property (nonatomic, strong) NSManagedObjectContext * managedObjectContext; @einde
Het is belangrijk om erop te wijzen dat we deze keer niet voldoen aan CPTPieChartDataSource. Dit komt omdat we de grafische datalogica van STBarGraphViewController abstraheren naar een aparte dataSource-klasse. Maar voordat we dat doen, laten we het afmaken. Importeer in het .m-bestand 'STGraphView.h', synthetiseer de eigenschappen en implementeer de dealloc-methode.
Stel ten slotte de methoden loadView en viewDidLoad in, zoals hieronder:
- (ongeldig) loadView [super loadView]; [self setTitle: @ "Inschrijving op onderwerp"]; [self setView: [[[STGraphView alloc] initWithFrame: self.view.frame] autorelease]]; CPTTheme * defaultTheme = [CPTTheme themeNamed: kCPTPlainWhiteTheme]; [self setGraph: (CPTGraph *) [defaultTheme newGraph]]; - (void) viewDidLoad [super viewDidLoad]; STGraphView * graphView = (STGraphView *) [zelfweergave]; [[graphView chartHostingView] setHostedGraph: [zelfgrafiek]]; // Sta toe dat gebruiker teruggaat naar UINavigationItem * navigationItem = [[[UINavigationItem alloc] initWithTitle: self.title] autorelease]; [navigationItem setHidesBackButton: YES]; UINavigationBar * navigationBar = [[[UINavigationBar alloc] initWithFrame: CGRectMake (0, 0, self.view.frame.size.width, 44.0f)] autorelease]; [navigationBar pushNavigationItem: navigationItem animated: NO]; [self.view addSubview: navigationBar]; [navigationItem setRightBarButtonItem: [[[UIBarButtonItem alloc] initWithTitle: @ "Gereed" stijl: UIBarButtonItemStyleDone target: [self delegate] actie: @selector (doneButtonWasTapped :)] autorelease] geanimeerd: NO];
Het bovenstaande zou nu bekend moeten zijn. Laten we dus kijken naar het abstraheren van de grafische logica in een aparte klasse.
We hebben al de logica geschreven voor het verkrijgen van gegevens voor het totale aantal studenten in alle vakken; we willen het niet nog een keer schrijven, gelukkig hoeven we dat niet te doen. Alle gegevensbronprotocollen voor de plots overerven van 'CPTPlotDataSource' en het is dit protocol dat numberOfRecordsForPlot: en numberForPlot: fieldEnum: recordIndex-methoden bevat.
Maak een klasse met de naam 'STAbstractSubjectDataSource.h' (overgenomen van NSObject) in een nieuwe groep genaamd 'DataSource' in de grafische groep. Voor het headerbestand importeert u 'CorePlot-CocoaTouch.h' en plaatst u de volgende eigenschappen en methodeaangiften:
@interface STAbstractSubjectEnrollementDataSource: NSObject@property (nonatomic, strong) NSManagedObjectContext * managedObjectContext; - (id) initWithManagedObjectContext: (NSManagedObjectContext *) aManagedObjectContext; - (float) getTotalSubjects; - (float) getMaxEnrolled; - (NSArray *) getSubjectTitlesAsArray; @einde
We abonneren ons op het 'CPTPlotDataSource'-protocol. We maken een aangepaste init-methode die door een managedObjectContext loopt, zodat het object toegang heeft tot de gegevensopslag. Ten slotte zijn er drie hulpmethoden die kunnen helpen bij het verkrijgen van informatie over de onderwerpen en inschrijving. Dit zijn dezelfde methoden die momenteel bestaan in STBarGraphViewController. We gaan ze naar de gegevensbronmethode verplaatsen.
Afgezien van de methode init bevat het bestand .m geen nieuwe code die u nog niet eerder hebt gezien. Het is gewoon een kwestie van het verplaatsen van alle bestaande code van STBarGraphViewController naar het dataSource-object. De methoden die u moet verplaatsen zijn:
Zorg er ook voor dat je de aangepaste init methode toevoegt:
- (id) initWithManagedObjectContext: (NSManagedObjectContext *) aManagedObjectContext self = [super init]; if (self) [self setManagedObjectContext: aManagedObjectContext]; terugkeer zelf;
Nu hebben we een gegevensbronobject dat de basisgegevens voor zowel de cirkel als het staafdiagram kan leveren. De abstracte gegevensbron geeft ons echter niet alles wat we nodig hebben, de barFillForBarPlot: recordIndex kan niet worden geïmplementeerd omdat het deel uitmaakt van CPTBarPlotDataSource. We zullen onze abstracte klasse moeten uitbreiden naar iets specifieks voor barplots.
Maak een nieuw object in de gegevensbrongroep 'STBarGraphSubjectEnrollementDataSource' die onze abstracte klasse uitbreidt. In de header abonneren op 'CPTBarPlotDataSource:
- (id) initWithManagedObjectContext: (NSManagedObjectContext *) aManagedObjectContext @interface STBarGraphSubjectEnrollementDataSource: STAbstractSubjectEnrollementDataSource
En implementeer in het .m-bestand de methode barFillForBarPlot:
#pragma mark - CPTBarPlotDataSource-methoden - (CPTFill *) barFillForBarPlot: (CPTBarPlot *) barPlot recordIndex: (NSUInteger) index CPTColor * areaColor = nil; switch (index) case 0: areaColor = [CPTColor redColor]; breken; case 1: areaColor = [CPTColor blueColor]; breken; geval 2: areaColor = [CPTColor orangeColor]; breken; geval 3: areaColor = [CPTColor greenColor]; breken; standaard: areaColor = [CPTColor purpleColor]; breken; CPTFill * barFill = [CPTFill fillWithColor: areaColor]; terugkeer barFill;
Ga nu terug naar uw STBarGraphViewControllers-headerbestand en importeer de nieuwe staafgrafiekgegevensbron. U kunt nu het abonnement 'CPTBarPlotDataSource' verwijderen. Spring in het .m-bestand en verwijder alle methoden behalve loadView, viewDidLoad en dealloc. We hebben ze niet meer nodig.
We moeten een aanwijzer naar de gegevensbron houden en vervolgens de aanwijzer loslaten wanneer het aanzicht hiermee is voltooid. In de private interface, de eigenschap declareren en vervolgens samenvoegen:
@interface STBarGraphViewController () @property (nonatomic, retain) STBarGraphSubjectEnrollementDataSource * barGraphDataSource; @end @implementation STBarGraphViewController @ delegate delegeren; @synthesize managedObjectContext; @synthetiseer grafiek; @ synthetiseer barGraphDataSource;
Zorg ervoor dat je het ook vrijgeeft in de dealloc-methode. Maak een nieuw exemplaar en stel het in als onze eigenschap in de loadView-methode:
[self setBarGraphDataSource: [[[STBarGraphSubjectEnrollementDataSource alloc] initWithManagedObjectContext: [self managedObjectContext]] autorelease]];
In de viewDidLoad-methode moeten we de hulpmethoden van onze gegevensbron gebruiken voor het berekenen van de plotruimte en de aangepaste labels:
CPTXYPlotSpace * studentPlotSpace = (CPTXYPlotSpace *) [graph defaultPlotSpace]; [studentPlotSpace setXRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) length: CPTDecimalFromInt ([[self barGraphDataSource] getTotalSubjects] + 1)]]; [studentPlotSpace setYRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) length: CPTDecimalFromInt ([[self barGraphDataSource] getMaxEnrolled] + 1)]];
NSArray * subjectsArray = [[self barGraphDataSource] getSubjectTitlesAsArray];
Opslaan, bouwen en uitvoeren. Alles zou moeten werken zoals voorheen. Als dat zo is, kunnen we aan de slag gaan met het maken van onze taartgrafiek!
We willen een specifieke gegevensbron maken voor het cirkeldiagram, net zoals we deden voor het staafdiagram voor het geval we specifieke cirkeldiagramgegevensbronnen moesten implementeren. Maak een klasse met de naam 'STPieGraphSubjectEnrollementDataSource' die overerft van 'STAbstractSubjectEnrollementDataSource'. In het headerbestand abonneert u zich op het protocol 'CPTPieChartDataSource'. We zullen nog geen specifieke cirkeldiagramgegevensbronmethoden implementeren, daar zullen we later op terugkomen.
Nu we gegevensbronnen hebben, is het maken van de taartgrafiek eenvoudig! Spring in de STBPieGraphViewController.m en importeer het cirkeldiagramgegevensbronobject. Verklaar het als een eigenschap in het .m-bestand, zoals we het de vorige keer deden:
@interface STPieGraphViewController () @property (nonatomic, strong) STPieGraphSubjectEnrollementDataSource * pieChartDataSource; @end @implementation STPieGraphViewController @synthesize managedObjectContext; @synthesize delegate; @synthetiseer grafiek; @synthesize pieChartDataSource;
Maak en stel het nu in loadView:
[self setPieChartDataSource: [[[STPieGraphSubjectEnrollementDataSource alloc] initWithManagedObjectContext: [self managedObjectContext]] autorelease]];
Ten slotte moeten we in de viewDidLoad-methode ons cirkeldiagram maken, dit aan onze GraphView toevoegen en de standaardas verwijderen:
STGraphView * graphView = (STGraphView *) [zelfweergave]; [[graphView chartHostingView] setHostedGraph: [zelfgrafiek]]; CPTPieChart * pieChart = [[CPTPieChart alloc] initWithFrame: [graph bounds]]; [pieChart setPieRadius: 100.00]; [pieChart setIdentifier: @ "Subject"]; [pieChart setStartAngle: M_PI_4]; [pieChart setSliceDirection: CPTPieDirectionCounterClockwise]; [pieChart setDataSource: pieChartDataSource]; [graph addPlot: pieChart]; [graph setAxisSet: nihil]; [graph setBorderLineStyle: nil];
Het grootste deel van het bovenstaande moet bekend voorkomen. Merk op dat het niet expliciet een 'plot' wordt genoemd omdat het niet afhankelijk is van een x-as of y-as, maar we behandelen het nog steeds grotendeels hetzelfde. Er zijn een aantal cirkeldiagram-specifieke dingen die we hier ook doen. We creëren een taartstraal en een starthoek. We stellen ook een slice-richting in. Uiteindelijk stellen we de 'axisSet' van de grafiek op nul, zodat we de x- en y-lijnen niet krijgen.
En dat zou alles moeten zijn. Bouw en ren naar je cirkeldiagram.
Dit is goed, maar het zou kunnen doen met een indicatie van wat elke kleur vertegenwoordigt. Een goede manier om dit te doen is door legendes te gebruiken. Hiertoe maken we een 'CPTLegend' object dat we aan onze grafiek toevoegen en een gedelegeerde methode implementeren die de relevante titel voor de legenda retourneert.
Laten we eerst het CPTLegend-object maken. Voer in onze viewDidLoad-methode de volgende code in waar we ons cirkeldiagram maken:
CPTLegend * theLegend = [CPTLegend legendWithGraph: [self graph]]; [theLegend setNumberOfColumns: 2]; [[zelfgrafiek] setLegend: theLegend]; [[zelfgrafiek] setLegendAnchor: CPTRectAnchorBottom]; [[zelfgrafiek] setLegendDisplacement: CGPointMake (0.0, 30.0)];
Dit maakt een legenda en voegt deze toe aan ons grafiekobject. Het aantal kolommen bepaalt hoe de legendatitels worden weergegeven. Vervolgens stellen we enkele attributen in op het grafiekobject die bepalen waar de legenda wordt geplaatst (de onderkant) en enige verplaatsing om te zorgen dat deze volledig zichtbaar is in de weergave.
We moeten de legende echter nog steeds voorzien van titels. Er is een methode specifiek voor CPTPieChartDataSource die ons in staat stelt om dit te doen. Spring in de cirkeldiagramgegevensbron en voer de volgende code uit:
#pragma mark - CPTPieChartDataSource - (NSString *) legendTitleForPieChart: (CPTPieChart *) pieChart recordIndex: (NSUInteger) index NSError * error = nil; NSFetchRequest * request = [[NSFetchRequest alloc] init]; NSEntityDescription * entity = [NSEntityDescription entityForName: @ "STSubject" inManagedObjectContext: [self managedObjectContext]]; NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "subjectID ==% d", index]; [request setEntity: entity]; [request setResultType: NSDictionaryResultType]; [verzoek setPredicate: predicaat]; [request setReturnsDistinctResults: NO]; [request setPropertiesToFetch: [NSArray arrayWithObject: @ "subjectName"]]; NSArray * titleStrings = [[self managedObjectContext] executeFetchRequest: request error: & error]; NSDictionary * fetchedSubject = [titleStrings objectAtIndex: 0]; return [fetchedSubject objectForKey: @ "subjectName"];
Deze methode krijgt gewoon de index van de legenda en haalt de titel uit het gegevensarchief als een tekenreeks en retourneert deze.
Bouw en voer uit en je zou een informatieve taartgrafiek moeten hebben!
We hebben besproken hoe de datalogica van de controller kan worden samengevoegd tot een afzonderlijk object dat eenvoudiger te beheren en uit te breiden is. We hebben ook de basis besproken van het maken van een cirkeldiagram.
Dat brengt ons tot het einde van de serie. Ik hoop dat je deze tutorials nuttig hebt gevonden. Er is veel meer dat CorePlot kan doen, maar dit zou je een solide basis moeten geven om op te bouwen. Veel succes met het toevoegen van grafieken aan uw eigen projecten!