程序主要有两个部分组成,一个程序的显示部分,一个程序的设置部分,显示部分主要是一个可以用手指拖动圆形小球,设置部分主要是对小球的颜色和大小进行参数设置。
1.1 View-ViewController
主要有三个ViewController,一个是用于显示的MainViewController,还有一个是用于设置的SetingsViewController,还有一个是用于设置小球颜色ColorSettingViewController.
一个RoundBallView,进行显示小球的View。
程序第一次开启的时候,小球的坐标是界面上一个(30,30)这个位置,小球颜色为红色,直径为50像素。SettingsView的Color选项为Red,Size为最小值50。ColorSettingView的CheckMark为Red。
MainView主要对小球进行拖动操作,程序重启后,小球的位置是最后一次拖动的坐标。
SetingsViewController的第一表格引导进入ColorSettingView,SetingsViewController的第二表格设置小球大小的变化,MainView始终保持小球最后一次设置的大小,小球的直径的最大值为100,最小值为50。
在ColorSettingViewController进行颜色参数的改变后能直接引起MainViewController中小球颜色对应变化,还有SetingsView的当前颜色的文字描述的对应变化,还有ColorSettingView自身的CheckMark的所在行。
程序开启的时候始终保持上次最终的状态。
MainView进入SetingView为垂直进入,SetingView进入ColorSettingView为导航横向进入。
1.2 Controller
MainViewController,SetingViewController ,ColorSettingViewController三个都是简单ViewController,MainViewController,SetingViewController可以直接继承UIViewController, ColorSettingViewController继承UITableViewController
RoundBallView继承UIView.
我们先看RoundBallView,绘制球的类:
#import "RoundBallView.h" @implementation RoundBallView @synthesize ball = _ball; - (void)dealloc { [_ball release]; [super dealloc]; } - (id)initWithFrame:(CGRect)frame ball:(BallModel *)aBall { if (self = [super initWithFrame:frame]) { _ball = [aBall retain]; } return self; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { [super drawRect:rect]; // Drawing code CGContextRef ctx = UIGraphicsGetCurrentContext(); [[UIColor whiteColor] set]; CGContextFillRect(ctx, rect); [_ball.color set]; CGRect ballRect = CGRectMake(_ball.location.x - _ball.radius, _ball.location.y - _ball.radius, _ball.radius * 2, _ball.radius * 2); CGContextFillEllipseInRect(ctx, ballRect); CGContextStrokePath(ctx); } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint touchPoint = [touch locationInView:self]; CGFloat dltX, dltY; dltX = touchPoint.x - _ball.location.x; dltY = touchPoint.y - _ball.location.y; CGFloat dest = sqrtf(powf(dltX, 2) + powf(dltY, 2)); if (dest > _ball.radius) { _draging = NO; return; } _draging = YES; _dltPoint = CGPointMake(dltX, dltY); } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if (!_draging) { return; } { CGRect redrawRect = CGRectMake(_ball.location.x - _ball.radius, _ball.location.y - _ball.radius, _ball.radius * 2, _ball.radius * 2); _ball.location = CGPointMake(-_ball.radius * 2, -_ball.radius * 2); [self setNeedsDisplayInRect:redrawRect]; } UITouch *touch = [touches anyObject]; CGPoint touchPoint = [touch locationInView:self]; CGPoint pointLocation = touchPoint; pointLocation = CGPointMake(pointLocation.x - _dltPoint.x, pointLocation.y - _dltPoint.y); _ball.location = pointLocation; { CGRect redrawRect = CGRectMake(_ball.location.x - _ball.radius, _ball.location.y - _ball.radius, _ball.radius * 2, _ball.radius * 2); [self setNeedsDisplayInRect:redrawRect]; } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { _draging = NO; } @end
然后是Ball:
#import "BallModel.h" #import "AppDelegate.h" @implementation BallModel @synthesize color, radius, location; - (void)dealloc { [color release]; [super dealloc]; } - (id)initWithColor:(UIColor *)aColor location:(CGPoint)aPoint radius:(CGFloat)itsRadius { if (self = [super init]) { self.color = aColor; self.location = aPoint; self.radius = itsRadius; } return self; } + (BallModel *)defaultBall { static BallModel *_instance = nil; if (nil == _instance) { NSDictionary *archive = nil; archive = [NSKeyedUnarchiver unarchiveObjectWithFile:[AppDelegate archiveFilename]]; if (nil == archive) { archive = [NSDictionary dictionaryWithObjectsAndKeys: [UIColor redColor], @"color", NSStringFromCGPoint(CGPointMake(55, 55)), @"location", [NSNumber numberWithFloat:25.0f], @"radius", nil]; } _instance = [[BallModel alloc] initWithColor:[archive objectForKey:@"color"] location:CGPointFromString([archive objectForKey:@"location"]) radius:[[archive objectForKey:@"radius"] floatValue]]; } return _instance; } @end
MainViewController:
#import "MainViewController.h" @interface MainViewController () @end @implementation MainViewController - (void)dealloc { [_ball removeObserver:self forKeyPath:@"color"]; [_ball removeObserver:self forKeyPath:@"radius"]; [_ball release]; [_canvas release]; [super dealloc]; } - (id)init { if (self = [super init]) { _ball = [BallModel defaultBall]; [_ball addObserver:self forKeyPath:@"color" options:NSKeyValueObservingOptionNew context:nil]; [_ball addObserver:self forKeyPath:@"radius" options:NSKeyValueObservingOptionNew context:nil]; } return self; } - (void)loadView { [super loadView]; _canvas = [[RoundBallView alloc] initWithFrame:[UIScreen mainScreen].bounds ball:_ball]; UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoDark]; button.frame = CGRectMake(256, 396, 64, 64); [button addTarget:self action:@selector(onInfoButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_canvas]; [self.view addSubview:button]; [_canvas release]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. } #pragma mark - 按钮事件 - (void)onInfoButtonTapped:(id)sender { SettingsViewController *settingVC = [[SettingsViewController alloc] initWithBall:_ball]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:settingVC]; [self presentModalViewController:nav animated:YES]; [settingVC release]; [nav release]; } #pragma mark - 观察者 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == _ball) { [_canvas setNeedsDisplay]; } } @end
SettingViewController:
#import "SettingsViewController.h" @implementation SettingsViewController - (void)dealloc { [_ball removeObserver:self forKeyPath:@"color"]; [_ball release]; [super dealloc]; } - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (id)initWithBall:(BallModel *)aBallModel { if (self = [self initWithStyle:UITableViewStyleGrouped]) { _ball = [aBallModel retain]; [_ball addObserver:self forKeyPath:@"color" options:NSKeyValueObservingOptionNew context:nil]; } return self; } // 颜色列表 + (NSArray *)arrayColorList { static NSArray *colorList = nil; if (nil == colorList) { colorList = [[NSArray alloc] initWithObjects: [NSDictionary dictionaryWithObjectsAndKeys: [UIColor redColor], @"color", @"Red", @"name", nil], [NSDictionary dictionaryWithObjectsAndKeys: [UIColor greenColor], @"color", @"Green", @"name", nil], [NSDictionary dictionaryWithObjectsAndKeys: [UIColor blueColor], @"color", @"Blue", @"name", nil], [NSDictionary dictionaryWithObjectsAndKeys: [UIColor yellowColor], @"color", @"Yellow", @"name", nil], [NSDictionary dictionaryWithObjectsAndKeys: [UIColor brownColor], @"color", @"Brown", @"name", nil], nil]; } return colorList; } - (void)viewDidLoad { [super viewDidLoad]; // Uncomment the following line to preserve selection between presentations. // self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(onDismissButtonTapped:)] autorelease]; self.title = @"Settings"; } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } #pragma mark - TableViewCell - (UIView *)sizeSliderView { UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(120, 0, 170, 44)]; slider.maximumValue = 50.0f; slider.minimumValue = 25.0f; slider.value = _ball.radius; slider.continuous = NO; [slider addTarget:self action:@selector(onSizeSliderValueChanged:) forControlEvents:UIControlEventValueChanged]; return [slider autorelease]; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return 2; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (nil == cell) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; } // Configure the cell... cell.textLabel.text = nil; cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleBlue; for (UIView *subview in [cell.contentView subviews]) { [subview removeFromSuperview]; } if (0 == indexPath.section) { switch (indexPath.row) { case 0: { NSArray *colorList = [SettingsViewController arrayColorList]; cell.textLabel.text = @"Color"; for (NSDictionary *colorInfo in colorList) { if ([[colorInfo objectForKey:@"color"] isEqual:_ball.color]) { cell.detailTextLabel.text = [colorInfo objectForKey:@"name"]; break; } } cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } break; case 1: { cell.textLabel.text = @"Size"; [cell.contentView addSubview:[self sizeSliderView]]; cell.selectionStyle = UITableViewCellSelectionStyleNone; } break; default: break; } } return cell; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { switch (section) { case 0: return @"Display"; break; default: break; } return nil; } #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; // Navigation logic may go here. Create and push another view controller. if (0 == indexPath.section) { switch (indexPath.row) { case 0: { ColorSettingViewController *detailViewController = [[ColorSettingViewController alloc] initWithBall:_ball]; // ... // Pass the selected object to the new view controller. [self.navigationController pushViewController:detailViewController animated:YES]; [detailViewController release]; } break; default: break; } } } #pragma mark - 按钮事件 - (void)onDismissButtonTapped:(id)sender { [self dismissModalViewControllerAnimated:YES]; } - (void)onSizeSliderValueChanged:(id)sender { if ([sender isKindOfClass:[UISlider class]]) { _ball.radius = [(UISlider *)sender value]; } } #pragma mark - 观察者 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == _ball) { [self.tableView reloadData]; } } @end
ColorSettingViewController:
#import "ColorSettingViewController.h" #import "SettingsViewController.h" @implementation ColorSettingViewController - (void)dealloc { [_ball release]; [super dealloc]; } - (id)initWithBall:(BallModel *)aBall { if (self = [self initWithStyle:UITableViewStyleGrouped]) { _ball = [aBall retain]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; // Uncomment the following line to preserve selection between presentations. // self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; self.title = @"Color"; } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return [[SettingsViewController arrayColorList] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (nil == cell) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.accessoryType = UITableViewCellAccessoryNone; // Configure the cell... NSDictionary *colorInfo = [[SettingsViewController arrayColorList] objectAtIndex:indexPath.row]; cell.textLabel.text = [colorInfo objectForKey:@"name"]; if ([[colorInfo objectForKey:@"color"] isEqual:_ball.color]) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } return cell; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (0 == section) { return @"Color Select"; } return nil; } #pragma mark - Table view delegate - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (0 == indexPath.section) { UIColor *color = [[[SettingsViewController arrayColorList] objectAtIndex:indexPath.row] objectForKey:@"color"]; _ball.color = color; [tableView reloadData]; } return indexPath; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; } @end