IOS 严格秉承MVC模式, 即每个View的出现将有相应的Controller负责其逻辑事物, 因此IOS的UI设计中需要首先考虑MVC的问题. 在本博客中,在兼顾MVC的同时,考虑了两点设计中常用的问题。
1. IOS中对可重用UI的处理(能重用的UI通过Controller特别封装, 提供给其它View进行重用)
UI涉及的一个非常重要的问题,跟程序设计也是一样, 如何管理冗余(即重复信息)的信息, 冗余度的处理实际上不单单是程序设计的死敌,同样是管理的死敌(冗余代码是Bug的温床,同样如此,雷同UI是用户体验的死敌)。
对付重复性,我们这里一个小需求是, 如何实现一个类似于ListView的功能, 让所有的UI的小Item都能不断的加入到父面板中? UI如下:
图:不断增加一个重复的UI
当然,也许有人说用UITableView可以做到, 但是更个性化的Item, 会很需要一个类似的结构来达成我们的目的。并且,你一定会面临这样的问题,相同的数据结构,需要用同一个UI展示。当你辛苦的设计好一个UI以及逻辑之后,发现在另外相似的情况下复用,已经痛不欲生,因此, 这里我们采用的一种方式是: 封装好一个小的UI. 然后随处可用。
a. 隔离
图: 父面板实际上可以是任意的
图:在任意需要的地方,调用这个小东西
b. 代码中加载
//
// KEYI_ViewController.m
// LoadPartView
//
// Created by 尘 凡 on 12-12-28.
// Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//
#import "KEYI_ViewController.h"
@interface KEYI_ViewController ()
@end
@implementation KEYI_ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//仅仅只是为了获取view的大小, 这个controller设置为autoRelease
LiteController *tempControl = [[[LiteController alloc] initWithNibName:@"LiteController" bundle:nil] autorelease];
UIView *liteView = tempControl.view;
CGPoint point = liteView.center;
CGSize size = liteView.bounds.size;
//不知道为什么, 需要代码初始化这个ScrollView, IB拖拉的方式构造界面,会无效
UIScrollView *parentView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
[self.view addSubview:parentView];
int len = 75;
for (int i = 0; i < len; i++) {
CGFloat centX = point.x;
CGFloat centY = point.y + i * size.height;
NSString *string = [NSString stringWithFormat:@"%d",i];
[self addItems:centX :centY:parentView:string];
}
parentView.contentSize = CGSizeMake(320, len* size.height);
parentView.scrollEnabled = YES;
}
- (void) addItems:(CGFloat)centX:(CGFloat)centY:(UIScrollView *)parentView:(NSString*)title
{
LiteController *contr = [[LiteController alloc] initWithNibName:@"LiteController" bundle:nil];
UIView *aItem = contr.view;
[contr.textLabel setText:title];
aItem.center = CGPointMake(centX, centY);
aItem.backgroundColor = [UIColor grayColor];
[parentView addSubview:aItem];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)dealloc {
[super dealloc];
}
@end
2. IOS中对个性化页面的处理: 个性化中,公用UI进行提炼, 个性化的UI自己负责自己的Controller以及XIB文件
下图是一个典型的个性化页面处理情况,点击4个Tab按钮将出现不同的UI.
面对这样的个性化特征很强的界面, 按照程序设计的低耦合原则, 应该将可变化的部分, 安插在影响最小的位置,比如【注册】的UI/逻辑不能影响【登陆】的UI以及逻辑, 这里,我是按照这样的方式:
a. 公共部分, 如上层按钮, 放在一个controller中. 见下图:
图: 一个全局的Controller, 相当PC中CPU的作用: 组装
b. 各个按钮对应的不同界面,各自建立Controller. 见下图:
图: 【登陆】已经被封装到自己的Controller, 最小耦合度原则
图: 【注册】已经被封装到自己的Controller, 最小耦合度原则
c. 关键的代码, 加载各自不同的Controller
头文件
//
// ControllerUsrMgr.h
// keyiApp
//
// Created by 尘 凡 on 12-12-14.
// Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "ControllerMod.h"
#import "ControllerLogin.h"
#import "ControllerRegister.h"
#import "ControllerForget.h"
#import "ToolUI.h"
@interface ControllerUsrMgr : UIViewController
{
IBOutlet UILabel *selTitle;
IBOutlet UIButton *changeBtn;
IBOutlet UIButton *forgotBtn;
IBOutlet UIButton *regBtn;
IBOutlet UIButton *loginBtn;
IBOutlet UIView *parentView;
IBOutlet UILabel *titleInfo;
NSArray *btnArr;
NSArray *selImgArr;
NSArray *unSelImgArr;
NSArray *upperTitle;
NSArray *lowerTitle;
ControllerLogin *loginCtr;
ControllerRegister *registerCtrl;
}
- (IBAction)actionLogin:(UIButton *)sender;
- (IBAction)actionRegister:(UIButton *)sender;
- (IBAction)actionForgot:(UIButton *)sender;
- (IBAction)actionChange:(UIButton *)sender;
@end
源文件
//
// ControllerUsrMgr.m
// keyiApp
//
// Created by 尘 凡 on 12-12-14.
// Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//
#import "ControllerUsrMgr.h"
@interface ControllerUsrMgr ()
@end
@implementation ControllerUsrMgr
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
unSelImgArr = [[NSArray alloc] initWithObjects:@"usr_mgr_login_nosel.png",@"usr_mgr_reg_nosel.png",@"usr_mgr_mod_nosel.png",@"usr_mgr_login_nosel.png", nil];
selImgArr = [[NSArray alloc] initWithObjects:@"usr_mgr_login_sel.png",@"usr_mgr_reg_sel.png",@"usr_mgr_mod_sel.png",@"usr_mgr_login_sel.png", nil];
lowerTitle = [[NSArray alloc] initWithObjects:@"请填写登陆信息",@"请填写注册信息",@"请填写申诉信息",@"请填写修改信息", nil];
upperTitle = [[NSArray alloc] initWithObjects:@"用户登陆",@"用户注册",@"忘记密码",@"修改密码", nil];
loginCtr = [[ControllerLogin alloc]initWithNibName:@"ControllerLogin" bundle:nil];
registerCtrl = [[ControllerRegister alloc]initWithNibName:@"ControllerRegister" bundle:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
btnArr = [[NSArray alloc] initWithObjects:loginBtn,regBtn,changeBtn,forgotBtn, nil] ;
[self actionLogin:loginBtn];
}
- (void)viewDidUnload
{
[loginBtn release];
loginBtn = nil;
[regBtn release];
regBtn = nil;
[forgotBtn release];
forgotBtn = nil;
[changeBtn release];
changeBtn = nil;
[parentView release];
parentView = nil;
[titleInfo release];
titleInfo = nil;
[selTitle release];
selTitle = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[loginBtn release];
[regBtn release];
[forgotBtn release];
[changeBtn release];
[parentView release];
[titleInfo release];
[selTitle release];
[super dealloc];
}
- (IBAction)actionLogin:(UIButton *)sender {
[ToolUI removeSubView:parentView];
[parentView addSubview:loginCtr.view];
[self highLightButton:sender];
}
- (IBAction)actionRegister:(UIButton *)sender {
[ToolUI removeSubView:parentView];
[parentView addSubview:registerCtrl.view];
[self highLightButton:sender];
}
- (IBAction)actionForgot:(UIButton *)sender {
[ToolUI removeSubView:parentView];
[self highLightButton:sender];
}
- (void) pressOne:(UIButton *)curBtn {
if (curBtn == loginBtn)
{
[curBtn performSelector:@selector(highLightButton:) withObject:curBtn afterDelay:0.1];
}
}
- (void) highLightButton:(UIButton *)b{
for (int i = 0; i < btnArr.count; i++) {
UIButton *item = [btnArr objectAtIndex:i];
NSString *unSel = [unSelImgArr objectAtIndex:i];
NSString *sel = [selImgArr objectAtIndex:i];
if (b == item) {
[item setBackgroundImage:[UIImage imageNamed:sel] forState:UIControlStateNormal];
[selTitle setText:[upperTitle objectAtIndex:i]];
[titleInfo setText:[lowerTitle objectAtIndex:i]];
}
else {
[item setBackgroundImage:[UIImage imageNamed:unSel] forState:UIControlStateNormal];
}
}
}
- (IBAction)actionChange:(UIButton *)sender {
[ToolUI removeSubView:parentView];
[self highLightButton:sender];
}
@end
附注: