1. 程式人生 > >iOS開發之如何通過路由方式進行頁面間的跳轉

iOS開發之如何通過路由方式進行頁面間的跳轉

在你的開發過程中,是否遇到過如下的需求

  1. tableView型別的展示列表中,點選每個cell中人物頭像都可以跳轉到人物詳情,可參見微博中的頭像,同理包括轉發、評論按鈕、各種連結及linkcard。
  2. 跳轉到任意頁面
    • 產品要求,某個頁面的不同banner圖,點選可以跳轉到任何一個頁面,可能是原生的頁面A、頁面B,或者是web頁C。
    • 在web頁面,可以跳轉到任何一個原生頁面。
    • 在遠端推送中跳轉到任意指定的頁面。

以上2種需求,我想大多數開發者都遇到過,並且可以實現這種功能。畢竟,這是比較基礎的功能。但是程式碼未必那麼優雅。 

一般處理辦法

針對  1. ,一般初學者會用tar

get或者block等方法在tableView的代理方法拿到事件,並把要執行的跳轉寫到controller裡。功能是可以實現的,但問題是這種cell及相似的cell(佈局有些變化,或者多幾個少幾個控制元件)一般出現在多個頁面。這樣的話相同的程式碼就會出現在多個地方。就算把跳轉方法抽取出來寫成category,但是target或者block總是每個地方都要寫的。 

針對  2. ,初級的方法是每個地方寫一坨判斷及跳轉,高階一些是抽取出來寫在基類或者category。 

優雅的解決辦法

縱觀上面各種情況,總結起來就是一句話, 在任意的地方觸發事件(可以是推送,攔截的js跳轉,各種控制元件的點選事件)可以跳轉到任意介面。

 所以我們可以統一用一個控制跳轉的manager來完成跳轉。 

  1. 與後端約定好資料結構,例如:

    NSDictionary *target = @{@"action" : @"user",
                             @"data"   : @{@"user_id" : @(123456)}};

    就是跳轉到id為123456的使用者頁面,如果跳轉需要更多的資料,可以在data的value裡面繼續新增。

  2. 建立一個用來跳轉的類,可以起的牛x的名字,XXCoreActionManager。建立一個類方法:

    + (BOOL)doActionForTarget:(NSDictionary *)target{
        //根據你的app結構,來取得你當前的controller,由它來進行跳轉
        UIApplication *application = [UIApplication sharedApplication];
        AppDelegate *myAppDelegate = (AppDelegate *)[application delegate];
        UIViewController *viewController;
        if ([myAppDelegate getTabbarSelectedView]) {
            viewController = [myAppDelegate getTabbarSelectedView].visibleViewController;
        }else {
            return NO;
        }
    
        if([json[@"action"] isEqualToString:@"film_view"]){
            MFMaterialListViewController *materialListVC = [[MFMaterialListViewController alloc] initWithNibName:@"MFMaterialListViewController" bundle:nil];
            materialListVC.hidesBottomBarWhenPushed = YES;
            materialListVC.filmId = json[@"data"][@"film_id"];
            [viewController.navigationController pushViewController:materialListVC animated:YES];
            return YES;
        }else if([json[@"action"] isEqualToString:@"home"]){
            [myAppDelegate getTabbar].selectedIndex = 0;
            [viewController.navigationController popToRootViewControllerAnimated:YES];
            return YES;
        }
    
        return NO;
    }

    在剛才定義的資料結構中,  action 的值為需要跳轉的頁面,  data 的值跳轉所需要要的引數,比如  id 、  type等。伺服器只需要傳入相應的資料就可以用 

    [XXCoreActionManager doActionForTarget:target];

    來進行跳轉。真正的  write once,use anywhere

  3. 針對頭像、評論、轉發等多處使用的子控制元件,可以把事件由自己接收,通過XXCoreActionManager來進行跳轉。即做到了程式碼分離,使之成為真正獨立的控制元件,便於複用。下面是一個簡單例子: 

    @implementation MFUserHeadButton
    -(void)awakeFromNib{
        [self addTarget:self action:@selector(toUserDetail) forControlEvents:UIControlEventTouchUpInside];
    
    }
    
    - (void)toUserDetail{
        NSDictionary *target = @{@"action":@"user",
                               @"data":@{@"user_id":@(self.tag)}};
        [XXCoreActionManager doActionForTarget:target];
    
    }

    這就是一個簡單的實現跳轉到個人頁功能的頭像控制元件實現。

    如果你問  user_id 的值怎麼來的? 

    當然是configCell的時候傳給view的  tag 的。 

    你可能會說,我的跳轉需要多個引數啊,你一個tag不夠用啊親。

    可以定義一個NSDictionary屬性接收啊。

    如果你用原生的UI控制元件,那讓強大的runtime給你加嘍

    - (void)setDict:(NSDictionary *)dict {
            objc_setAssociatedObject(self, dictKey, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (NSDictionary *)dict {
            return objc_getAssociatedObject(self, dictKey);
    }

    總結

  4. 通過XXCoreActionManager,你可以做到無論你身在何處(哪一個controller),要到何處去(跳轉到哪一個controller),你只需要叫來XXCoreActionManager,告訴它你的目的地(target)。你就可以做到想跳就跳。真正的 write once,use anywhere 。 
  5. 針對各種有跳轉功能的控制元件,可以做到真的解耦。只需要把它放到他需要顯示的位置。告訴它對應的引數就可以了。方便複用和後期的維護。
  6. 這次想說的只是一個思路,程式碼很簡單。其實可以使用的地方還有很多。不只是跳轉各位童鞋可以自己思考。有什麼不明白的可以留言,如果覺得那裡不合適更歡迎留言指教或交流。