iOS开发系列之常用自定义控件开发集—自定义UITableViewCell侧滑菜单控件开发

在很多app中就有UITableViewCell左滑出现菜单如系统删除按钮,但是系统的只能有一个,有很多需求需要个性化不仅可以放文字还可以放按钮修改背景色创建多个菜单项,那么系统提供的肯定不适合,所以我们需要自己手工打造。

直接上代码如下:

WHC_MenuCell.h 头文件如下:

//
//  WHC_MenuCell.m
//  WHC_MenuCell
//
//  Created by 吴海超 on 15/4/3.
//  Copyright (c) 2015年 Sinosun Technology Co., Ltd. All rights reserved.
//

#import <UIKit/UIKit.h>
@class WHC_MenuCell;
@protocol WHC_MenuCellDelegate <NSObject>

- (BOOL)WHC_MenuCell:(WHC_MenuCell*)whcCell didPullCell:(NSInteger)index;            //拉动tableView的回调

@end

@interface WHC_MenuCell : UITableViewCell
@property (nonatomic,assign)   CGFloat                 menuViewWidth;                //菜单总宽度
@property (nonatomic,retain)   NSArray               * menuItemTitles;               //每个菜单的标题
@property (nonatomic,retain)   NSArray               * menuItemTitleColors;          //每个菜单的文字颜色
@property (nonatomic,retain)   NSArray               * menuItemBackImages;           //每个菜单的背景图片
@property (nonatomic,retain)   NSArray               * menuItemNormalImages;         //每个菜单正常的图片
@property (nonatomic,retain)   NSArray               * menuItemSelectedImages;       //每个菜单选中的图片
@property (nonatomic,retain)   NSArray               * menuItemBackColors;           //每个菜单的背景颜色
@property (nonatomic,retain)   NSArray               * menuItemWidths;               //每个菜单的宽度
@property (nonatomic,strong)   UIView                * ContentView;                  //自定义内容view
@property (nonatomic,assign)   CGFloat                 fontSize;                     //字体大小
@property (nonatomic,assign)   NSInteger               index;                        //cell下标
@property (nonatomic,assign)   id<WHC_MenuCellDelegate>delegate;                     //cell代理

//单击菜单项
- (void)clickMenuItem:(UIButton*)sender;

//关闭菜单
- (BOOL)closeCellWithAnimation:(BOOL)b;

//关闭批量菜单
- (BOOL)closeCellWithTableView:(UITableView*)tableView index:(NSInteger)index animation:(BOOL)b;

//开始或者正在拉开菜单
- (void)startScrollviewCell:(BOOL)state x:(CGFloat)moveX;

//结束拉开菜单
- (void)didEndScrollViewCell:(BOOL)state;

@end

WHC_MenuCell.m源文件如下:

//
//  WHC_MenuCell.m
//  WHC_MenuCell
//
//  Created by 吴海超 on 15/4/3.
//  Copyright (c) 2015年 Sinosun Technology Co., Ltd. All rights reserved.
//

#import "WHC_MenuCell.h"
#define KWHC_MENUCELL_ANMATION_PADING (10.0)
@interface WHC_MenuCell ()<UIGestureRecognizerDelegate>{
    BOOL                                  _isOpen;              //是否打开菜单
    BOOL                                  _isScorllClose;       //是否滚动关闭菜单
    CGFloat                               _startX;              //存储拉开菜单开始触摸x坐标
    UIView                              * _menuView;            //菜单view
    UIPanGestureRecognizer              * _panGesture;          //手势
}

@end

@implementation WHC_MenuCell

//初始化UI
- (void)initUI{
    _panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)];
    _panGesture.delegate = self;
    [self.contentView addGestureRecognizer:_panGesture];

    UITapGestureRecognizer  * tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTapGestrue:)];
    tapGesture.delegate = self;
    [self.contentView addGestureRecognizer:tapGesture];

    if(_menuItemTitles == nil){
        _menuItemTitles = @[];
    }
    if(_menuItemBackImages == nil){
        _menuItemBackImages = @[];
    }
    if(_menuItemBackColors == nil){
        _menuItemBackColors = @[[UIColor redColor]];
    }
    if(_menuItemTitleColors == nil){
        _menuItemTitleColors = @[[UIColor blackColor]];
    }
    if(_menuItemWidths == nil){
        _menuItemWidths = @[];
    }
    if(_menuItemNormalImages == nil){
        _menuItemNormalImages = @[];
    }
    if(_menuItemSelectedImages == nil){
        _menuItemSelectedImages = @[];
    }

    CGFloat  _menuViewX = CGRectGetWidth(_ContentView.frame) - _menuViewWidth;
    _menuView = [[UIView alloc]initWithFrame:CGRectMake(_menuViewX + CGRectGetMinX(_ContentView.frame), 0.0, _menuViewWidth, CGRectGetHeight(_ContentView.frame))];
    _menuView.backgroundColor = [UIColor clearColor];
    [self.contentView insertSubview:_menuView belowSubview:_ContentView];

    NSInteger menuItemCount = _menuItemTitles.count;
    NSInteger menuBackImageCount = _menuItemBackImages.count;
    NSInteger menuBackColorCount = _menuItemBackColors.count;
    NSInteger menuTitleColorCount = _menuItemTitleColors.count;
    NSInteger menuItemWidthCount = _menuItemWidths.count;
    NSInteger menuItemNormalImageCount = _menuItemNormalImages.count;
    NSInteger menuItemSelectedImageCount = _menuItemSelectedImages.count;
    CGFloat btnWidth = _menuViewWidth / (CGFloat)menuItemCount;

    CGFloat (^currentWidth)(NSInteger i) = ^(NSInteger i){
        CGFloat  width = 0.0;
        for (NSInteger j = 0; j <= i ; j++) {
            width += [_menuItemWidths[j] floatValue];
        }
        return width;
    };

    //创建菜单按钮
    for (NSInteger i = 0; i < menuItemCount; i++) {
        UIButton  * btn = [UIButton buttonWithType:UIButtonTypeCustom];
        btn.tag = i;
        CGRect btnRc = CGRectMake(i * btnWidth, 0.0, btnWidth, CGRectGetHeight(_ContentView.frame));
        btn.frame = btnRc;
        if(menuItemWidthCount == menuItemCount){

            btnRc.origin.x = currentWidth(i - 1);
            btnRc.size.width = [_menuItemWidths[i] floatValue];
            btn.frame = btnRc;
        }
        [btn setTitle:_menuItemTitles[i] forState:UIControlStateNormal];
        NSInteger  titleColorIndex = i;
        if(titleColorIndex >= menuTitleColorCount){
            titleColorIndex = menuTitleColorCount - 1;
            if(titleColorIndex < 0){
                titleColorIndex = 0;
            }
        }
        if(titleColorIndex < menuTitleColorCount){
            [btn setTitleColor:_menuItemTitleColors[titleColorIndex] forState:UIControlStateNormal];
        }
        NSInteger  imageIndex = i;
        if(imageIndex >= menuBackImageCount){
            imageIndex = menuBackImageCount - 1;
            if(imageIndex < 0){
                imageIndex = 0;
            }
        }
        if(imageIndex > menuBackImageCount){
            [btn setBackgroundImage:[UIImage imageNamed:_menuItemBackImages[imageIndex]] forState:UIControlStateNormal];
        }

        NSInteger  colorIndex = i;
        if(colorIndex >= menuBackColorCount){
            colorIndex = menuBackColorCount - 1;
            if(colorIndex < 0){
                colorIndex = 0;
            }
        }
        if(colorIndex < menuBackColorCount){
            btn.backgroundColor = _menuItemBackColors[colorIndex];
        }

        if(i < menuItemNormalImageCount){
            NSString  * imageName = _menuItemNormalImages[i];
            if(imageName != nil && imageName.length){
                [btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
            }

            if(i < menuItemSelectedImageCount){
                NSString  * selectedImageName = _menuItemSelectedImages[i];
                if(selectedImageName != nil && selectedImageName.length){
                    [btn setImage:[UIImage imageNamed:selectedImageName] forState:UIControlStateHighlighted];
                }
            }
        }
        btn.titleLabel.minimumScaleFactor = 0.1;
        btn.titleLabel.adjustsFontSizeToFitWidth = YES;
        if(_fontSize == 0.0){
            _fontSize = 18.0;
        }
        btn.titleLabel.font = [UIFont boldSystemFontOfSize:_fontSize];
        [btn addTarget:self action:@selector(clickMenuItem:) forControlEvents:UIControlEventTouchUpInside];
        [_menuView addSubview:btn];
    }

}

//加载xib
- (void)awakeFromNib{
    [self initUI];
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self){
    }
    return self;
}

//设置滚动列表时菜单关闭状态
- (void)setIsScrollClose{
    _isScorllClose = NO;
}

//下面两个方法有子类实现属于触摸监听方法
- (void)startScrollviewCell:(BOOL)state x:(CGFloat)moveX{}
- (void)didEndScrollViewCell:(BOOL)state{}

//单击菜单项
- (void)clickMenuItem:(UIButton *)sender{
    [self closeCellWithAnimation:YES];
}

//批量关闭tableview上得多个cell菜单
- (BOOL)closeCellWithTableView:(UITableView*)tableView index:(NSInteger)index animation:(BOOL)b{

    NSArray  * indexPathArr = [tableView indexPathsForVisibleRows];
    BOOL  handleResult = NO;
    for (NSIndexPath * indexPath in indexPathArr) {
        if(_index != indexPath.row && index > -1){

            WHC_MenuCell * cell = (WHC_MenuCell *)[tableView cellForRowAtIndexPath:indexPath];
            [cell setIsScrollClose];
            if([cell closeCellWithAnimation:b]){
                handleResult = YES;
            }
        }else if(index <= -1){

            WHC_MenuCell * cell = (WHC_MenuCell *)[tableView cellForRowAtIndexPath:indexPath];
            if(_index != indexPath.row){
                [cell setIsScrollClose];
            }
            if([cell closeCellWithAnimation:b]){
                handleResult = YES;
            }
        }
    }
    return handleResult;
}

//关闭cell菜单
- (BOOL)closeCellWithAnimation:(BOOL)b{
    BOOL isClose = NO;
    if(_isOpen){
        isClose = YES;
        if(b){
            [UIView animateWithDuration:0.2 animations:^{
                _ContentView.transform = CGAffineTransformMakeTranslation(0.0, 0.0);
            }completion:^(BOOL finished) {
                _isOpen = NO;
                [self didEndScrollViewCell:_isOpen];
            }];
        }else{
            _ContentView.transform = CGAffineTransformMakeTranslation(0.0, 0.0);
            _isOpen = NO;
            [self didEndScrollViewCell:_isOpen];
        }
    }
    return isClose;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
    // Configure the view for the selected state
}

//手势处理
- (void)handlePanGesture:(UIPanGestureRecognizer*)panGesure{

    switch (panGesure.state) {
        case UIGestureRecognizerStateBegan:{

            _startX = _ContentView.transform.tx;
            _isScorllClose = [_delegate WHC_MenuCell:self didPullCell:_index];
        }
            break;
        case UIGestureRecognizerStateChanged:{
            if(_isScorllClose && _isOpen == NO){
                return;
            }
            CGFloat    currentX = _ContentView.transform.tx;
            CGFloat    moveDistanceX = [panGesure translationInView:panGesure.view].x;
            CGFloat    velocityX = [panGesure velocityInView:panGesure.view].x;
            CGFloat    moveX = _startX + moveDistanceX;

            if(velocityX > 0){//right
                if(currentX >= KWHC_MENUCELL_ANMATION_PADING){
                    [panGesure setTranslation:CGPointMake(KWHC_MENUCELL_ANMATION_PADING, 0.0) inView:panGesure.view];
                    break;
                }
            }else{
                if(currentX < -_menuViewWidth){
                    moveX = currentX - 0.4;
                    [panGesure setTranslation:CGPointMake(moveX, 0.0) inView:panGesure.view];
                }
            }
            _ContentView.transform = CGAffineTransformMakeTranslation(moveX, 0.0);
            [self startScrollviewCell:_isOpen x:moveDistanceX];
        }
            break;
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded:{
            _isScorllClose = NO;
            if(_ContentView.transform.tx > 0.0){

                [UIView animateWithDuration:0.2 animations:^{
                    _ContentView.transform = CGAffineTransformMakeTranslation(-KWHC_MENUCELL_ANMATION_PADING, 0.0);
                }completion:^(BOOL finished) {
                    _isOpen = NO;
                    [self didEndScrollViewCell:_isOpen];
                    [UIView animateWithDuration:0.2 animations:^{
                        _ContentView.transform = CGAffineTransformMakeTranslation(0.0, 0.0);
                    }];
                }];

            }else if (_ContentView.transform.tx < 0){

                CGFloat  tx  = fabsf(_ContentView.transform.tx);
                if(tx < _menuViewWidth / 2.0 || (tx < _menuViewWidth && _isOpen)){
                    [UIView animateWithDuration:0.2 animations:^{
                        _ContentView.transform = CGAffineTransformMakeTranslation(0.0, 0.0);
                    }completion:^(BOOL finished) {
                        _isOpen = NO;
                        [self didEndScrollViewCell:_isOpen];
                    }];
                }else{
                    [UIView animateWithDuration:0.2 animations:^{
                        _ContentView.transform = CGAffineTransformMakeTranslation(-_menuViewWidth, 0.0);
                    }completion:^(BOOL finished) {
                        _isOpen = YES;
                        [self didEndScrollViewCell:_isOpen];
                    }];
                }
            }
        }
            break;
        default:
            break;
    }
}

- (void)handleTapGestrue:(UITapGestureRecognizer*)tapGesture{

}

#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{

    if([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){

        return [_delegate WHC_MenuCell:self didPullCell:-1];

    }else if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class] ]){

        UIPanGestureRecognizer  * panGesture = (UIPanGestureRecognizer*)gestureRecognizer;
        CGPoint                   velocityPoint = [panGesture velocityInView:panGesture.view];
        if(fabsf(velocityPoint.x) > fabsf(velocityPoint.y)){
            return YES;
        }else{
            _isScorllClose = [_delegate WHC_MenuCell:self didPullCell:-1];
            return _isScorllClose;
        }
    }
    return NO;
}
@end

时间: 2024-08-02 18:39:34

iOS开发系列之常用自定义控件开发集—自定义UITableViewCell侧滑菜单控件开发的相关文章

iOS开发系列之常用自定义控件开发集—自定义状态栏消息提示控件开发

在实际开发中消息提示时很常见的需求,为了个性化和拥有简洁的UI状态栏提示是比较好的方案,好处很多如:不遮挡主UI,新意,下面贴出实现代码. WHC_StatusBarMessage.h头文件如下: // // WHCStatusBarMessage.m // WHCStatusBarMessage // // Created by apple on 14-3-28. // Copyright (c) 2014年 apple. All rights reserved. // #import "WH

iOS开发系列之常用自定义控件开发集—自定义多选按钮控件开发

在实际开发中很多时候我们需要用到下拉列表,我们下面来实现一下. WHC_ComboBox.h头文件如下: // // WHC_ComboBox.h // WHC_ComboBox // // Created by 吴海超 on 15/4/2. // // #import <UIKit/UIKit.h> @interface WHC_ComboBox : UIButton @end WHC_ComboBox.m源文件如下: // // WHC_ComboBox.m // WHC_ComboBox

iOS开发系列之常用自定义控件开发集—自定义单选按钮或者多选按钮控件开发

在我们实际开发中我们做登陆或者注册功能时往往需要勾选某个协议这个时候就需要用到CheckBox按钮,CheckBox是pc或者android上得控件ios没有,所以需要我们自定义. WHC_RadioButton.h头文件如下: // // WHC_RadioButton.h // CTBMobileBank // // Created by 吴海超 on 15/4/1. // // #import <UIKit/UIKit.h> #define KWHC_IMAGE_SIZE (15.0)

C#自定义工业控件开发

转自阿凡卢原文C#自定义工业控件开发 由于工作需要,调研过一段时间的工业控制方面的"组态软件"(SCADA)的开发,组态软件常用于自动化工业控制领域,其中包括实时数据采集.数据储存.设备控制和数据展现等功能.其中工控组件的界面展现的实现类似于Windows系统下的各种开发控件,通过各种控件的组装,和硬件协议的集成,就可以实现对相应设备的控制和实时状态的显示. 每个对应的硬件UI展示都可以用一个自定义控件来实现,如下图的一个温度计,就可以使用UserControl来实现. using S

利用ArcGIS Engine、VS .NET和Windows控件开发GIS应用

原文:利用ArcGIS Engine.VS .NET和Windows控件开发GIS应用 此过程说明适合那些使用.NET建立和部署应用的开发者,它描述了使用ArcGIS控件建立和部署应用的方法和步骤. 你可以在下面的目录下找到相应的样例程序: <安装目录>\DeveloperKit\Samples\Developer_Guide_Scenarios\ ArcGIS_Engine\Building_an_ArcGIS_Control_Application\Map_Viewer 注:ArcGIS样

【转载】基于MFC的ActiveX控件开发(3)

原文:http://iysm.net/?p=122 3.事件 ActiveX 控件使用事件通知容器控件上发生了某些事情.事件的常见示例包括单击控件.使用键盘输入数据和控件状态更改.当发生这些操作时,控件将引发事件以提醒容器. MFC 支持两种事件:常用和自定义.常用事件是 COleControl 类自动处理的事件.自定义事件使控件得以在该控件特定的操作发生时通知容器.控件内部状态发生更改或收到某个窗口消息即属于此类事件. 常用事件 常用事件由 COleControl 类自动引发.COleCont

asp.net控件开发基础(1)(转)原文更多内容

asp.net本身提供了很多控件,提供给我们这些比较懒惰的人使用,我认为控件的作用就在此,因为我们不想重复工作,所以要创建它,这个本身便是一个需求的关系,所以学习控件开发很有意思. wrox网站上有本书 Professional ASP.NET 2.0 Server Control and Component Development 现在还没有出版,但网站上放出了代码,所以正好下载过来学习一下. 我看过前几章代码,环环相扣,作者用不同的知识向我们展示同一个效果,所以循序渐进的学下来很有好处. 虽

基于MFC的ActiveX控件开发 (转)

ActiveX 控件是基于组件对象模型 (COM) 的可重用软件组件,广泛应用于桌面及Web应用中.在VC下ActiveX控件的开发可以分为三种,一种是直接用COM的API来开发,这样做显然非常的麻烦,对程序员要求也非常高,因此一般是不予考虑的:一种是基于传统的MFC,采用面向对象的方式将COM的基本功能封装在若干MFC的C++类中,开发者通过继承这些类得到COM支持功能.MFC为广大VC程序员所熟悉,易于上手学习,但缺点是MFC封装的东西比较多,因此用MFC开发出来的控件相对会比较大,因此比较

带农历日历的DatePicker控件!Xamarin控件开发小记

原文:带农历日历的DatePicker控件!Xamarin控件开发小记 闲来无事开发了个日期选择控件,感兴趣的同学前往: https://github.com/MatoApps/Mato.DatePicker Mato.DatePicker 说明 这是一个带有农历日历的日期选择Xamarin控件 可以指定初始日期 多选和单选日期 引用 PCL:https://www.nuget.org/packages/Mato.DatePicker.PCL/ Android:https://www.nuget