封装了一个仿照抖音效果的iOS评论弹窗
需求背景
开发一个类似抖音评论弹窗交互效果的弹窗,支持滑动消失,
滑动查看评论
效果如下图
思路
创建一个视图,该视图上面放置一个tableView, 该视图上添加一个滑动手势,同时设置代理,实现代理方法
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
支持同时响应手势,就是为了我们tableView滚动到顶部的时候,继续滚动父亲视图,达到连续滑动的效果,如果不是设置同时响应的话,我们滚动到tableView顶部,继续向下滑动的话,整个弹窗是不会向下滑动的,同时,滚动到顶部的时候,要设置tableView.pangesture.enabled = NO,否则反复来回滑动的时候,会造成两个视图同时滚动的效果
代码
//
// LBCommentPopView.m
// TEXT
//
// Created by mac on 2024/7/7.
// Copyright © 2024 刘博. All rights reserved.
//#import "LBCommentPopView.h"
#import "LBFunctionTestHeader.h"@interface LBCommentPopView () <UIGestureRecognizerDelegate>@property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;@property (nonatomic, weak) UIScrollView *scrollView;
@property (nonatomic, assign) BOOL isDragScrollView;
@property (nonatomic, assign) CGFloat lastTransitionY;@end@implementation LBCommentPopView- (instancetype)initWithFrame:(CGRect)frame {if (self = [super initWithFrame:frame]) {[self createRecognizer];}return self;
}- (void)createRecognizer {[self addGestureRecognizer:self.tapGesture];[self addGestureRecognizer:self.panGesture];
}- (void)show:(void (^)(void))completion {self.hidden = NO;[UIView animateWithDuration:0.25f animations:^{CGRect frame = self.containerView.frame;frame.origin.y = self.frame.size.height - frame.size.height;self.containerView.frame = frame;} completion:^(BOOL finished) {!completion ? : completion();}];
}- (void)dismiss {[UIView animateWithDuration:0.25f animations:^{CGRect frame = self.containerView.frame;frame.origin.y = ScreenHeight;self.containerView.frame = frame;}completion:^(BOOL finished) {self.hidden = YES;}];
}#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {if (gestureRecognizer == self.panGesture) {UIView *touchView = touch.view;while (touchView != nil) {if ([touchView isKindOfClass:[UIScrollView class]]) {self.scrollView = (UIScrollView *)touchView;self.isDragScrollView = YES;break;}else if (touchView == self.containerView) {self.isDragScrollView = NO;break;}touchView = (UIView *)[touchView nextResponder];}}return YES;
}- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {if (gestureRecognizer == self.tapGesture) {CGPoint point = [gestureRecognizer locationInView:self.containerView];if ([self.containerView.layer containsPoint:point] && gestureRecognizer.view == self) {return NO;}}else if (gestureRecognizer == self.panGesture) {return YES;}return YES;
}// 是否与其他手势共存
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {if (gestureRecognizer == self.panGesture) {if ([otherGestureRecognizer isKindOfClass:NSClassFromString(@"UIScrollViewPanGestureRecognizer")] || [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {if ([otherGestureRecognizer.view isKindOfClass:[UIScrollView class]]) {return YES;}}}return NO;
}#pragma mark - HandleGesture
- (void)handleTapGesture:(UITapGestureRecognizer *)tapGesture {CGPoint point = [tapGesture locationInView:self.containerView];if (![self.containerView.layer containsPoint:point] && tapGesture.view == self) {[self dismiss];}
}- (void)handlePanGesture:(UIPanGestureRecognizer *)panGesture {CGPoint translation = [panGesture translationInView:self.containerView];if (self.isDragScrollView) {// 当UIScrollView在最顶部时,处理视图的滑动if (self.scrollView.contentOffset.y <= 0) {if (translation.y > 0) { // 向下拖拽self.scrollView.contentOffset = CGPointZero;self.scrollView.panGestureRecognizer.enabled = NO;self.isDragScrollView = NO;CGRect contentFrame = self.containerView.frame;contentFrame.origin.y += translation.y;self.containerView.frame = contentFrame;}}}else {CGFloat contentM = (self.frame.size.height - self.containerView.frame.size.height);if (translation.y > 0) { // 向下拖拽CGRect contentFrame = self.containerView.frame;contentFrame.origin.y += translation.y;self.containerView.frame = contentFrame;}else if (translation.y < 0 && self.containerView.frame.origin.y > contentM) { // 向上拖拽CGRect contentFrame = self.containerView.frame;contentFrame.origin.y = MAX((self.containerView.frame.origin.y + translation.y), contentM);self.containerView.frame = contentFrame;}}[panGesture setTranslation:CGPointZero inView:self.containerView];if (panGesture.state == UIGestureRecognizerStateEnded) {CGPoint velocity = [panGesture velocityInView:self.containerView];self.scrollView.panGestureRecognizer.enabled = YES;// 结束时的速度>0 滑动距离> 5 且UIScrollView滑动到最顶部NSLog(@"%f", self.lastTransitionY);if (velocity.y > 0 && self.lastTransitionY > 5 && !self.isDragScrollView) {[self dismiss];}else {[self show:^{}];}}self.lastTransitionY = translation.y;
}#pragma mark - lazy load- (UITapGestureRecognizer *)tapGesture {if (!_tapGesture) {_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];_tapGesture.delegate = self;}return _tapGesture;
}- (UIPanGestureRecognizer *)panGesture {if (!_panGesture) {_panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];_panGesture.delegate = self;}return _panGesture;
}@end
demo link
相关文章:

封装了一个仿照抖音效果的iOS评论弹窗
需求背景 开发一个类似抖音评论弹窗交互效果的弹窗,支持滑动消失, 滑动查看评论 效果如下图 思路 创建一个视图,该视图上面放置一个tableView, 该视图上添加一个滑动手势,同时设置代理,实现代理方法 (BOOL)gestur…...

【JavaWeb程序设计】Servlet(二)
目录 一、改进上一篇博客Servlet(一)的第一题 1. 运行截图 2. 建表 3. 实体类 4. JSP页面 4.1 login.jsp 4.2 loginSuccess.jsp 4.3 loginFail.jsp 5. mybatis-config.xml 6. 工具类:创建SqlSessionFactory实例,进行 My…...

php探针
php探针是用来探测空间、服务器运行状况和PHP信息用的,探针可以实时查看服务器硬盘资源、内存占用、网卡流量、系统负载、服务器时间等信息。 下面就分享下我是怎样利用php探针来探测服务器网站空间速度、性能、安全功能等。 具体步骤如下: 1.从网上下…...

泰勒级数 (Taylor Series) 动画展示 包括源码
泰勒级数 (Taylor Series) 动画展示 包括源码 flyfish 泰勒级数(英语:Taylor series)用无限项连加式 - 级数来表示一个函数,这些相加的项由函数在某一点的导数求得。 定义了一个函数f(x)表示要近似的函数 sin ( x ) \sin(x) …...

蔚来汽车:拥抱TiDB,实现数据库性能与稳定性的飞跃
作者: Billdi表弟 原文来源: https://tidb.net/blog/449c3f5b 演讲嘉宾:吴记 蔚来汽车Tidb爱好者 整理编辑:黄漫绅(表妹)、李仲舒、吴记 本文来自 TiDB 社区合肥站走进蔚来汽车——来自吴记老师的演讲…...

【Django+Vue3 线上教育平台项目实战】构建高效线上教育平台之首页模块
文章目录 前言一、导航功能实现a.效果图:b.后端代码c.前端代码 二、轮播图功能实现a.效果图b.后端代码c.前端代码 三、标签栏功能实现a.效果图b.后端代码c.前端代码 四、侧边栏功能实现1.整体效果图2.侧边栏功能实现a.效果图b.后端代码c.前端代码 3.侧边栏展示分类及…...

对比 UUIDv1 和 UUIDv6
UUIDv6是UUIDv1的字段兼容版本,重新排序以改善数据库局部性。UUIDv6主要在使用UUIDv1的上下文中实现。不涉及遗留UUIDv1的系统应该改用UUIDv7。 与 UUIDv1 将时间戳分割成低、中、高三个部分不同,UUIDv6 改变了这一序列,使时间戳字节从最重要…...

记一次饱经挫折的阿里云ROS部署经历
前言 最近在参加的几个项目测评里,我发现**“一键部署”这功能真心好用,省下了不少宝贵时间和力气,再加上看到阿里云现在有个开源上云**的活动。趁着这波热潮,今天就聊聊怎么从头开始,一步步搞定阿里云的资源编排服务…...

代码运行故障排除:PyCharm中的问题解决指南
代码运行故障排除:PyCharm中的问题解决指南 引言 PyCharm,作为一款流行的集成开发环境(IDE),提供了强大的工具来支持Python开发。然而,即使是最先进的IDE也可能遇到代码无法运行的问题。这些问题可能由多…...

css实现渐进中嵌套渐进的方法
这是我们想要的实现效果: 思路: 1.有一个底色的背景渐变 2.需要几个小的块级元素做绝对定位通过渐变filter模糊来实现 注意:这里的采用的定位方法,所以在内部的元素一律要使用绝对定位,否则会出现层级的问题&…...

JavaWeb后端学习
Web:全球局域网,万维网,能通过浏览器访问的网站 Maven Apache旗下的一个开源项目,是一款用于管理和构建Java项目的工具 作用: 依赖管理:方便快捷的管理项目以来的资源(jar包)&am…...

VUE_TypeError: Cannot convert a BigInt value to a number at Math.pow 解决方法
错误信息 TypeError: Cannot convert a BigInt value to a number at Math.pow vue 或 react package.json添加 "browserslist": {"production": ["chrome > 67","edge > 79","firefox > 68","opera >…...

Linux下mysql数据库的导入与导出以及查看端口
一:Linux下导出数据库 1、基础导出 要在Linux系统中将MySQL数据库导出,通常使用mysqldump命令行工具。以下是一个基本的命令示例,用于导出整个数据库: mysqldump -u username -p database_name > export_filename.sql 其中&a…...

Open3d入门 一文读懂三维点云
三维点云技术的发展始于20世纪60年代,随着激光雷达和三维扫描技术的进步,在建筑、考古、地理信息系统和制造等领域得到了广泛应用。20世纪90年代,随着计算机处理能力的提升,点云数据的采集和处理变得更加高效,推动了自…...

pyinstaller系列教程(一)-基础介绍
1.介绍 PyInstaller是一个用于将Python应用程序打包为独立可执行文件的工具,它支持跨平台操作,包括Windows、Linux和MacOS等操作系统。特点如下: 跨平台支持:PyInstaller可以在多个操作系统上运行,并生成相应平台的可…...

echarts图表:类目轴
category 类目轴,适用于离散的类目数据。 例如商品名称、时间等。 类目轴上的每个刻度代表一个类目,刻度之间没有量的关系,只是简单的分类。 在类目轴上,数据点会对应到相应的类目上。...

SSM贫困生申请管理系统-计算机源码84308
摘要 随着教育信息化的不断推进,越来越多的高校开始借助信息技术手段提升贫困生申请管理的效率与准确性。为此,我们设计并实现了SSM贫困生申请管理系统,旨在通过信息化手段优化贫困生申请流程,提高管理效率,为贫困生提…...

[C++]——同步异步日志系统(5)
同步异步日志系统 一、日志消息格式化设计1.1 格式化子项类的定义和实现1.2 格式化类的定义和实现 二、日志落地类设计2.1 日志落地模块功能实现与测试2.2 日志落地模块功能功能扩展 一、日志消息格式化设计 日志格式化模块的作用:对日志消息进行格式化,…...

Qt项目:基于Qt实现的网络聊天室---TCP服务器和token验证
文章目录 TCP服务器设计客户端TCP管理者ChatServerAsioIOServicePoolSession层LogicSystem总结 token验证模块完善protoStatusServer验证token客户端处理登陆回包用户管理登陆界面 本篇完成的模块是TCP服务器的设计和token验证 TCP服务器设计 客户端TCP管理者 因为聊天服务要…...

深入理解C++构造函数
目录 1.引言 2.默认构造函数 3.自定义构造函数 4.带继承关系类的构造函数 5.带多重继承关系类的构造函数 6.带虚继承关系类的构造函数 7.总结 1.引言 对于学过C的来说,构造函数是非常熟悉不过的了。但是你真正了解它吗?构造函数内部初始化变量的顺…...

J025_斗地主游戏案例开发(简版)
一、需求描述 完成斗地主游戏的案例开发。 业务:总共有54张牌; 点数:3、4、5、6、7、8、9、10、J、Q、K、A、2 花色:黑桃、红桃、方片、梅花 大小王:大王、小王 点数分别要组合4种花色,大小王各一张。…...

路径规划 | 飞蛾扑火算法求解二维栅格路径规划(Matlab)
目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 路径规划 | 飞蛾扑火算法求解二维栅格路径规划(Matlab)。 飞蛾扑火算法(Firefly Algorithm)是一种基于自然界萤火虫行为的优化算法,在路径规划问题中也可以应…...

优化Cocos Creator 包体体积
优化Cocos Creator 包体体积 引言一、优化图片文件体积:二、优化声音文件体积:三、优化引擎代码体积:四、 优化字体字库文件大小: 引言 优化Cocos Creator项目的包体体积是一个常见且重要的任务,尤其是在移动设备和网…...

TCPDump协议分析工具
TCPDump协议分析工具 TCPDump是一个强大的命令行工具,用于捕获和分析网络数据包。它能够实时监控和记录网络流量,帮助网络管理员和安全专家排查网络问题、分析流量和检测网络攻击。以下是TCPDump的详细介绍,包括其安装、基本使用、过滤规则和…...

土壤分析仪:解密土壤之奥秘的科技先锋
在农业生产和生态保护的道路上,土壤的质量与状况一直是我们关注的焦点。土壤分析仪,作为现代科技在农业和环保领域的杰出代表,以其高效、精准的分析能力,为我们揭示了土壤的奥秘,为农业生产提供了科学指导,…...

计算1的数量
1. 计算1的数量 题目ID:9809必做题100分 最新提交: Accepted 100 分 历史最高: Accepted 100 分 时间限制: 1000ms 空间限制: 524288kB 题目描述 给定一个n*m的二进制矩阵,请你数一数矩阵中完全被0上下左右包围的1的数…...

Linux udp编程
我最近开了几个专栏,诚信互三! > |||《算法专栏》::刷题教程来自网站《代码随想录》。||| > |||《C专栏》::记录我学习C的经历,看完你一定会有收获。||| > |||《Linux专栏》࿱…...

【开源项目】Rust开发复制文件夹目录结构工具
说明 由于我经常需要在多个大容量的移动硬盘中查找和新增文件,我希望把硬盘的目录结构放到服务器的自建网盘中,因此开发了这个工具,使得在不同硬盘之间的文件管理变得更加便捷 项目地址:https://github.com/VinciYan/folder_clon…...

PostgreSQL的pg_dirtyread工具
PostgreSQL的pg_dirtyread工具 pg_dirtyread 是一个第三方PostgreSQL扩展,它允许用户读取数据库文件中的“脏”数据,即那些被标记为删除或不再可见的数据。这个扩展对于数据恢复和调试非常有用,尤其是在需要恢复被删除或更新前的数据时。 以…...

苹果梦碎:Vision Pro的辉煌与失落,苹果已决定暂停 Vision Pro 后续产品的研发工作
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 苹果Vision Pro:科技巨头的跌宕起伏 在科技的海洋中,苹果公司一直以其创新精神和卓越品质引领潮流。然而,即…...