当前位置: 首页 > news >正文

OC-动画实现折叠cell

文章目录

  • 折叠cell
    • 前言
    • 准备Model
    • 自定义header
    • 实现VC
      • 折叠关系的判断
      • 注册header
      • 完整VC代码
    • 效果

折叠cell

前言

在阅读学长博客的时候,发现了一个很有意思的且看着很高级的折叠cell的demo,对比我的简陋版,属实天差地别,所以特地学习了一遍

准备Model

我们首先先为每个UItableView准备一个Model,用来存储单元格的内容和展开状态,由于我们只是简单实现效果,因此没有特意准备单元格的内容。这里知识简单存储标题和展开内容以及标志位

#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Model : NSObject
@property (nonatomic, copy)NSString* name;
@property (nonatomic, strong)NSArray<NSString* >* items;
@property (nonatomic, assign)BOOL collapsed;
- (instancetype)initWithName:(NSString* )name withItems:(NSArray<NSString* >* )items andCollapsed:(BOOL)collapased;
@endNS_ASSUME_NONNULL_END

我们对外声明一个接口用来初始化Model对象

//  Created by xiaoli pop on 2025/9/16.
//#import "Model.h"@implementation Model
- (instancetype)initWithName:(NSString* )name withItems:(NSArray<NSString* >* )items andCollapsed:(BOOL)collapased {if (self = [super init]) {self.name = name;self.items = items;self.collapsed = collapased;}return self;
}
@end

在这个方法中完成对Model属性的初始化

自定义header

由于我们的每个单元section的header需要包含标题和按钮的相关属性,所以需要自定义一个UITableViewHeaderFooterView的子类,去实现自定义的header

//  Created by xiaoli pop on 2025/9/16.
//#import <UIKit/UIKit.h>NS_ASSUME_NONNULL_BEGIN@interface Header : UITableViewHeaderFooterView
@property (nonatomic, strong)UILabel* titleLabel;
@property (nonatomic, strong)UIButton* button;
@endNS_ASSUME_NONNULL_END

在实现文件中,需要我们对相关控件进行初始化

//  Created by xiaoli pop on 2025/9/16.
//#import "Header.h"
#import "Masonry.h"
@implementation Header- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {if (self = [super initWithReuseIdentifier:reuseIdentifier]) {[self setupViews];}return self;
}- (void)setupViews {self.contentView.backgroundColor = [UIColor blueColor];self.titleLabel = [[UILabel alloc] init];self.titleLabel.font = [UIFont boldSystemFontOfSize:16];self.titleLabel.textColor = [UIColor whiteColor];[self.contentView addSubview:self.titleLabel];self.button = [UIButton buttonWithType:UIButtonTypeCustom];[self.button setImage:[[UIImage imageNamed:@"im.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateNormal];[self.contentView addSubview:self.button];self.button.userInteractionEnabled = YES;[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {make.left.equalTo(self).offset(15);make.centerY.equalTo(self);make.right.equalTo(self);}];[self.button mas_makeConstraints:^(MASConstraintMaker *make) {make.width.height.equalTo(@25);make.right.equalTo(self.contentView).offset(-15);make.centerY.equalTo(self);}];
}
@end

上面我们就完成了准备工作,接下来该完成UITableView大的具体实现了

实现VC

折叠关系的判断

- (void)reverseCollapase:(UIButton* )button {NSInteger section = button.tag - 101;Model* sectionData = self.models[section];sectionData.collapsed = !sectionData.collapsed;[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];
}- (void)rotateButton:(UIButton* )button withCollapased:(BOOL)collapased {CGFloat angle = collapased ? 0.0 : M_PI_2;button.transform = CGAffineTransformMakeRotation(angle);
}

实现折叠关系的转变其实只需要两步,首先为每个section的header中的按钮添加点击事件,其次是在点击实现中按钮的collapase属性转换以判断section的展开与闭合

 [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];

这个方法是用来重新加载section的方法,NSIndexSet就是一个用来表示一组索引的类,使用该方法可以创建一个只包含单个索引的集合,UITableViewRowAnimationNone用来设置刷新时的动画效果

注册header

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {Header* header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"header"];if (!header) {header = [[Header alloc] initWithReuseIdentifier:@"header"];}Model* sectionData = self.models[section];header.titleLabel.text = sectionData.name;header.button.tag = section + 101;[header.button addTarget:self action:@selector(reverseCollapase:) forControlEvents:UIControlEventTouchUpInside];[self rotateButton:header.button withCollapased:sectionData.collapsed];return header;
}

注意标识符的匹配

完整VC代码

//  Created by xiaoli pop on 2025/9/17.
//#import "MyViewController.h"
#import "Header.h"
#import "Model.h"
@interface MyViewController ()<UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong)UITableView* tableView;
@property (nonatomic, strong)NSMutableArray* models;
@end@implementation MyViewController- (void)viewDidLoad {[super viewDidLoad];[self setUpMyData];self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];self.tableView.delegate = self;self.tableView.dataSource = self;[self.view addSubview:self.tableView];[self.tableView registerClass:[Header class] forHeaderFooterViewReuseIdentifier:@"header"];[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
}- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {return self.models.count;
}- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {return 0;
}- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];return view;
}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {Model* sectionData = self.models[section];if (sectionData.collapsed) {return 0;} else {return sectionData.items.count;}
}- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];Model* sectionData = self.models[indexPath.section];cell.textLabel.text = sectionData.items[indexPath.row];return cell;
}- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {Header* header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"header"];if (!header) {header = [[Header alloc] initWithReuseIdentifier:@"header"];}Model* sectionData = self.models[section];header.titleLabel.text = sectionData.name;header.button.tag = section + 101;[header.button addTarget:self action:@selector(reverseCollapase:) forControlEvents:UIControlEventTouchUpInside];[self rotateButton:header.button withCollapased:sectionData.collapsed];return header;
}//- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//    NSInteger section = indexPath.section;
//    Model* sectionData = self.models[section];
//    sectionData.collapsed = !sectionData.collapsed;
//}- (void)reverseCollapase:(UIButton* )button {NSInteger section = button.tag - 101;Model* sectionData = self.models[section];sectionData.collapsed = !sectionData.collapsed;[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];
}- (void)rotateButton:(UIButton* )button withCollapased:(BOOL)collapased {CGFloat angle = collapased ? 0.0 : M_PI_2;button.transform = CGAffineTransformMakeRotation(angle);
}- (void)setUpMyData {self.models = [NSMutableArray array];[self.models addObject:[[Model alloc] initWithName:@"iOS" withItems:@[@"xiaoli", @"xiaoliu", @"xiaoding", @"xiaofu", @"xiaoyang", @"xiaowu"] andCollapsed:NO]];[self.models addObject:[[Model alloc] initWithName:@"android" withItems:@[@"xiaoji", @"xiaoyang", @"xiaohong", @"xiaobai", @"xiaoyang", @"xiaowu"] andCollapsed:NO]];[self.models addObject:[[Model alloc] initWithName:@"server" withItems:@[@"xiaohei", @"xiaohuang", @"xiaodang", @"xiaofu", @"xiaoyang", @"xiaowu"] andCollapsed:NO]];
}

效果

在这里插入图片描述


文章转载自:

http://dkK6Qwgf.tbnpn.cn
http://gbEiaI9L.tbnpn.cn
http://gGrO6nWP.tbnpn.cn
http://P63VFp6V.tbnpn.cn
http://UygMEmV3.tbnpn.cn
http://V8xXMgU1.tbnpn.cn
http://IHPNW4Zm.tbnpn.cn
http://zXeVrxSy.tbnpn.cn
http://3r7XK67a.tbnpn.cn
http://gdHhCkeV.tbnpn.cn
http://CsXF2b93.tbnpn.cn
http://kqLfQZfT.tbnpn.cn
http://flJiq9cE.tbnpn.cn
http://3THLfJ5m.tbnpn.cn
http://e2BZ79tk.tbnpn.cn
http://R003IXXW.tbnpn.cn
http://h9e564u3.tbnpn.cn
http://im8CZxAH.tbnpn.cn
http://5yfSBjTX.tbnpn.cn
http://MqEeOJxu.tbnpn.cn
http://D4cSWCo8.tbnpn.cn
http://Z5M7B8xv.tbnpn.cn
http://pyhfg6bK.tbnpn.cn
http://q52PITcF.tbnpn.cn
http://ZLxq2K8c.tbnpn.cn
http://fv7NJ5mW.tbnpn.cn
http://P4OCfjqf.tbnpn.cn
http://JjF6CmHd.tbnpn.cn
http://j3q36fM6.tbnpn.cn
http://KdpGug8n.tbnpn.cn
http://www.dtcms.com/a/388424.html

相关文章:

  • 关于层级问题
  • Linux基础命令汇总
  • getchar 和 putchar
  • 【序列晋升】35 Spring Data Envers 轻量级集成数据审计
  • 快速入门HarmonyOS应用开发(二)
  • 绿联、极空间、飞牛NAS无需安装,实现快速远程访问
  • Datawhale 理工科-大模型入门实训课程 202509 第1次作业
  • 城市治理综合管理平台
  • 《嵌入式硬件(十三):基于IMX6ULL的增强型中断周期定时器(EPIT)操作》
  • PM2 入门指南与常用命令(含 开机自启、Node.js 及 Java 服务部署)
  • 汽车多核架构中内存系统故障检测的改进算法
  • C++真的比Python更快吗?
  • 【实操分享】使用 SeeDream 4.0 进行 AI 修图——开启专属“AI 云旅拍”
  • 不依赖第三方,不销毁重建,loveqq 框架如何原生实现动态线程池?
  • Python中正则的三个基础方法
  • 最外层的项目没有父pom配置文件,有很多子模块(maven项目)导入idea中,左侧模块显示不全问题解决
  • 前端将一个 DOM 元素滚动到视口顶部
  • 前端-防重复点击/防抖的方案
  • doris数据库问题
  • PyQt5中实现只读QLineEdit控件的完整指南
  • 金融工程vs金融数学:谁更贴近量化交易?
  • LeetCode 167.两数之和 II - 输入有序数组
  • 小杰机器学习高级(one)——激活函数——sigmoid、tanh、Relu、Leaky Relu、Prelu、ELU、softmax
  • OpenAI原生调用 vs LangChain调用方式的关系
  • [Token剪枝]Token Cropr: 针对众多任务的更快ViT, CVPR2025
  • NW725NW743美光固态闪存NW727NW734
  • 【Linux】归档、压缩、用户管理
  • Lattice FPGA 开发流程(以 ECP5 为例)
  • 大模型实战应用指南:从GPT-4.5到LLaMA的行业解决方案
  • 告别人工标注瓶颈!Reward-RAG:用 CriticGPT 打造更懂人类偏好的检索模型