封装了一个仿照抖音效果的iOS评论弹窗

embedded/2024/12/22 15:52:39/

需求背景

开发一个类似抖音评论弹窗交互效果的弹窗,支持滑动消失,
滑动查看评论
效果如下图
请添加图片描述

思路

创建一个视图,该视图上面放置一个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.ppmy.cn/embedded/59116.html

相关文章

健康云足迹:在iCloud中珍藏您的个人健康检查记录

健康云足迹&#xff1a;在iCloud中珍藏您的个人健康检查记录 随着健康意识的提高&#xff0c;个人健康数据管理变得越来越重要。iCloud作为苹果公司提供的云服务&#xff0c;不仅能够同步您的联系人、日历和照片&#xff0c;还能成为您个人健康检查记录的安全港湾。本文将详细…

ScrapySharp框架:小红书视频数据采集的API集成与应用

引言 随着大数据时代的到来&#xff0c;数据采集成为了互联网企业获取信息的重要手段。小红书作为一个集社交和电商于一体的平台&#xff0c;其丰富的用户生成内容&#xff08;UGC&#xff09;为数据采集提供了丰富的资源。本文将介绍如何使用ScrapySharp框架进行小红书视频数…

微信小程序 2024年更新内容汇总

本心、输入输出、结果 文章目录 微信小程序 2024年更新内容汇总v3.4.10 (2024-07-03)v3.4.9 (2024-06-26)v3.4.8 (2024-06-19)v3.4.7 (2024-06-07)v3.4.6 (2024-05-29)v3.4.5 (2024-05-23)v3.4.4 (2024-05-11)v3.4.3 (2024-04-24)v3.4.2 (2024-04-11)v3.4.1 (2024-04-02)v3.4.1…

C++ enum class转常量

当使用 enum class 时&#xff0c;它具有更强的类型安全性和隔离性&#xff0c;因此需要显式转换才能访问其底层整数值。 std::underlying_type_t 是一个类型别名&#xff0c;它返回枚举类型的底层类型。 to_underlying 函数提供了一种方便的方式来执行这种转换&#xff0c;特别…

使用Python和MediaPipe实现手势控制音量(Win/Mac)

1. 依赖库介绍 OpenCV OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它包含了数百个计算机视觉算法。 MediaPipe MediaPipe是一个跨平台的机器学习解决方案库&#xff0c;可以用于实时人类姿势估计、手势识…

kali安装vulhub遇到的问题及解决方法(docker及docker镜像源更换)

kali安装vulhub&#xff1a; 提示&#xff1a;项目地址 https://github.com/vulhub/vulhub 项目安装&#xff1a; git clone https://github.com/vulhub/vulhub.git 安装docker 提示&#xff1a;普通用户请使用sudo&#xff1a; 首先安装 https 协议、CA 证书 apt-get in…

网络安全监控与入侵检测:使用Snort、Suricata等工具进行入侵检测

网络安全监控与入侵检测&#xff1a;使用Snort、Suricata等工具进行入侵检测 随着网络攻击手段的不断演变和升级&#xff0c;企业和个人面临着前所未有的安全挑战。网络安全监控与入侵检测是构建坚不可摧的网络安全防线的重要环节。通过实时监控网络流量和系统活动&#xff0c…

oracle控制文件详解以及新增控制文件

文章目录 oracle控制文件1、 控制文件包含的主要信息如下&#xff1a;2、查看目前系统的控制文件信息&#xff0c;主要是查看相关的字典视图 oracle新增控制文件 oracle控制文件 控制文件是一个很小的二进制文件(10MB左右)&#xff0c;含有数据库结构信息&#xff0c;包括数据…