封装了一个仿照抖音效果的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/373477.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

挑战杯 opencv 图像识别 指纹识别 - python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于机器视觉的指纹识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c;适…

基于swagger插件的方式推送接口文档至torna

目录 一、前言二、登录torna三、创建/选择空间四、创建/选择项目五、创建/选择应用六、获取应用的token七、服务推送7.1 引入maven依赖7.2 test下面按照如下方式新建文件 一、前言 Torna作为一款企业级文档管理系统&#xff0c;支持了很多种接口文档的推送方式。官方比较推荐的…

蓝牙人员定位精准吗?是否会对人体有伤害?

不知道大家现在使用的蓝牙人员定位系统都是什么样的呢&#xff1f;其实就出行而言&#xff0c;使用GPS定位也就是足够了的&#xff0c;而且目前的定位相对也比较精准了&#xff0c;效果还是很不错的。但是如果说是室内定位&#xff0c;很显然常规的定位系统是无法满足使用需求的…

[数据结构] 基于插入的排序 插入排序希尔排序

标题&#xff1a;[数据结构] 排序#插入排序&希尔排序 水墨不写bug 目录 &#xff08;一&#xff09;插入排序 实现思路&#xff1a; 插入排序实现&#xff1a; &#xff08;二&#xff09;希尔排序 希尔排序的基本思想&#xff1a; 希尔排序的实现&#xff1a; 正…

PHP同城多商户多行业系统小程序源码

同城新生态&#xff0c;解锁多商户多行业系统的无限魅力&#x1f306;&#x1f680; &#x1f308; 开篇&#xff1a;同城新纪元&#xff0c;多商户多行业系统引领潮流&#xff01; 想象一下&#xff0c;在同一个城市内&#xff0c;无论是美食探索、购物狂欢&#xff0c;还是…

Python在量化交易中的应用

量化交易近年来越来越受到投资者的青睐。Python因其简洁的语法和丰富的库&#xff0c;成为量化交易的首选编程语言。本文将从Python量化交易的基础知识、主要技术及其在实际交易中的应用三个方面进行介绍。 一、Python量化交易的基础知识 1. 量化交易的概念 量化交易是指利用…

东方通Tongweb发布vue前端

一、前端包中添加文件 1、解压vue打包文件 以dist.zip为例&#xff0c;解压之后得到dist文件夹&#xff0c;进入dist文件夹&#xff0c;新建WEB-INF文件夹&#xff0c;进入WEB-INF文件夹&#xff0c;新建web.xml文件&#xff0c; 打开web.xml文件&#xff0c;输入以下内容 …

sdwan是硬件还是网络协议?

SD-WAN&#xff08;Software-Defined Wide Area Network&#xff0c;软件定义广域网&#xff09;并不是一个硬件产品或单一的网络协议&#xff0c;而是结合了软件、硬件和网络技术的一种解决方案。SD-WAN的核心在于其软件定义的特性&#xff0c;它通过软件来控制和管理广域网的…

【BUG】RestTemplate发送Post请求后,响应中编码为gzip而导致的报错

BUG描述 20240613-09:59:59.062|INFO|null|810184|xxx|xxx||8|http-nio-xxx-exec-1|com.xxx.jim.xxx.XXXController.?.?|MSG接收到来自xxx的文件请求 headers:[host:"xxx", accept:"text/html,application/json,application/xhtmlxml,application/xml;q0.9,*…

Apache Seata分布式事务原理解析探秘

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 前言 fescar发布已有时日&#xff0c;分布式事务一直是业界备受关注的领域&#xff0c;fesca…

如何探索高效知识管理:FlowUs知识库体验很好

在当今信息爆炸的时代&#xff0c;有效的知识管理对于个人和团队的发展至关重要。FlowUs 知识库作为一款创新的知识管理工具&#xff0c;正逐渐成为众多用户的首选&#xff0c;为他们带来了高效、便捷和有条理的知识管理体验。 FlowUs 知识库的一大特色在于其简洁直观的界面设计…

雷池WAF动态防护功能初体验

一、 介绍 大名鼎鼎的雷池WAF最近新上了个名为 动态防护 的功能 所谓动态防护&#xff0c;是在用户浏览到的网页内容不变的情况下&#xff0c;将网页赋予动态特性&#xff0c;即使是静态页面&#xff0c;也会具有动态的随机性。 说白了就是给你网站的 html 和 js 代码加上加密…

前端与嵌入式开发通信之QWebChannel(Qt)

前端与嵌入式开发通信之QWebChannel 最近开发中需要用到和c开发的操作台进行通信的的需求&#xff0c;就找到了这个技术&#xff0c;记录一下 首先需要安装导入 qwebchannel npm i qwebchannel import { QWebChannel } from "qwebchannel"; 初始化qwebchannel并封…

哈喽GPT-4o,程序员如何通过GPT-4o提高办公效率

目录 一、编写工作汇报Prompt&#xff1a;我是一名Java开发工程师&#xff0c;请写一份工作总结&#xff0c;工作内容是一个SpringBootVue实现的图书管理系统&#xff0c;按下面的结构来撰写&#xff1a;1. 工作背景&#xff1b;2. 工作内容&#xff1b;3. 工作建议&#xff1b…

springboot中@bean注解的创建和使用

bean的创建顺序 在Spring Boot中&#xff0c;当一个配置类&#xff08;使用Configuration注解的类&#xff09;中定义了多个bean时&#xff0c;这些bean的创建顺序并不完全由它们在类中的声明顺序决定。Spring框架在创建和管理bean时&#xff0c;遵循了复杂的依赖注入和生命周…

简单仿写SpringIOC

gitee地址&#xff08;需要自取&#xff09;ioc_Imitation: 简单仿写IOC (gitee.com) 项目目录结构 Autowired Target(ElementType.FIELD) Retention(RetentionPolicy.RUNTIME) public interface Autowired { }Component Target(ElementType.TYPE) Retention(RetentionPoli…

文献笔记|综述|When Large Language Model Meets Optimization

When Large Language Model Meets Optimization 题目&#xff1a;当大型语言模型遇到优化时 作者&#xff1a;Sen Huang , Kaixiang Yang , Sheng Qi and Rui Wang 来源&#xff1a;arXiv 单位&#xff1a;华南理工大学 文章目录 When Large Language Model Meets Optimization…

Redis主从部署

文章目录 Redis主从部署1.下载安装Redis2.单点双副本主从配置1.修改配置信息2.修改配置文件redis.conf3.拷贝配置文件到每一个实例文件夹里4.修改每一个实例的端口和工作目录5.配置主从关系6.检查效果 3.哨兵模式监控主从1.创建实例目录2.复制配置文件并进行修改3.启动并测试 4…

Java增加线程后kafka仍然消费很慢

文章目录 一、问题分析二、控制kafka消费速度属性三、案例描述 一、问题分析 Java增加线程通常是为了提高程序的并发处理能力&#xff0c;但如果Kafka仍然消费很慢&#xff0c;可能的原因有&#xff1a; 网络延迟较大&#xff1a;如果网络延迟较大&#xff0c;即使开启了多线…

使用redis进行短信登录验证(验证码打印在控制台)

使用redis进行短信登录验证 一、流程1. 总体流程图2. 流程文字讲解&#xff1a;3.代码3.1 UserServiceImpl&#xff1a;&#xff08;难点&#xff09;3.2 拦截器LoginInterceptor&#xff1a;3.3 拦截器配置类&#xff1a; 4 功能实现&#xff0c;成功存入redis &#xff08;黑…