当前位置:

首页 > 编程开发 > iOS 实现类似抖音滚动效果

iOS 实现类似抖音滚动效果

基于UITableView实现抖音式滚动效果,通过设置contentInet上下各一个屏幕高度作为缓冲,在scrollViewWillEndDragging方法获取手指离开速度,于scrollViewDidEndDragging中根据速度绝对值是否大于0.4决定切换临界偏移量(8或60点),结合手势方向判断上下滑动,最后用UIView动画快速翻页至目标cel

效果图

请添加图片描述

思路

整体思路其实不难——直接拿tableView来撑。为了让内容有足够的缓冲空间,我们把tableView的contentInset设成上下各一个屏幕的高度,左右留0。这样在滚动时,内容其实早就准备好了,不会出现临时加载的尴尬。

滑动效果的实现是重头戏。关键是在scrollViewWillEndDragging方法里拿到手指离开屏幕那一瞬间的速度,然后在scrollViewDidEndDragging方法里通过translationInView判断滑动的方向。

速度这个值怎么用?很简单:当手指离开时的速度绝对值大于0.4,切换页面的临界偏移量就设成8个点;否则就放宽到60个点。方向判断靠translatedPoint.y的正负,正数往上滑,负数往下滑。方向确定之后,直接用UIView animateWithDuration做一个快速翻页动画,效果就出来了。

代码

//
//  ViewController.m
//  LBDouyinScroll
//
//  Created by mac on 2024/6/26.
//
#import "ViewController.h"
#import "DouyinScrollTableViewCell.h"
#define kScreenWidth  [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, assign) NSInteger currentIndex;
@property (nonatomic, assign) CGFloat velocity;
@property (nonatomic, strong) NSMutableArray *colorArray;
@end
@implementation ViewController
- (BOOL)prefersStatusBarHidden
{
    return YES;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.tableView];
    self.colorArray = [NSMutableArray array];
    for (int i = 0; i < 10; i ++) {
        int r = arc4random() % 255;
        int g = arc4random() % 255;
        int b = arc4random() % 255;
        CGFloat rr = r / 255.0;
        CGFloat rg = g / 255.0;
        CGFloat rb = b / 255.0;
        UIColor *color = [[UIColor alloc]initWithRed:rr green:rg blue:rb alpha:1];
        [self.colorArray addObject:color];
    }
    [self.tableView reloadData];
    // Do any additional setup after loading the view.
}
#pragma mark - UITableViewDelegate, UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    DouyinScrollTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([DouyinScrollTableViewCell class])];
    [cell updateWithColor:self.colorArray[indexPath.row]];
    //    cell.textLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row];
    //    cell.backgroundColor = self.colorArray[indexPath.row];
    //    if (!cell.contentView.backgroundColor) {
    //        cell.contentView.backgroundColor = self.colorArray[indexPath.row];
    //    }
    //    return cell;
    return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return kScreenHeight;
}
#pragma mark - scrolllVIewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    self.velocity = velocity.y;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    dispatch_async(dispatch_get_main_queue(), ^{
        CGPoint translatedPoint = [scrollView.panGestureRecognizer translationInView:scrollView];
        //UITableView禁止响应其他滑动手势
        scrollView.panGestureRecognizer.enabled = NO;
        CGFloat translateCheck = 60;
        if (fabs(self.velocity) > 0.4) {
            translateCheck = 8;
        }
        if(translatedPoint.y < -translateCheck && self.currentIndex < 10) {
            self.currentIndex ++;   //向下滑动索引递增
        }
        if(translatedPoint.y > translateCheck && self.currentIndex > 0) {
            self.currentIndex --;   //向上滑动索引递减
        }
        if (self.currentIndex == 10) {
        } else {
            [UIView animateWithDuration:0.15      delay:0.0    options:UIViewAnimationOptionCurveEaseOut animations:^{
                //UITableView滑动到指定cell
                [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.currentIndex inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
            } completion:^(BOOL finished) {
                //UITableView可以响应其他滑动手势
                scrollView.panGestureRecognizer.enabled = YES;
            }];
        }
    });
}
#pragma - private
- (void)animationToIndex:(NSInteger)index
{
    [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
        self.tableView.contentOffset = CGPointMake(0, kScreenHeight * index);
    } completion:^(BOOL finished) {
    }];
}
#pragma mark - lazy load
- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, - kScreenHeight, CGRectGetWidth(self.view.bounds), kScreenHeight * 3) style:UITableViewStylePlain];
        [_tableView registerClass:[DouyinScrollTableViewCell class] forCellReuseIdentifier:NSStringFromClass([DouyinScrollTableViewCell class])];
        _tableView.rowHeight = kScreenHeight;
        _tableView.contentInset = UIEdgeInsetsMake(kScreenHeight , 0, kScreenHeight, 0);
        _tableView.estimatedRowHeight = kScreenHeight;
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.backgroundColor = [UIColor redColor];
        _tableView.contentInsetAdjustmentBeha vior = UIScrollViewContentInsetAdjustmentNever;
        _tableView.separatorInset = UIEdgeInsetsZero;
        _tableView.decelerationRate = UIScrollViewDecelerationRateFast;
    }
    return _tableView;
}
@end

其中最核心的逻辑在于下面这两段袋里方法:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    self.velocity = velocity.y;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    dispatch_async(dispatch_get_main_queue(), ^{
        CGPoint translatedPoint = [scrollView.panGestureRecognizer translationInView:scrollView];
        //UITableView禁止响应其他滑动手势
        scrollView.panGestureRecognizer.enabled = NO;
        CGFloat translateCheck = 60;
        if (fabs(self.velocity) > 0.4) {
            translateCheck = 8;
        }
        if(translatedPoint.y < -translateCheck && self.currentIndex < 10) {
            self.currentIndex ++;   //向下滑动索引递增
        }
        if(translatedPoint.y > translateCheck && self.currentIndex > 0) {
            self.currentIndex --;   //向上滑动索引递减
        }
        if (self.currentIndex == 10) {
        } else {
            [UIView animateWithDuration:0.15      delay:0.0    options:UIViewAnimationOptionCurveEaseOut animations:^{
                //UITableView滑动到指定cell
                [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.currentIndex inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
            } completion:^(BOOL finished) {
                //UITableView可以响应其他滑动手势
                scrollView.panGestureRecognizer.enabled = YES;
            }];
        }
    });
}
本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发 IOS软件
相关文章 更多
C++动态数组初始化怎么写?常用语句与代码示例
C++动态数组初始化怎么写?常用语句与代码示例

深入解析C++中动态数组的初始化机制,涵盖new操作符的不同用法、基本类型与类对象的初始化差异,以及为何在现代C++开发中应优先使用std::vector。

在 iOS 27 的“信息”应用中 苹果新增了一个“绘图”选项
在 iOS 27 的“信息”应用中 苹果新增了一个“绘图”选项

iOS27信息应用新增绘图选项,点击加号图标即可调用,并完整集成标记工具集。macOS27在备忘录和无边记应用中也加入了标记工具。目前两系统处于开发者测试阶段,正式版预计9月推送。

iOS 27全面强化横屏支持,为折叠屏设备铺路
iOS 27全面强化横屏支持,为折叠屏设备铺路

iOS27大幅扩展横屏支持,覆盖设置、相册、邮件等更多系统应用与核心功能,信息应用可折叠侧边栏,实时活动也完美适配横屏,同时优化键盘布局与通知中心显示,旨在为折叠屏等大屏设备优化交互体验与多任务效率。

iOS 27为锁定屏幕带来五大交互与视觉升级 支持AI创作个性化背景
iOS 27为锁定屏幕带来五大交互与视觉升级 支持AI创作个性化背景

iOS27锁屏迎来五大升级:扩展显示自动延展照片边缘;精简时钟模式将时间移至顶部;ImagePlayground支持自然语言生成AI壁纸;LiquidGlass新增透明度滑块,灵活调节视觉层次;Siri交互界面聚焦灵动岛,体验更直观。

苹果今日发布iOS 27首个开发者测试版 意外曝光折叠屏
苹果今日发布iOS 27首个开发者测试版 意外曝光折叠屏

iOS27首个开发者测试版代码中出现折叠状态、折叠角度及屏幕数量查询接口,证实苹果正为折叠屏设备进行系统层适配。该功能消失于iOS26,支撑折叠识别、UI自适应与跨屏调度,预计秋季发布首款折叠屏旗舰机型。

苹果发布超250项更新细节 不止iOS 27系统和AI
苹果发布超250项更新细节 不止iOS 27系统和AI

苹果WWDC2026发布iOS27等五大系统,超250项功能更新,涵盖通信、交互、影像、健康等领域,涉及同号互通、界面优化等。开发者测试版已开放,预计9月正式推送。

苹果iOS 27版Find My升级新增位置共享时长控制及液态玻璃界面设计
苹果iOS 27版Find My升级新增位置共享时长控制及液态玻璃界面设计

iOS27版FindMy新增位置共享时长控制,支持自定义时长或截止日期,并加入静默暂停功能,对方无通知但显示“未找到位置”。界面采用液态玻璃设计,标签栏统一,物品标签换用AirTag风格图标。

苹果发布 iOS 27 更新新增信息应用绘图工具
苹果发布 iOS 27 更新新增信息应用绘图工具

苹果在iOS27和macOS27系统中,为信息应用新增了绘图工具,并将Markup标注功能整合进聊天窗口,支持用户可以在图片和文档上即兴画写标注。此外,macOS27的备忘录和Freeform应用也同步获得该支持,并伴随多项人工智能功能升级。

苹果 iOS 27 改进中文输入更精准的候选词和汉字拆字输入优化
苹果 iOS 27 改进中文输入更精准的候选词和汉字拆字输入优化

iOS27首个Beta版本优化简体中文输入,结合上下文提供更精准候选词,减少选词错误;新增汉字拆字输入功能,输入组成部分拼音即可查找生僻字;同时主动提供标点符号建议,提升日常输入体验。

苹果发布 iOS/iPadOS 26.6 开发者预览版 Beta 2
苹果发布 iOS/iPadOS 26.6 开发者预览版 Beta 2

苹果推送iOS/iPadOS26.6开发者预览版Beta2,版本号23G5043d,距上次发布20天。公开测试版需注册AppleBeta计划后升级,开发者预览版需登录开发者计划后接收推送。

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。