Home>

Jiugongge coordinate calculation

I. Requirements

Complete the layout below

Analysis

Looking for the pattern on the left,The x and y coordinates of each uiview.

Third, the realization of ideas

(1) Clear what each view is used for

(2) clear the parent-child relationship between each view,Each view has only one parent view,Has many subviews.

(3) You can first try to add grids one by one.Finally consider using a for loop to complete the creation of all uiviews

(4) Load the app data and create a corresponding number of grids based on the data length

(5) Add child controls inside the grid

(6) Assemble data to internal child controls

Fourth, the code example

//
//yyviewcontroller.m
//Nine Palace Practice
//
//created by Kong Yiji on 14-5-22.
//copyright (c) 2014 itcast. all rights reserved.
//
</p>
<p>
#import "yyviewcontroller.h"
</p>
<p>
@interface yyviewcontroller ()
@property (nonatomic, strong) nsarray * apps;
@end

@implementation yyviewcontroller
//1. Load data
-(nsarray *) apps
{
 if (! _apps) {
 nsstring * path=[[nsbundle mainbundle] pathforresource:@"app.plist" oftype:nil];
 _apps=[nsarray arraywithcontentsoffile:path];
 }
 return _apps;
}
</p>
<p>
-(void) viewdidload
{
 [super viewdidload];
 nslog (@ "%d", self.apps.count);
 //2. Complete the layout design
 //three columns
 int totalloc=3;
 cgfloat appvieww=80;
 cgfloat appviewh=90;
 cgfloat margin=(self.view.frame.size.width-totalloc * appvieww)/(totalloc+ 1);
 int count=self.apps.count;
 for (int i=0;i<count;i ++) {
 int row=i/totalloc;//row number
 //1/3=0, 2/3=0, 3/3=1;
 int loc=i%totalloc;//column number
 cgfloat appviewx=margin + (margin + appvieww) * loc;
 cgfloat appviewy=margin + (margin + appviewh) * row;
 //Create a uiview control
 uiview * appview=[[uiview alloc] initwithframe:cgrectmake (appviewx, appviewy, appvieww, appviewh)];
 //[appview setbackgroundcolor:[uicolor purplecolor]];
 [self.view addsubview:appview];
 //Create a subview in the uiview control
 uiimageview * appimageview=[[uiimageview alloc] initwithframe:cgrectmake (0, 0, 80, 50)];
 uiimage * appimage=[uiimage imagenamed:self.apps [i] [@ "icon"]];
 appimageview.image=appimage;
 [appimageview setcontentmode:uiviewcontentmodescaleaspectfit];
 //nslog (@ "%@", self.apps [i] [@ "icon"]);
 [appview addsubview:appimageview];
 //Create text label
 uilabel * applable=[[uilabel alloc] initwithframe:cgrectmake (0, 50, 80, 20)];
 [applable settext:self.apps [i] [@ "name"]];
 [applable settextalignment:nstextalignmentcenter];
 [applable setfont:[uifont systemfontofsize:12.0]];
 [appview addsubview:applable];
 //Create button
 uibutton * appbtn=[uibutton buttonwithtype:uibuttontypecustom];
 appbtn.frame=cgrectmake (10, 70, 60, 20);
 [appbtn setbackgroundimage:[uiimage imagenamed:@"buttongreen"] forstate:uicontrolstatenormal];
 [appbtn setbackgroundimage:[uiimage imagenamed:@"buttongreen_highlighted"] forstate:uicontrolstatehighlighted];
 [appbtn settitle:@"download" forstate:uicontrolstatenormal];
 appbtn.titlelabel.font=[uifont systemfontofsize:12.0];
 [appview addsubview:appbtn];
 [appbtn addtarget:self action:@selector (click) forcontrolevents:uicontroleventtouchupinside];
 }
</p>
<p>
}
</p>
<p>
-(void) click
{
 //Animated tags
 uilabel * animalab=[[uilabel alloc] initwithframe:cgrectmake (self.view.center.x-100, self.view.center.y + 20, 200, 40)];
 [animalab settext:@"Download successful"];
 animalab.font=[uifont systemfontofsize:12.0];
 [animalab setbackgroundcolor:[uicolor browncolor]];
 [animalab setalpha:0];
 [self.view addsubview:animalab];
//[uiview beginanimations:nil context:nil];
//[animalab setalpha:1];
//[uiview setanimationduration:4.0];
//[uiview commitanimations];
 //After execution,I have to delete this,Recommended block animation
 [uiview animatewithduration:4.0 animations:^ {
 [animalab setalpha:1];
 } completion:^ (bool finished) {
 //[self.view re];
 }];
}
</p>
<p>
-(void) didreceivememorywarning
{
 [super didreceivememorywarning];
}
</p>
<p>
@end

Implementation effect:

Dictionary to model

1. "Problem code" that can complete functions

1. Data loaded from plist

2. Implemented code

//
//lfviewcontroller.m
//03- Application Management
//
//created by apple on 14-5-22.
//copyright (c) 2014 heima. all rights reserved.
//
</p>
<p>
#import "lfviewcontroller.h"
</p>
<p>
@interface lfviewcontroller ()
@property (nonatomic, strong) nsarray * applist;
@end
</p>
<p>
@implementation lfviewcontroller
</p>
<p>
-(nsarray *) applist
{
 if (! _applist) {
</p>
<p>
//1. Load from mainbundle
 nsbundle * bundle=[nsbundle mainbundle];
 nsstring * path=[bundle pathforresource:@"app.plist" oftype:nil];
 _applist=[nsarray arraywithcontentsoffile:path];
 nslog (@ "%@", _applist);
 }
 return _applist;
}
</p>
<p>
-(void) viewdidload
{
 [super viewdidload];
 //There are 3 columns in total
 int totalcol=3;
 cgfloat vieww=80;
 cgfloat viewh=90;
 cgfloat marginx=(self.view.bounds.size.width-totalcol * vieww)/(totalcol + 1);
 cgfloat marginy=10;
 cgfloat starty=20;
 for (int i=0;i<self.applist.count;i ++) {
</p>
<p>
int row=i/totalcol;
 int col=i%totalcol;
 cgfloat x=marginx + (vieww + marginx) * col;
 cgfloat y=starty + marginy + (viewh + marginy) * row;
 uiview * appview=[[uiview alloc] initwithframe:cgrectmake (x, y, vieww, viewh)];
 [self.view addsubview:appview];
 //Create details inside appview
 //0>read dictionary from array
 nsdictionary * dict=self.applist [i];
 //1>uiimageview
 uiimageview * imageview=[[uiimageview alloc] initwithframe:cgrectmake (0, 0, vieww, 50)];
 imageview.image=[uiimage imagenamed:dict [@ "icon"]];
 imageview.contentmode=uiviewcontentmodescaleaspectfit;
 [appview addsubview:imageview];
 //2>uilabel
 uilabel * label=[[uilabel alloc] initwithframe:cgrectmake (0, imageview.bounds.size.height, vieww, 20)];
 //set text
 label.text=dict [@ "name"];
 label.font=[uifont systemfontofsize:12.0];
 label.textalignment=nstextalignmentcenter;
 [appview addsubview:label];
 //3>uibutton
 //uibuttontypecustom and [[uibutton alloc] init] are equivalent
 uibutton * button=[uibutton buttonwithtype:uibuttontypecustom];
 button.frame=cgrectmake (15, 70, vieww-30, 20);
 [button settitle:@"download" forstate:uicontrolstatenormal];
 //*** cannot set title directly with the following code
//button.titlelabel.text [email protected]"download";
 //@property readonly means that the pointer address of the object is not allowed to be modified
But you can modify the properties of the object
 button.titlelabel.font=[uifont systemfontofsize:14.0];
 [button setbackgroundimage:[uiimage imagenamed:@"buttongreen"] forstate:uicontrolstatenormal];
 [button setbackgroundimage:[uiimage imagenamed:@"buttongreen_highlighted"] forstate:uicontrolstatehighlighted];
 [appview addsubview:button];
 }
}
</p>
<p>
@end

3. Achieve effect

4. Code issues

In lines 62 and 69 of the above code, we are directly obtaining the data information in the plist through the dictionary key name.Need to deal with data directly in viewcontroller,If you need to use it multiple times, you may accidentally write the key name incorrectly.And the program does not report an error.In light of this, consider converting dictionary data into a model,Encapsulate the data into a model,Let the viewcontroller no longer deal directly with data,Instead, interact with the model.

In general,The setting data and the fetching data both use "string keys". When writing these keys, the editor does not have a smart prompt.Need to knock by hand.Such as:

dict [@ "name"] [email protected]"jack";
</p>
<p>
nsstring * name=dict [@ "name"];

Typing string key by hand, key is easy to write wrong

If key is written incorrectly,The compiler will not have any warnings or errors,Cause wrong data or fetch data

Dictionary-to-model

1. Dictionary to Model Introduction

schematic diagram:

The benefits of the dictionary to model:

(1) Reduce the coupling of the code

(2) All the dictionary-to-model code is processed in one place.Reduce the chance of code errors

(3) Use the attribute operations of the model directly in the program,Improve coding efficiency

(4) the caller does not need to care about any processing details inside the model

Note to dictionary-to-model:

The model should provide a constructor that can pass dictionary parameters

-(instancetype) initwithdict:(nsdictionary *) dict;
</p>
<p>
+ (instancetype) xxxwithdict:(nsdictionary *) dict;

Tip:Use read-only attributes in your models appropriately,You can further reduce the coupling of the code.

2. Code example (1)

Create a new class,Used as a data model

viewcontroller.m file code (dictionary to model)
#import "lfviewcontroller.h"
#import "lfappinfo.h"
</p>
<p>
@interface lfviewcontroller ()
@property (nonatomic, strong) nsarray * applist;
@end
</p>
<p>
@implementation lfviewcontroller
</p>
<p>
//dictionary to model
-(nsarray *) applist
{
 if (! _applist) {
 //1. Load from mainbundle
 nsbundle * bundle=[nsbundle mainbundle];
 nsstring * path=[bundle pathforresource:@"app.plist" oftype:nil];
//_applist=[nsarray arraywithcontentsoffile:path];
 nsarray * array=[nsarray arraywithcontentsoffile:path];
 //convert the array into a model,Means self.applist stores lfappinfo object
 //1. traverse the array,Convert the dictionaries in the array into appinfo objects in order and add them to a temporary array
 //2. self.applist=temporary array
</p>
<p>
nsmutablearray * arraym=[nsmutablearray array];
 for (nsdictionary * dict in array) {
 //Factory method for instantiating objects with a dictionary
 [arraym addobject:[lfappinfo appinfowithdict:dict]];
 }
 _applist=arraym;
 }
 return _applist;
}
</p>
<p>
-(void) viewdidload
{
 [super viewdidload];
 //There are 3 columns in total
 int totalcol=3;
 cgfloat vieww=80;
 cgfloat viewh=90;
 cgfloat marginx=(self.view.bounds.size.width-totalcol * vieww)/(totalcol + 1);
 cgfloat marginy=10;
 cgfloat starty=20;
 for (int i=0;i<self.applist.count;i ++) {
</p>
<p>
int row=i/totalcol;
 int col=i%totalcol;
 cgfloat x=marginx + (vieww + marginx) * col;
 cgfloat y=starty + marginy + (viewh + marginy) * row;
 uiview * appview=[[uiview alloc] initwithframe:cgrectmake (x, y, vieww, viewh)];
 [self.view addsubview:appview];
 //Create details inside appview
 //0>read appinfo in array
//nsdictionary * dict=self.applist [i];
 lfappinfo * appinfo=self.applist [i];
 //1>uiimageview
 uiimageview * imageview=[[uiimageview alloc] initwithframe:cgrectmake (0, 0, vieww, 50)];
 imageview.image=appinfo.image;
 imageview.contentmode=uiviewcontentmodescaleaspectfit;
 [appview addsubview:imageview];
 //2>uilabel
 uilabel * label=[[uilabel alloc] initwithframe:cgrectmake (0, imageview.bounds.size.height, vieww, 20)];
 //set text
 label.text=appinfo.name;
 label.font=[uifont systemfontofsize:12.0];
 label.textalignment=nstextalignmentcenter;
 [appview addsubview:label];
 //3>uibutton
 //uibuttontypecustom and [[uibutton alloc] init] are equivalent
 uibutton * button=[uibutton buttonwithtype:uibuttontypecustom];
 button.frame=cgrectmake (15, 70, vieww-30, 20);
 [button settitle:@"download" forstate:uicontrolstatenormal];
 button.titlelabel.font=[uifont systemfontofsize:14.0];
 [button setbackgroundimage:[uiimage imagenamed:@"buttongreen"] forstate:uicontrolstatenormal];
 [button setbackgroundimage:[uiimage imagenamed:@"buttongreen_highlighted"] forstate:uicontrolstatehighlighted];
 [appview addsubview:button];
 button.tag=i;
 [button addtarget:self action:@selector (downloadclick :) forcontrolevents:uicontroleventtouchupinside];
 }
}
</p>
<p>
-(void) downloadclick:(uibutton *) button
{
 nslog (@ "%d", button.tag);
 //instantiate a uilabel to display on the view,Prompt user to download complete
 uilabel * label=[[uilabel alloc] initwithframe:cgrectmake (80, 400, 160, 40)];
 label.textalignment=nstextalignmentcenter;
 label.backgroundcolor=[uicolor lightgraycolor];
 lfappinfo * appinfo=self.applist [button.tag];
 label.text=[nsstring stringwithformat:@"download%@complete", appinfo.name];
 label.font=[uifont systemfontofsize:13.0];
 label.alpha=1.0;
 [self.view addsubview:label];
 //animation effect
 //After the animation effect is completed,Remove label from view
 //head-to-tail animation,Can only do animation,It is inconvenient to handle the operation after completion
//[uiview beginanimations:nil context:nil];
//[uiview setanimationduration:1.0];
//label.alpha=1.0;
//[uiview commitanimations];
</p>
<p>
//block animation is simpler than head-to-tail animation,And can control the operation after the animation ends
 //In ios, basically use head-to-tail animation
 [uiview animatewithduration:2.0 animations:^ {
 label.alpha=0.0;
 } completion:^ (bool finished) {
 //delete label
 [label removefromsuperview];
 }];
}
</p>
<p>
@end

Model .h file code

#import<foundation/foundation.h>
</p>
<p>
@interface lfappinfo:nsobject
</p>
<p>
//application name
@property (nonatomic, copy) nsstring * name;
//application icon name
@property (nonatomic, copy) nsstring * icon;
</p>
<p>
//image
//When defining attributes,Generates getter&setter methods, and also generates an underlined member variable
//If it is a readonly property, only the getter method will be generated, and no member variables
@property (nonatomic, strong, readonly) uiimage * image;
</p>
<p>
//instancetype will let the compiler check the exact type of the instantiated object
//instancetype can only be used for return types,Cannot be used as a parameter
</p>
<p>
-(instancetype) initwithdict:(nsdictionary *) dict;
/** factory method * /
+ (instancetype) appinfowithdict:(nsdictionary *) dict;
</p>
<p>
@end

Model.m file data processing code

#import "lfappinfo.h"
</p>
<p>
@interface lfappinfo ()
{
 uiimage * _imageabc;
}
@end

@implementation lfappinfo
</p>
<p>
-(instancetype) initwithdict:(nsdictionary *) dict
{
 self=[super init];
 if (self) {
 self.name=dict [@ "name"];
 self.icon=dict [@ "icon"];
 }
 return self;
}
</p>
<p>
+ (instancetype) appinfowithdict:(nsdictionary *) dict
{
 return [[self alloc] initwithdict:dict];
}
</p>
<p>
-(uiimage *) image
{
 if (! _imageabc) {
 _imageabc=[uiimage imagenamed:self.icon];
 }
 return _imageabc;
}
</p>
<p>
@end

3. Code Example (2)

Data information:plist file

Dictionary to Model (Preliminary)

Model.h file

#import<foundation/foundation.h>
</p>
<p>
@interface lfquestion:nsobject
</p>
<p>
@property (nonatomic, copy) nsstring * answer;
@property (nonatomic, copy) nsstring * title;
@property (nonatomic, copy) nsstring * icon;
@property (nonatomic, strong) nsarray * options;
</p>
<p>
@property (nonatomic, strong) uiimage * image;
</p>
<p>
/** Instantiate member methods of an object with a dictionary * /
-(instancetype) initwithdict:(nsdictionary *) dict;
/** Class method for instantiating objects with a dictionary,Also known as factory method * /
+ (instancetype) questionwithdict:(nsdictionary *) dict;
@end

Model.m file

#import "lfquestion.h"
</p>
<p>
@implementation lfquestion
</p>
<p>
+ (instancetype) questionwithdict:(nsdictionary *) dict
{
 return [[self alloc] initwithdict:dict];
}
</p>
<p>
-(instancetype) initwithdict:(nsdictionary *) dict
{
 self=[super init];
 if (self) {
 self.answer=dict [@ "answer"];
 self.icon=dict [@ "icon"];
 self.title=dict [@ "title"];
 self.options=dict [@ "options"];
</p>
<p>
[self setvaluesforkeyswithdictionary:dict];
 }
 return self;
}
</p>
<p>
Data processing in viewcontroller.m file
</p>
<p>
-(nsarray *) questions
{
 if (! _questions) {
 nsarray * array=[nsarray arraywithcontentsoffile:[[nsbundle mainbundle] pathforresource:@"questions.plist" oftype:nil]];
 nsmutablearray * arraym=[nsmutablearray array];
 for (nsdictionary * dict in array) {
 [arraym addobject:[lfquestion questionwithdict:dict]];
 }
 _questions=arraym;
 }
 return _questions;
}

Dictionary to model (optimized)

The above code can be further optimized,Reading data from a plist file can be handed over to the model for processing.The optimized code is as follows:

Model.h file

#import<foundation/foundation.h>
</p>
<p>
@interface lfquestion:nsobject
</p>
<p>
@property (nonatomic, copy) nsstring * answer;
@property (nonatomic, copy) nsstring * title;
@property (nonatomic, copy) nsstring * icon;
@property (nonatomic, strong) nsarray * options;
</p>
<p>
@property (nonatomic, strong) uiimage * image;
</p>
<p>
/** Instantiate member methods of an object with a dictionary * /
-(instancetype) initwithdict:(nsdictionary *) dict;
/** Class method for instantiating objects with a dictionary,Also known as factory method * /
+ (instancetype) questionwithdict:(nsdictionary *) dict;
</p>
<p>
/** Load object array from plist * /
+ (nsarray *) questions;
</p>
<p>
@end

Model.m file

#import "lfquestion.h"
</p>
<p>
@implementation lfquestion
</p>
<p>
+ (instancetype) questionwithdict:(nsdictionary *) dict
{
 return [[self alloc] initwithdict:dict];
}
</p>
<p>
-(instancetype) initwithdict:(nsdictionary *) dict
{
 self=[super init];
 if (self) {
 self.answer=dict [@ "answer"];
 self.icon=dict [@ "icon"];
 self.title=dict [@ "title"];
 self.options=dict [@ "options"];
 [self setvaluesforkeyswithdictionary:dict];
 }
 return self;
}
</p>
<p>
+ (nsarray *) questions
{
 nsarray * array=[nsarray arraywithcontentsoffile:[[nsbundle mainbundle] pathforresource:@"questions.plist" oftype:nil]];
 nsmutablearray * arraym=[nsmutablearray array];
 for (nsdictionary * dict in array) {
 [arraym addobject:[lfquestion questionwithdict:dict]];
 }
 return arraym;
}
@end

Data processing code section in viewcontroller.m file

-(nsarray *) questions
{
 if (! _questions) {
 _questions=[lfquestion questions];
 }
 return _questions;
}

Supplementary content:the use of (kvc)

(1) In the data processing part of the model,Can be processed using key-value encoding

-(instancetype) initwithdict:(nsdictionary *) dict
{
 self=[super init];
 if (self) {
//self.answer=dict [@ "answer"];
//self.icon=dict [@ "icon"];
//self.title=dict [@ "title"];
//self.options=dict [@ "options"];
 //kvc (key value coding)
 //Cocoa's big move, allowing indirect modification of object property values
 //The first parameter is the value of the dictionary
 //The second parameter is a property of the class
 [self setvalue:dict [@ "answer"] forkeypath:@"answer"];
 [self setvalue:dict [@ "icon"] forkeypath:@"icon"];
 [self setvalue:dict [@ "title"] forkeypath:@"title"];
 [self setvalue:dict [@ "options"] forkeypath:@"options"];
 }
 return self;
}

(2) Use of setvaluesforkeys

The above data operation details,This can be done directly through the setvaluesforkeys method.

-(instancetype) initwithdict:(nsdictionary *) dict
{
 self=[super init];
 if (self) {
 //using setvaluesforkeys requires that the attributes of the class must exist in the dictionary,Can have more keys than in a dictionary,But not less.
 [self setvaluesforkeyswithdictionary:dict];
 }
 return self;
}

Third, supplementary notes

1.readonly attribute

(1) readonly in @property indicates that it is not allowed to modify the pointer address of the object,However, you can modify the properties of an object.

(2) When using the @property keyword to define a property,A getter&setter method is generated, and an underlined member variable is also generated.

(3) If it is a readonly property, only the getter method will be generated, and underlined member variables will not be generated.

2.instancetype

(1) instancetype will let the compiler check the exact type of the instantiated object

(2) instancetype can only be used for return types,Cannot be used as a parameter

Comparison of 3.instancetype&id

(1) instancetype in type representation,Like id, it can represent any object type

(2) instancetype can only be used on return value types,Cannot be used on parameter types like id

(3) one more advantage of instancetype than id:the compiler will detect the true type of instancetype

ios
  • Previous Java implementation verification code specific pictures (pictures, Chinese characters)
  • Next Summary of http request method libraries in Python