仿购物车的实现

基本实现了全选,删除等按钮点击功能

一.  首先,设置好基本的购物车界面,实现tableView的相关的 数据源 和 代理 方法
在QHLShoppingCarController.m中写一个类扩展,定义下列属性:

/** 模型数组 */
@property (nonatomic, strong) NSMutableArray *shoppingCar;
/** 底部结算view */
@property (nonatomic, weak) QHLSettleMentView *settleMentView;
/** 底部隐藏的按钮view */
@property (nonatomic, weak) QHLHiddenView *hiddenView;
/** 购物车界面状态  */
@property (nonatomic, assign) QHLViewState state;
/** 用来保存按钮选中时候的按钮字典数组 */
@property (nonatomic, strong) NSMutableArray *btnsArray;
/**  存储编辑状态下选中时对应的沙盒中的按钮字典数组 */
@property (nonatomic, strong) NSMutableArray *documentArray;
/** 存储在沙盒中的数据数组 */
@property (nonatomic, strong) NSMutableArray *tempArray;
/** 选中商品数量 */
@property (nonatomic, assign) NSInteger count;
/** 选中商品金额 */
@property (nonatomic, assign) NSInteger money;

在懒加载中,tempArray是用来保存存储在应用沙盒中的字典数组

- (NSMutableArray *)tempArray {
    if (!_tempArray) {

        _tempArray = [NSKeyedUnarchiver unarchiveObjectWithFile:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"goods.archive"]];

    }
    return _tempArray;
}

抽取的方法 : 根据不同的self.state状态来设置不同的底部view的全选按钮的选中状态

#pragma mark - 根据不同的选中状态来设置底部view的全选按钮的选中状态
- (void)setButtonSelectState:(BOOL)selected {
    if (self.state == QHLViewStateNormal) { //根据状态来设置不同的全选按钮的选中
        self.settleMentView.btnSelected = selected;
    } else {
        self.hiddenView.allSelBtnSelected = selected;
    }
}

抽取的方法 : 根据不同的选中状态来对传入的数组做不同的操作

#pragma mark - 根据不同的选中状态来对数组进行操作
- (void)handleObjectInArrays:(id)btnsObject documentsObject:(id)documentsObject selectedState:(BOOL)selected{

    if (selected) { //选中时
        [self.documentArray addObject:documentsObject];
        [self.btnsArray addObject:btnsObject];
    } else { //取消选中时
        [self.documentArray removeObject:documentsObject];
        [self.btnsArray removeObject:btnsObject];
    }
}

二.  在自定义的cell中,cell中的选中button的点击事件通过代理放在控制器中去处理:

在QHLShoppingCarController.m中实现cell的代理方法

- (void)cell:(QHLTableViewCell *)cell selBtnDidClickToChangeAllSelBtn:(BOOL)selBtnSelectState andIndexPath:(NSIndexPath *)indexPath{
    BOOL selected = !selBtnSelectState;

    //获取模型
    QHLShop *shop = self.shoppingCar[indexPath.section];
    QHLGoods *good = shop.goods[indexPath.row];

    //设置按钮所在的cell的按钮的选中状态
    good.selected = selected;

    if (self.state == QHLViewStateNormal) { //判断当前view的state

        if (selected) {
            self.count ++;

            //添加金额
            self.money += [good.price integerValue];

        }else {
            self.count --;

            //减去金额
            self.money -= [good.price integerValue];
        }

        self.settleMentView.count = self.count;
        self.settleMentView.money = self.money;

    } else { //edit 状态

        //获取沙盒数组中的模型
        QHLShop *shops = self.tempArray[indexPath.section];
        QHLGoods *goods = shops.goods[indexPath.row];

        [self handleObjectInArrays:good documentsObject:goods selectedState:selected];

    }

    //设置按钮cell所在的表头视图的按钮状态
    for (QHLGoods *goods in shop.goods) {

        if (!goods.selected) {

            shop.selected = NO;
            [self.tableView reloadData];

            if (self.state == QHLViewStateNormal) {

                self.settleMentView.btnSelected = NO; //全选按钮设置为未选中状态

            } else {

                //获取沙盒数组中的模型
                QHLShop *shops = self.tempArray[indexPath.section];

                [self.btnsArray removeObject:shop];
                [self.documentArray removeObject:shops];

                self.hiddenView.allSelBtnSelected = NO;  //全选按钮设置为未选中状态
            }
            return;
        }
    }
    //能执行到此处,就说明该组cell的按钮 都是选中状态
    shop.selected = YES;
    if (self.state == QHLViewStateEdited) {
        //获取沙盒数组中的模型
        QHLShop *shops = self.tempArray[indexPath.section];

        [self.btnsArray addObject:shop];
        [self.documentArray addObject:shops];
    }

    [self.tableView reloadData];

    //根据表透视图的按钮状态设置全选按钮的状态
    for (QHLShop *shop in self.shoppingCar) {
        if (!shop.selected) {

            [self setButtonSelectState:NO];

            return;
        }
    }
    [self setButtonSelectState:YES];
}

在该自定义cell的button点击的代理方法中:
1. 当点击cell中的btn的时候,先判断当前购物车的state是 QHLViewStateNormal 还是 QHLViewStateEdited!!

当state是 QHLViewStateNormal 的时候:
    对self.count 和self.money 作 增加 或者 减少 的操作.

当state是 QHLViewStateEdited 的时候:
    调用方法 : [self handleObjectInArrays:good documentsObject:goods selectedState:selected]
    1> 当selected == YES时,把当前点击的cell相对应的self.shoppingCar中的模型对象(good) 保存到self.btnsArray中 或者 从self.btnsArray中移除
    2> 当selected == NO时,把当前点击的cell相对应的self.tempArray中的模型对象(goods)  保存到self.documentArray中 或者 从self.documentArray中移除

2. 之后遍历该cell所在的组的模型数据数组:
如果cell所在组的模型数组中的数据有 good.selected是 NO 的,就设置该组组头视图中的 btn 状态为未选中并直接 return; 退出该方法;如果所有good.selected 都是YES,那么设置该组组头视图中的 btn 的状态为选中,并刷新数据.

2.1> 在该组cell所在的模型数据数组中有 good.selected 是NO 的情况时:
当state是 QHLViewStateNormal 的时候:
    设置self.settleMentView.btnSelected = NO,  设置后会在相对应的setter方法中来设置对应的全选按钮状态为未选中.

当state是 QHLViewStateEdited 的时候,在return之前执行下面操作:
    1. 设置self.hiddenView.allSelBtnSelected = NO,  设置后悔在相对应的setter方法中来设置相应的全选按钮的状态为未选中.
    2. 把当前点击的cell在self.shoppingCar中所对应的组头的模型对象(shop) 从self.btnsArray中移除
    3. 把当前点击的cell在self.tempArray中所对应的组头的模型对象(shops) 从self.documentArray中移除

2.2> 在该组cell所在的模型数据中所有 good.selected 都是 YES 的情况时:
        1. 设置该组cell所在组相对应的组头模型中的selected为YES,并刷新tableView.
        2. 当state是 QHLViewStateEdited 的时候:
            把该组头视图在 self.shoppingCar中所对应的模型对象(shop)  保存到 self.btnsArray中.
            把该组头视图在 self.tempArray中所对应的模型对象(shops)  保存到 self.documentArray中.

2.3> 之后在遍历整个self.shoppingCar中的每个QHLShop对象,当存在有shop对象的selected 是NO的情况时,根据不同的state状态 设置不同的view的选中属性为NO,并且直接 return 退出方法;当所有shop对象的selected 都是YES时,根据不同是state状态 设置不同的view的选中属性为YES.

三.  在自定义的组头视图中,视图中的选中button的点击事件通过代理放在控制器中去处理:
在QHLShoppingCarController.m中实现headerView的代理方法

#pragma mark - headerView的代理方法
- (void)headerView:(QHLHeaderView *)headerView selBtnDidClickToChangeAllSelBtn:(BOOL)selBtnSelectState andSection:(NSInteger)section {

    BOOL selected = !selBtnSelectState;

    //获取对应的模型
    QHLShop *shop = self.shoppingCar[section];

    if (self.state == QHLViewStateNormal) {

        if (selected) {
            for (QHLGoods *good in shop.goods) {
                //判断表头所在的cell组中  cell中的按钮 是否选中,当不选中的情况下 执行下面代码
                if (!good.selected) {
                    self.count ++;
                    //添加金额
                    self.money += [good.price integerValue];
                }
            }
        } else { //这边不用做判断,表头视图中的cell中的按钮 都是选中状态
            for (QHLGoods *good in shop.goods) {
                self.count --;
                //添加金额
                self.money -= [good.price integerValue];
            }
        }

        self.settleMentView.count = self.count;
        self.settleMentView.money = self.money;

    } else {  //edit 状态
        QHLShop *shops = self.tempArray[section];

        if (selected) { //组头视图中的button选中时
            [self.documentArray addObject:shops];
            [self.btnsArray addObject:shop];
        } else { // 组头视图中的button取消选中时
            [self.documentArray removeObject:shops];
            [self.btnsArray removeObject:shop];
        }

        NSInteger count = shop.goods.count;
        for (int i = 0; i < count; i++) {

            if (selected) {
                [self.documentArray addObject:shops.goods[i]];
                [self.btnsArray addObject:shop.goods[i]];
            } else {
                [self.documentArray removeObject:shops.goods[i]];
                [self.btnsArray removeObject:shop.goods[i]];
            }
        }
    }

    //设置表头view的按钮状态
    shop.selected = selected;

    //设置表头所在组cell的按钮状态
    for (QHLGoods *good in shop.goods) {
        good.selected = selected;
    }
    [self.tableView reloadData];

    //设置全选按钮的选中状态
    for (QHLShop *shop in self.shoppingCar) {
        if (!shop.selected) {

            if (self.state == QHLViewStateNormal) { //根据状态来设置不同的全选按钮的选中
                self.settleMentView.btnSelected = NO;
            } else {
                self.hiddenView.allSelBtnSelected = NO;
            }

            return;
        }
    }
    if (self.state == QHLViewStateNormal) { //根据状态来设置不同的全选按钮的选中
        self.settleMentView.btnSelected = YES;
    } else {
        self.hiddenView.allSelBtnSelected = YES;
    }
}

在该自定义headerView的删除button点击的代理方法中:

1. 当点击cell中的btn的时候,先判断当前购物车的state是 QHLViewStateNormal 还是 QHLViewStateEdited!!

当 当前的state 是QHLViewStateNormal的时候:
    1> 如果headerView中的button状态为选中时候,遍历当前headerView所在组相对应的shop.goods模型数组:
        1> 遍历时,当模型数组中的good.selected == NO 时, 对 self.count 和 self.money 自加;如果good.selected == YES 时,不做处理

2> 如果headerView中的button状态为未选中时候,遍历当前headerView所在组相对应的shop.goods模型数组:
        1> 遍历时,对self.count 和 self.money 做自减操作

当 当前的state 是QHLViewStateEdited的时候:
    1> 调用方法 : [self handleObjectInArrays:shop documentsObject:shops selectedState:selected] 根据 headerView中的button选中状态selected来添加或者移除self.btnsArray 和 self.documentArray 中 对应的QHLShop 模型对象

2> 根据当前headerView所在的组的cell个数 做循环, 在循环中调用方法 : [self handleObjectInArrays:shop.goods[i] documentsObject:shops.goods[i] selectedState:selected]  根据 headerView中的button选中状态selected来添加或者移除self.btnsArray 和 self.documentArray 中 对应的QHLGoods 模型对象

2. 对 shop.goods 模型数组做循环遍历:
    根据当前shop.selected 的 bool 值 来设置 good.selected 的值(即 good.selected == shop.selected)

3. 对 self.shoppingCar 模型数组做循环遍历:
    1> 当该数组中 至少有一个shop.selected == NO的时候,直接return 退出该方法;
       在return之前 调用方法 : [self setButtonSelectState:NO] 根据不同的state状态来设置不同的view中的全选按钮的隐藏

2> 当所有的shop.selected == YES 的时候,遍历结束之后,调用方法 : [self setButtonSelectState:YES] 根据不同的state状态来设置不同的view中的全选按钮的隐藏

四.  在该自定义headerView的全选按钮的点击事件的代理方法中:
遍历self.shoppingCar模型数组,根据全选按钮的不同的选中状态,调用 handleObjectInArrays: documentsObject: selectedState: 方法来对self.documentArray 和 self.btnsArray 数组 做不同的操作

五.  在右上角编辑按钮的点击事件中:
- (void)editBtnDidClick:(QHLButton *)editBtn方法中

设置底部2个view的隐藏显示切换
改变编辑按钮的选中状态

1> 当编辑按钮选中时:
    1. 改变self.state  变为 编辑状态
    2. 保存self.shoppingCar模型数组,归档写入到应用沙盒中
    3. 遍历self.shoppingCar 模型数组,是其中所有的模型的selected属性为 NO,最后刷新tableView

2> 当编辑按钮取消选中时:
    1. 改变self.state 变为 正常状态
    2. 设置隐藏view的全选按钮的选中属性为NO
    3. 把self.tempArray(存储在沙盒中的模型数据数组) 赋值给 self.shoppingCar,然后刷新tableView
    4. 把self.btnsArray self.documentArray self.tempArray 置为 nil
    5. 判断self.shoppingCar中元素的个数,如果个数为0 设置结算view中的全选按钮的选中状态为NO,并return 退出方法;如果self.shoppingCar.count不为0的话执行下面操作
    6. 先把 self.count 和 self.money 的值 等于0!!!然后遍历self.shoppingCar模型数组,根据QHLGoods模型对象good的selected 是否等于 YES 来使self.count 和 self.money 执行自加操作
    7. 遍历self.shoppingCar中的shop.goods模型数组:
        1> 当数组中有QHLGoods模型对象的selected的值是NO的话,break跳出本次循环.在break之前设置该对象所在的shop.selected为NO,和结算view的全选按钮的状态为NO
        2> 当shop.goods中的good.selected都是YES的时候,shop.selected 设置为YES.
    8.遍历self.shoppingCar模型数组:
        1> 当shop.selected 的值 有为NO时,设置结算view中的全选按钮的状态为未选中,并且return退出方法.
        2> 当所有shop.selected的值 都是YES时,设置结算view中的全选按钮的状态为选中.

六.  抽取的用来遍历数组删除数据的方法

/**
 *  @param dataArray  dataArray 保存要删除的对象的数组
 *  @param modelArray modelArray 模型数组 要从该数组中删除数据
 */
#pragma mark - 遍历删除模型数组dataArray中的元素在模型数组modelArray中对应的object
- (void)enumerateObjectsUsForinWithDataArray:(NSMutableArray *)dataArray modelArray:(NSMutableArray *)modelArray {

    //遍历删除 对应的good
    for (id obj in dataArray) {

        for (QHLShop *shops in modelArray) {

            for (QHLGoods *goods in shops.goods) {

                if ([goods isEqual:obj]) {

                    [shops.goods removeObject:goods];
                    break;

                }
            }
        }
    }

    //遍历删除 对应的shops
    for (id obj in dataArray) {

        for (QHLShop *shops in modelArray) {

            if ([shops isEqual:obj]) {

                [modelArray removeObject:shops];
                break;
            }
        }
    }
}

七.  编辑状态下,在删除按钮的点击事件中:

#pragma mark - hiddenView delegate
- (void)hiddenView:(QHLHiddenView *)hiddenView didClicHiddenViewBtn:(QHLHiddenViewButtonState)buttonType {
    if (buttonType == QHLHiddenViewButtonStateShared) {

    } else if (buttonType == QHLHiddenViewButtonStateAttention) {

    } else if (buttonType == QHLHiddenViewButtonStateDelete) {

        //修改self.shoppingCar
        [self enumerateObjectsUsForinWithDataArray:self.btnsArray modelArray:self.shoppingCar];

        [self.tableView reloadData];

        //修改保存沙盒数据的数值中对应的数据
        [self enumerateObjectsUsForinWithDataArray:self.documentArray modelArray:self.tempArray];

        if (!self.shoppingCar.count) {
            self.hiddenView.allSelBtnSelected = NO;
        }
    }
}

在按钮的删除方法中,先遍历删除QHLGoods对象模型,在遍历QHLShop对象模型,根据self.btnsArray 和 self.documentArray 中保存的元素 在 self.shoppingCar 和 self.tempArray 中 删除相对应的模型对象.遍历结束后,判断self.shoppingCar中是否还有元素,没有元素了的话设置全选按钮为未选中状态

八.  在添加cell侧滑删除功能的方法中:

#pragma mark - 设置cell侧滑按钮
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {

    QHLShop *shop = self.shoppingCar[indexPath.section];

    //删除
    UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        //删除数据
        [shop.goods removeObjectAtIndex:indexPath.row];

        if (!shop.goods.count) {   //判断 shoppingCar数组中的shop对象的goods数组 是否为空  为空的话移除shop  不为空的话 移除good
            [self.shoppingCar removeObjectAtIndex:indexPath.section];
        }
        [tableView reloadData];

        if (self.state == QHLViewStateEdited) { //在编辑界面下删除cell时  同时删除沙盒中读取到的数组中对应的元素
            //根据indexPath获取到QHLShop对象
            QHLShop *shops = self.tempArray[indexPath.section];

            //移除该对象goods数组中的下标为indexPath.row的元素
            [shops.goods removeObject:shops.goods[indexPath.row]];

            if (!shops.goods.count) { //判断沙盒存储的数组中的shop对象的goods数组 是否为空  为空的话移除
                [self.tempArray removeObject:shops];
            }
        }

        for (QHLGoods *good in shop.goods) {
            if (!good.selected) {
                shop.selected = NO;
                [self setButtonSelectState:NO];
                [tableView reloadData];
                return;
            }
        }
        shop.selected = YES;
        if (self.state == QHLViewStateEdited) {
            //根据indexPath获取到QHLShop对象
            QHLShop *shops = self.tempArray[indexPath.section];
            [self handleObjectInArrays:shop documentsObject:shops selectedState:YES];
        }
        [tableView reloadData];

        for (QHLShop *shop in self.shoppingCar) {
            if (!shop.selected) {
                [self setButtonSelectState:NO];
                return;
            }
        }
        [self setButtonSelectState:YES];

    }];

    return @[deleteAction];
}

在删除按钮的回调方法中:
    1> 当删除按钮被点击时,会先把对应的QHLGoods模型对象从shop.goods中删除掉,然后判断shop.goods中是否还有别的元素,没有的话删从self.shoppingCar中删除掉shop模型对象,然后刷新tableView.
    2> 然后判断当前self.state是否是编辑状态,是的话,根据indexPath在模型数组self.tempArray(存储在沙盒中的模型数组)中删除相对应的goods模型对象,然后判断该模型对象所在的shops.goods是否还有别的元素,没有了的话把shops模型对象从self.tempArray中移除掉.
    3> 遍历删除的cell所在的组模型数组shop.goods模型数组,当有good.selected == NO时,设置shop.selected = NO 并且根据不同的state状态 设置不同的底部view的全选按钮的选中状态,最后return结束回调方法
    4> 当遍历结束时,说明shop.goods中所有的good.selected 都是YES,所以设置shop.selected = YES,如果当前的state是在编辑状态下的时候,把对应的shop模型对象和shops模型对象保存到对应的数组中,并且刷新tableView.
    5> 遍历self.shoppingCar模型数组,如果有shop.selected = NO的话,调用[self setButtonSelectState:NO]方法 根据不同的strate来设置不同的全选按钮为未选中状态,并且退出回调方法;如果所有的shop.selected 都是YES的话,调用[self setButtonSelectState:NO]方法 根据不同的strate来设置不同的全选按钮为选中状态.

通过这些主要的方法的实现以及tableView的 数据源 和 代理 方法的实现,差不多就可以实现购物车的基本功能了.

demo已经上传到cocoachina那边了 连接:http://code.cocoachina.com/view/129721

时间: 2024-12-27 09:48:00

仿购物车的实现的相关文章

js实现仿购物车加减效果

代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> *{ margin: 0; padding: 0; } body{ overflow-y: auto; } ul{ margin-top: 20px; border-top: 1px solid #666; } h1{ width: 500

jQuery拖拽插件制作拖拽排序特效

基于jQuery拖拽插件制作拖拽排序特效是一款非常实用的鼠标拖拽布局插件.效果图如下: 在线预览   源码下载 实现的代码. html代码: <h1>水平拖拽</h1> <div class="demo"> <div class="item item1"><span>1</span></div> <div class="item item2"><

仿饿了么加入购物车旋转控件 - 自带闪转腾挪动画 的按钮

转载请标明出处: http://blog.csdn.net/zxt0601/article/details/54235736 本文出自:[张旭童的博客](http://blog.csdn.net/zxt0601) 代码传送门:喜欢的话,随手点个star.多谢 https://github.com/mcxtzhang/AnimShopButton 概述 在上文,酷炫Path动画已经预告了,今天给大家带来的是利用 纯自定义View,实现的仿饿了么加入购物车控件,自带闪转腾挪动画的按钮. 效果图如下:

iOS开发——仿淘宝添加到购物车的动画效果实现

这篇博文实在不知道该起什么名字才能概况我的意思...挫语文水平 类似于淘宝一样,我们在写一些购物.订餐之类的app的时候,在用户选择购买或者加入购物车时可以添加一个商品飞到购物车中的动画效果,如下图所示: 实现这个效果还是不算难的,但涉及的问题比较多,还是挺有学习价值的.主要面对的问题有以下几点 1.cell中有button,如何获得该button,即如何知道用户点击的是哪一个button. 2.坐标系的转换,这里频繁使用坐标系转换,主要原因是这里需要涉及三个视图--cell.tableView

仿饿了么购物车下单效果

仿饿了么购物车下单效果 前一段由于新项目需要,开发一个类似饿了么购物车下单效果,电商类.外卖类.点餐类项目都可以用的上,废话不多说请看效果. 效果图如下: 主要的功能: 就是左侧展示分类,右侧展示分类下商品的,点击右侧分类下的商品,如果商品是套餐类型的话,点击可以看套餐详情,下单选择完商品后,可以在购物车里面添加或减少商品数量. 主要功能实现: 1:分类及商品及购物车里面商品数量的联动效果 2:底部购物车商品列表 3:选择左侧分类效果 4:添加商品是有0到1,减少商品有1到0动画效果 5:下单动

iOS高仿淘宝购物车,功能模块应有尽有

刚做完一个淘宝的购物车,按着淘宝做的,换了个产品经理,人家喜欢JD的购物车,一句话,咱换个风格,好心 酸有没有,天天刷存在感,只有我们苦逼了,那么既然需求来了,就要按着大爷的要求改了,为了纪念下,咱写个 Demo给大家分享下.    我擦,我一看代码,我还是用AutoLayout做的,主界面代码都能快接近800了,全加起来想想有点多啊,这简直是用 生命在写Demo啊,该有的效果全有了,各位请看图       再来一组 简单分析下功能 1.给UIKit控件增加Badge的扩展(这个扩展需要的去代码

仿聚美右下角购物车特效

如题 如图: 代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv=&qu

Android仿外卖购物车的实现

又两周没写博客了,不是不想写而是不知道该写点什么,总不能为了写博客而写博客,前两天项目里要加个购物车功能,看了下别人APP的效果觉得不错,虽然我项目里没用上不过毕竟还算是个常用的功能,于是决定写个博客分享下! 效果图 知识点分析 效果图来看不复杂内容并没多少,值得介绍一下的知识点也就下面几个吧 - 列表标题悬停 - 左右列表滑动时联动 - 添加商品时的抛物线动画 - 底部弹出购物车清单 - 数据的同步 另外就是实现效果的时候可能会遇到的几个坑... 布局很简单直接进入代码 列表标题悬停 现在做项

Android仿外卖购物车

效果图 知识点分析 效果图来看不复杂内容并没多少,值得介绍一下的知识点也就下面几个吧 - 列表标题悬停 - 左右列表滑动时联动 - 添加商品时的抛物线动画 - 底部弹出购物车清单 - 数据的同步 另外就是实现效果的时候可能会遇到的几个坑... 布局很简单直接进入代码 列表标题悬停 现在做项目列表什么的基本抛弃了ListView改用RecyclerView,上篇博客中的标题悬停也是使用了一个RecyclerView的开源项目sticky-headers-recyclerview,不过写这个demo