高仿简书个人中心
概述
详细
一、准备工作
高仿简书个人中心上下 左右滑动页面,开始做之前,首先思路要清晰,逻辑比较繁琐。
首先看到简书个人中心页面时,我大致给他划分为4大部分:
1,首先是用户的头像
2,用户资料信息
3,三个标题(TitleView)
4,下面UITableView
因为此处有左右滑动和上下两种滑动,所以在上面的2,3,4 我们整体放在一个ScrollView上, 而1,用户头像的改变,根据ScrollView 的上下滑动 y 值对头像大小进行处理。
二、程序实现
项目中不需要配置任何东西,全都是逻辑方面的东西,只要思维逻辑清楚,我们就开始干,
在上面的项目图中可以清楚的看到,所有的View都是自定义实现的,控制控制器的大小,之前一阿里朋友告诉我,他们公司的硬性规定,无论页面实现什么功能,在控制器中的代码 不能超过300 行,能封装的尽量封装起来,不做繁琐的代码Copy。
首先看下如何自定义头像View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** 初始化方法 * 头像图片 */ - (instancetype)initWithImage:(UIImage *)image; /** 更新头像大小 * 滚动视图 */ - ( void )reloadSizeWithScrollView:(UIScrollView *)scrollView; /** * 点击头像回调 */ - ( void )handleClickActionWithBlock:(ClickImageBlock)block; |
头像大小的改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | - ( void )observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:( void *)context { if ([keyPath isEqualToString:ContentOffset] && object == self.scrollView) { CGFloat offsetY = self.scrollView.contentOffset.y; CGFloat scale = 1.0; if (offsetY < 0) { // 放大 scale = MIN(1.5, 1 - offsetY / 300); //简书没有这个功能 } else if (offsetY > 0) { // 缩小 scale = MAX(0.40, 1 - offsetY / 300); } self.yourImages.transform = CGAffineTransformMakeScale(scale, scale); CGRect frame = self.yourImages.frame; frame.origin.y = 15; self.yourImages.frame = frame; } } |
自定义TitleView(要可以左右滑动,标题下方有标注)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | - ( void )titleButtonClicked:(UIButton *)button { _selectedIndex = button.tag; if (self.selectedButton) { self.selectedButton.selected = YES; } button.selected = NO; self.selectedButton = button; if (self.buttonSelected) { self.buttonSelected(button.tag); } NSString* title = self.gztitles[button.tag]; CGFloat sliderWidth = button.titleLabel.font.pointSize * title.length; [self.sliderView mas_remakeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(sliderWidth); make.height.mas_equalTo(2); make.centerX.equalTo(button); make.bottom.equalTo(self).offset(-2); }]; [UIView animateWithDuration:0.25 animations:^{ [self layoutIfNeeded]; }]; } - ( void )setSelectedIndex:(NSInteger)selectedIndex { _selectedIndex = selectedIndex; UIButton* button = self.subviews[selectedIndex]; [self titleButtonClicked:button]; } - ( void )setGztitles:(NSArray *)gztitles { [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; _gztitles = gztitles; CGFloat width = [UIScreen mainScreen].bounds.size.width / gztitles.count; for ( int i = 0; i<gztitles.count; i++ ) { UIButton* titleButton = [self titleButton:gztitles[i]]; titleButton.tag = i; [self addSubview:titleButton]; [titleButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.bottom.equalTo(self); make.left.equalTo(self).offset(width * i); make.width.mas_equalTo(width); }]; if (i != 0) { titleButton.selected = YES; } else { self.selectedButton = titleButton; } } UIButton *button = self.subviews[0]; NSString *title = gztitles[0]; CGFloat sliderWidth = button.titleLabel.font.pointSize * title.length; [self addSubview:self.sliderView]; [self.sliderView mas_makeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(sliderWidth); make.height.mas_equalTo(4); make.centerX.equalTo(button); make.bottom.equalTo(self).offset(-3); }]; [self layoutIfNeeded]; } - (UIButton *)titleButton:(NSString *)title { UIButton* titleButton = [[UIButton alloc] init]; [titleButton addTarget:self action:@selector(titleButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; titleButton.titleLabel.font = [UIFont systemFontOfSize:15]; [titleButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [titleButton setTitleColor:[UIColor grayColor] forState:UIControlStateSelected]; [titleButton setTitle:title forState:UIControlStateNormal]; return titleButton; } |
自定义的信息页面
1 2 3 4 5 6 7 | - ( void )layoutSubviews { [super layoutSubviews]; [self addSubview:self.nameLabel]; [self addSubview:self.Address]; [self addSubview:self.infoLabel]; [self addSubview:self.editInfoButton]; } |
简单的添加属性就好
UITableView的话也是简单的TableView
最后到我们的控制器页面,在这个页面我们只负责
UITableViewDelegate 的东西,数据我们都在自定义的页面处理,减少控制器页面的代码量,
在控制器中我们就是将自定义的View组合起来
首先是整体一个ScrollView 然后在其上面添加我们事先定义的所有控件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | GZContentScrollView *scrollView = [[GZContentScrollView alloc] init]; scrollView.delaysContentTouches = NO; [self.view addSubview:scrollView]; self.scrollView = scrollView; scrollView.pagingEnabled = YES; scrollView.showsVerticalScrollIndicator = NO; scrollView.showsHorizontalScrollIndicator = NO; scrollView.delegate = self; scrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width * 3, 0); UIView *headView = [[UIView alloc] init]; headView.frame = CGRectMake(0, 0, 0, GZHeadViewHeight + GZTitleHeight); GZTableView1 *gzTableView1 = [[GZTableView1 alloc] init]; gzTableView1.delegate = self; gzTableView1.separatorStyle = UITableViewCellSeparatorStyleNone; self.GZTableView1 = gzTableView1; gzTableView1.tableHeaderView = headView; [scrollView addSubview:gzTableView1]; [gzTableView1 mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(scrollView); make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width); make.top.equalTo(self.view); make.bottom.equalTo(self.view); }]; GZTableView2 *gzTableView2= [[GZTableView2 alloc] init]; gzTableView2.delegate = self; gzTableView2.separatorStyle = UITableViewCellSeparatorStyleNone; self.GZTableView2 = gzTableView2; gzTableView2.tableHeaderView = headView; [scrollView addSubview:gzTableView2]; [gzTableView2 mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(scrollView).offset([UIScreen mainScreen].bounds.size.width); make.width.equalTo(gzTableView1); make.top.bottom.equalTo(gzTableView1); }]; GZTableView3 *gzTableView3 = [[GZTableView3 alloc] init]; gzTableView3.delegate = self; gzTableView3.separatorStyle = UITableViewCellSeparatorStyleNone; self.GZTableView3 = gzTableView3; gzTableView3.tableHeaderView = headView; [scrollView addSubview:gzTableView3]; [gzTableView3 mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(scrollView).offset([UIScreen mainScreen].bounds.size.width * 2); make.width.equalTo(gzTableView1); make.top.bottom.equalTo(gzTableView1); }]; } |
头部视图添加
视图都添加完毕之后,要实现滑动事件,我们必须要进行下面的活动:
1 2 3 4 5 6 7 | - ( void )scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == self.scrollView || !scrollView.window) { return ; } CGFloat offsetY = scrollView.contentOffset.y; CGFloat originY = 0; CGFloat otherOffsetY = 0; |
判断ScrollView 是因为 我们这个页面有两种滑动事件
至此,简书个人中心页面的功能都已实现。
三、运行效果
运行效果如下图显示:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?