【iOS开发】我是这样封装view的

前言

一个有经验的开发,碰到一些特殊的UI控件,脑海中应该是有好几种实现方案的,同时也能记起一些第三方相似的开源控件。为了应对产品的需求变更,UI效果的变更,以及做到代码的可控性,所以在开发中,一般的UI效果我都喜欢自己动手去实现。而不是为了赶时间,或者什么的去用一些第三方的开源库。当然是除了一些非常通用的东西,像HUD, 下拉刷新这样,已经有非常好的实现,而且很容易做定制的。

示例

下面就以一个实际需求说一下自己封装UI的一点点经验:

先来看一下需求,直接上UI效果:


产品需求:

  1. 点击宝贝分类后弹出一个悬浮菜单
  2. 菜单的内容可能有多个,所以可能存在要上下滑动显示
  3. 点击菜单外面要隐藏菜单,不做其它的操作

放到整个项目中做通用控件考虑可定制项:

  1. 菜单是否要高亮上次选中过的菜单项
  2. 菜单项样式可能不同
  3. 菜单显示的位置
  4. 菜单上箭头显示的位置
  5. 菜单内边距
  6. 菜单边线颜色
  7. 菜单项的文字颜色,字体大小
  8. ...

通过上面的分析可以看到,要做一个极通用的控件,还是要考虑非常多的可定制点的。接触这个项目还不久,知道项目中是有一个类似的控件的,于是翻出来看了一下代码。可定制度很低。而且现在只有黑色的背景,颜色,菜单项高度的定制属性都没有,对项目不完全的熟悉,不能动通用控件,以防引起其它地方的bug。github上也看到过很多类似的控件。但是要完全按设计给到的UI效果来完成,还是要做很多的定制工作。所以还是决定自己写过。

实现

看UI效果,其实很简单的一个悬浮框显示到一个view上,以我写这种弹窗的经验,用一个透明背景的view做为整个控件的根view,加到要添加到的view上,里面的菜单做一个view,添加到透明view上。其它的就细节处理。

像上面这个view,层次是这样的,透明view 里面放 menu view ,menu view 里面放一个tableview 显示菜单项。箭头跟menu view同级,因为menu view 用了layer圆角,边框。箭头也可以考虑用layer画。更好定制。最后显示的时候将透明view加到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]) {
                    // 如果点击的是相同的分类,就不再请求
                    return;
                }
                
                // 传过来的就是点击到的分类,不用再用索引拿数据 
                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];
    
    // 显示动画
    [menu showAnimation];
    
    return menu;
}

关于这个显示方法,还有很多要改进的地方。先完成产品需求,设计上考虑一些大的改进点。到后面有相关需求或者时间够的时候可以进行改进。

/**
 显示一个菜单到指定的view上
 
 isTop这个属性其实是可以算出来的,没做这个处理。待改进。
 
 事件也可以通过这个显示方法传进来,参数太多了,待改进。

 @param view 要添加到view
 @param point 左侧的一个顶点,通过/isTop/来判断是左上角还是左下角
 @param isTop 是不是左上角
 @param width 菜单的整体宽度
 @param items 这个array 里面的单个数据可以是对象,要实现 /JXMenuCellDataProtocol/
 */
+ (JXMenu *)showInView:(UIView *)view point:(CGPoint)point isTop:(BOOL)isTop width:(CGFloat)width menuItems:(NSArray *)items;

说一下传入的菜单项及点击事件

传入的显示项是不确定的,可能是一个商品的分类,也可能是几个操作项。但是写好的view是确定的,就是说view要显示的数据是确定的。在这个例子中,要显示的内容就是一个title,但是数据是从接口拿回来的,拿回来后model化成了一个对应的ShopGoodsCategory 类型的model 数组。不确定数据来源,数据形式的时候,应该用接口来跟源数据进行对接,所以这里我定义了一个用于view显示的数据接口。让传进来的model去实现接口,就可以直接传model数组了。这样做的好处是,在点击了菜单项后,view可以直接返回点击的数据, 而不是一个唯一标识或者一个索引什么的。

接口定义

#import <Foundation/Foundation.h>

// 菜单的数据接口
@protocol JXMenuCellDataProtocol <NSObject>

@property (nonatomic, copy, readonly) NSString *jxmenu_title;    // 要显示的菜单项的标题

@end

传入的model实现接口

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

@interface ShopGoodsCategory : NSObject <JXMenuCellDataProtocol>

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

@property (nonatomic, copy) NSString *itemName; // 分类名称

@end

// 下面是m文件实现
#import "ShopGoodsCategory.h"

@implementation ShopGoodsCategory

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

@end

点击事件回传

点击菜单项后,可以用代理或者block的方式将数据返回给调用者,我一般使用block。

定义一个传递事件的block,把显示view的时候传进来的数据中的指定项传回去, 看情况再传view本身以及索引等。

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

添加简单的显示动画

#pragma mark - private

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

关于扩展

要定制菜单项的话,可以把cell for row方法通过代理开放出来。
如果要定制padding,字体,颜色等,可以定义一个配置类出来。不要做成单例。

JXMenu的代码可以在github上找到:JXMenu
pod 并不能用,只是把代码从项目中搬出来了,没有做pod支持。需要Masonry 和UIView的positioning分类支持。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容