程序主要有两个部分组成,一个程序的显示部分,一个程序的设置部分,显示部分主要是一个可以用手指拖动圆形小球,设置部分主要是对小球的颜色和大小进行参数设置。
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;
}
@endMainViewController:
#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];
}
}
@endSettingViewController:
#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];
}
}
@endColorSettingViewController:
#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