【iOS開發(fā)】我是這樣封裝view的

前言

一個(gè)有經(jīng)驗(yàn)的開發(fā),碰到一些特殊的UI控件饺饭,腦海中應(yīng)該是有好幾種實(shí)現(xiàn)方案的砚哗,同時(shí)也能記起一些第三方相似的開源控件。為了應(yīng)對(duì)產(chǎn)品的需求變更砰奕,UI效果的變更蛛芥,以及做到代碼的可控性,所以在開發(fā)中军援,一般的UI效果我都喜歡自己動(dòng)手去實(shí)現(xiàn)仅淑。而不是為了趕時(shí)間,或者什么的去用一些第三方的開源庫(kù)胸哥。當(dāng)然是除了一些非常通用的東西涯竟,像HUD, 下拉刷新這樣,已經(jīng)有非常好的實(shí)現(xiàn)空厌,而且很容易做定制的庐船。

示例

下面就以一個(gè)實(shí)際需求說(shuō)一下自己封裝UI的一點(diǎn)點(diǎn)經(jīng)驗(yàn):

先來(lái)看一下需求,直接上UI效果:


產(chǎn)品需求:

  1. 點(diǎn)擊寶貝分類后彈出一個(gè)懸浮菜單
  2. 菜單的內(nèi)容可能有多個(gè)嘲更,所以可能存在要上下滑動(dòng)顯示
  3. 點(diǎn)擊菜單外面要隱藏菜單筐钟,不做其它的操作

放到整個(gè)項(xiàng)目中做通用控件考慮可定制項(xiàng):

  1. 菜單是否要高亮上次選中過(guò)的菜單項(xiàng)
  2. 菜單項(xiàng)樣式可能不同
  3. 菜單顯示的位置
  4. 菜單上箭頭顯示的位置
  5. 菜單內(nèi)邊距
  6. 菜單邊線顏色
  7. 菜單項(xiàng)的文字顏色,字體大小
  8. ...

通過(guò)上面的分析可以看到赋朦,要做一個(gè)極通用的控件篓冲,還是要考慮非常多的可定制點(diǎn)的。接觸這個(gè)項(xiàng)目還不久宠哄,知道項(xiàng)目中是有一個(gè)類似的控件的壹将,于是翻出來(lái)看了一下代碼∶担可定制度很低诽俯。而且現(xiàn)在只有黑色的背景,顏色承粤,菜單項(xiàng)高度的定制屬性都沒有暴区,對(duì)項(xiàng)目不完全的熟悉闯团,不能動(dòng)通用控件,以防引起其它地方的bug颜启。github上也看到過(guò)很多類似的控件。但是要完全按設(shè)計(jì)給到的UI效果來(lái)完成浪讳,還是要做很多的定制工作缰盏。所以還是決定自己寫過(guò)。

實(shí)現(xiàn)

看UI效果淹遵,其實(shí)很簡(jiǎn)單的一個(gè)懸浮框顯示到一個(gè)view上口猜,以我寫這種彈窗的經(jīng)驗(yàn),用一個(gè)透明背景的view做為整個(gè)控件的根view透揣,加到要添加到的view上济炎,里面的菜單做一個(gè)view,添加到透明view上。其它的就細(xì)節(jié)處理辐真。

像上面這個(gè)view须尚,層次是這樣的,透明view 里面放 menu view 侍咱,menu view 里面放一個(gè)tableview 顯示菜單項(xiàng)耐床。箭頭跟menu view同級(jí),因?yàn)閙enu view 用了layer圓角楔脯,邊框撩轰。箭頭也可以考慮用layer畫。更好定制昧廷。最后顯示的時(shí)候?qū)⑼该鱲iew加到self.navigationController.view上堪嫂。

JXMenu *menu = [JXMenu showInView:self.navigationController.view point:CGPointMake(self.view.width / 4.0 - 50, self.view.height - 60 + 64) isTop:NO width:100 menuItems:self.viewModel.categoryArray];
            menu.action = ^(id data, NSInteger index) {
                
                ShopGoodsCategory *model = data;
                if (self.viewModel.currentCategory && [self.viewModel.currentCategory.id isEqualToString:model.id]) {
                    // 如果點(diǎn)擊的是相同的分類,就不再請(qǐng)求
                    return;
                }
                
                // 傳過(guò)來(lái)的就是點(diǎn)擊到的分類木柬,不用再用索引拿數(shù)據(jù) 
                self.viewModel.currentCategory = model;
                [self.collectionView.mj_header beginRefreshing];
            };

+ (JXMenu *)showInView:(UIView *)view point:(CGPoint)point isTop:(BOOL)isTop width:(CGFloat)width menuItems:(NSArray *)items {
    
    JXMenu *menu = [[JXMenu alloc] initWithFrame:view.bounds];
    
    menu.leftPoint = point;
    menu.attachView = view;
    menu.menuWidth = width;
    menu.menuItems = items;
    
    // 一定要賦值完成后再setupViews
    [menu setupViews];
    
    [view addSubview:menu];
    
    // 顯示動(dòng)畫
    [menu showAnimation];
    
    return menu;
}

關(guān)于這個(gè)顯示方法皆串,還有很多要改進(jìn)的地方。先完成產(chǎn)品需求眉枕,設(shè)計(jì)上考慮一些大的改進(jìn)點(diǎn)愚战。到后面有相關(guān)需求或者時(shí)間夠的時(shí)候可以進(jìn)行改進(jìn)。

/**
 顯示一個(gè)菜單到指定的view上
 
 isTop這個(gè)屬性其實(shí)是可以算出來(lái)的齐遵,沒做這個(gè)處理寂玲。待改進(jìn)。
 
 事件也可以通過(guò)這個(gè)顯示方法傳進(jìn)來(lái)梗摇,參數(shù)太多了拓哟,待改進(jìn)。

 @param view 要添加到view
 @param point 左側(cè)的一個(gè)頂點(diǎn),通過(guò)/isTop/來(lái)判斷是左上角還是左下角
 @param isTop 是不是左上角
 @param width 菜單的整體寬度
 @param items 這個(gè)array 里面的單個(gè)數(shù)據(jù)可以是對(duì)象伶授,要實(shí)現(xiàn) /JXMenuCellDataProtocol/
 */
+ (JXMenu *)showInView:(UIView *)view point:(CGPoint)point isTop:(BOOL)isTop width:(CGFloat)width menuItems:(NSArray *)items;

說(shuō)一下傳入的菜單項(xiàng)及點(diǎn)擊事件

傳入的顯示項(xiàng)是不確定的断序,可能是一個(gè)商品的分類流纹,也可能是幾個(gè)操作項(xiàng)。但是寫好的view是確定的违诗,就是說(shuō)view要顯示的數(shù)據(jù)是確定的漱凝。在這個(gè)例子中,要顯示的內(nèi)容就是一個(gè)title诸迟,但是數(shù)據(jù)是從接口拿回來(lái)的茸炒,拿回來(lái)后model化成了一個(gè)對(duì)應(yīng)的ShopGoodsCategory 類型的model 數(shù)組。不確定數(shù)據(jù)來(lái)源阵苇,數(shù)據(jù)形式的時(shí)候壁公,應(yīng)該用接口來(lái)跟源數(shù)據(jù)進(jìn)行對(duì)接,所以這里我定義了一個(gè)用于view顯示的數(shù)據(jù)接口绅项。讓傳進(jìn)來(lái)的model去實(shí)現(xiàn)接口紊册,就可以直接傳model數(shù)組了。這樣做的好處是快耿,在點(diǎn)擊了菜單項(xiàng)后囊陡,view可以直接返回點(diǎn)擊的數(shù)據(jù), 而不是一個(gè)唯一標(biāo)識(shí)或者一個(gè)索引什么的掀亥。

接口定義

#import <Foundation/Foundation.h>

// 菜單的數(shù)據(jù)接口
@protocol JXMenuCellDataProtocol <NSObject>

@property (nonatomic, copy, readonly) NSString *jxmenu_title;    // 要顯示的菜單項(xiàng)的標(biāo)題

@end

傳入的model實(shí)現(xiàn)接口

#import <Foundation/Foundation.h>
#import "JXMenuCellDataProtocol.h"

@interface ShopGoodsCategory : NSObject <JXMenuCellDataProtocol>

@property (nonatomic, copy) NSString *id;   // 分類id

@property (nonatomic, copy) NSString *itemName; // 分類名稱

@end

// 下面是m文件實(shí)現(xiàn)
#import "ShopGoodsCategory.h"

@implementation ShopGoodsCategory

- (NSString *)jxmenu_title {
    return self.itemName;
}

@end

點(diǎn)擊事件回傳

點(diǎn)擊菜單項(xiàng)后关斜,可以用代理或者block的方式將數(shù)據(jù)返回給調(diào)用者,我一般使用block铺浇。

定義一個(gè)傳遞事件的block痢畜,把顯示view的時(shí)候傳進(jìn)來(lái)的數(shù)據(jù)中的指定項(xiàng)傳回去, 看情況再傳view本身以及索引等鳍侣。

typedef void(^JXMenuAction) (id data, NSInteger index);

添加簡(jiǎn)單的顯示動(dòng)畫

#pragma mark - private

- (void)showAnimation {
    self.alpha = 0;
    [UIView animateWithDuration:0.3 animations:^{
       
        self.alpha = 1;
    } completion:^(BOOL finished) {
        
    }];
}

關(guān)于擴(kuò)展

要定制菜單項(xiàng)的話丁稀,可以把cell for row方法通過(guò)代理開放出來(lái)。
如果要定制padding,字體倚聚,顏色等线衫,可以定義一個(gè)配置類出來(lái)。不要做成單例惑折。

JXMenu的代碼可以在github上找到:JXMenu
pod 并不能用授账,只是把代碼從項(xiàng)目中搬出來(lái)了,沒有做pod支持惨驶。需要Masonry 和UIView的positioning分類支持白热。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市粗卜,隨后出現(xiàn)的幾起案子屋确,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攻臀,死亡現(xiàn)場(chǎng)離奇詭異焕数,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)刨啸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門堡赔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人设联,你說(shuō)我怎么就攤上這事善已。” “怎么了仑荐?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵雕拼,是天一觀的道長(zhǎng)纵东。 經(jīng)常有香客問(wèn)我粘招,道長(zhǎng),這世上最難降的妖魔是什么偎球? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任洒扎,我火速辦了婚禮,結(jié)果婚禮上衰絮,老公的妹妹穿的比我還像新娘袍冷。我一直安慰自己,他們只是感情好猫牡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布胡诗。 她就那樣靜靜地躺著,像睡著了一般淌友。 火紅的嫁衣襯著肌膚如雪煌恢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天震庭,我揣著相機(jī)與錄音瑰抵,去河邊找鬼。 笑死器联,一個(gè)胖子當(dāng)著我的面吹牛二汛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拨拓,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肴颊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了渣磷?” 一聲冷哼從身側(cè)響起苫昌,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后祟身,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奥务,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年袜硫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氯葬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡婉陷,死狀恐怖帚称,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秽澳,我是刑警寧澤闯睹,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站担神,受9級(jí)特大地震影響楼吃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妄讯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一孩锡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亥贸,春花似錦躬窜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至朴摊,卻和暖如春默垄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仍劈。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工厕倍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贩疙。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓讹弯,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親这溅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子组民,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容