IOS 開發學習(3): IOS UI架構設計

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


附註:

參考 1: 蘋果教程: UIViewControler知識

參考2:  中槍:  XCode ios iphone 變態的資源管理   非常混亂的說....

參考3:  中槍, 刪除默認的view之後產生的新問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章