UICollectionView与Dynamic Animator 无脑翻译

2024-01-23 22:48

本文主要是介绍UICollectionView与Dynamic Animator 无脑翻译,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

两者关系

Dynamic AnimatorUICollectionView动画效果实现的主要方式。其主要是通过UICollectionViewFlowLayout强引用UIDynamicAnimator,根据items的行为属性变化来对试图进行更新。
实现原理是UICollectionViewFlowLayoutUICollectionViewLayoutAttributes进行添加behaviors。UIDynamicAnimator根据自身变化来对视图进行刷新。

举个栗子

1)继承一个UICollectionViewFlowLayout类并实现代理方法

@implementation ASHCollectionViewController
static NSString * CellIdentifier = @"CellIdentifier";
-(void)viewDidLoad 
{
[super viewDidLoad];
[self.collectionView registerClass:[UICollectionViewCell class] 
forCellWithReuseIdentifier:CellIdentifier];
}
-(UIStatusBarStyle)preferredStatusBarStyle 
{
return UIStatusBarStyleLightContent;
}
-(void)viewDidAppear:(BOOL)animated 
{
[super viewDidAppear:animated];
[self.collectionViewLayout invalidateLayout];
}
#pragma mark - UICollectionView Methods
-(NSInteger)collectionView:(UICollectionView *)collectionView 
numberOfItemsInSection:(NSInteger)section 
{
return 120;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{
UICollectionViewCell *cell = [collectionView 
dequeueReusableCellWithReuseIdentifier:CellIdentifier 
forIndexPath:indexPath];
cell.backgroundColor = [UIColor orangeColor];
return cell;
}
@end

这里有个槽点是
[self.collectionViewLayout invalidateLayout]; 若是使用SB的话要的视图出现时候invalidate一下。

2)创建带UIDynamicAnimatorUICollectionViewFlowLayout子类并初始化

@interface ASHSpringyCollectionViewFlowLayout ()
@property (nonatomic, strong) UIDynamicAnimator *dynamicAnimator;
@end
- (id)init 
{
if (!(self = [super init])) return nil;
self.minimumInteritemSpacing = 10;
self.minimumLineSpacing = 10;
self.itemSize = CGSizeMake(44, 44);
self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self];
return self;
}

通过父类的prepareLayout的方法可以获取指定区域范围的属性。

[super prepareLayout];
CGSize contentSize = self.collectionView.contentSize;
NSArray *items = [super layoutAttributesForElementsInRect:
CGRectMake(0.0f, 0.0f, contentSize.width, contentSize.height)];

确认添加animator类的条件是否准备就绪,这里要注意animator不能被重复添加,否则运行时会报错。确定以后就是一轮迭代对每一个item添加behavior类

if (self.dynamicAnimator.behaviors.count == 0) {
[items enumerateObjectsUsingBlock:^(id<UIDynamicItem> obj, NSUInteger idx, BOOL *stop) {
UIAttachmentBehavior *behaviour = [[UIAttachmentBehavior alloc] initWithItem:obj 
attachedToAnchor:[obj center]];
behaviour.length = 0.0f;
behaviour.damping = 0.8f;
behaviour.frequency = 1.0f;
[self.dynamicAnimator addBehavior:behaviour];
}];
}

通过layoutAttributesForElementsInRect:layoutAttributesForItemAtIndexPath:两个方法来时时获取animator的状态:

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 
{
return [self.dynamicAnimator itemsInRect:rect];
}
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 
{
return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath];
}

3)滑动事件响应
做到动态调整,我们需要使layout与dynamic animator根据滑动的视图位置来做出反应。对应的方法是shouldInvalidateLayoutForBoundsChange:。这个方法提供了更新已发生变更behaviors的item的时机。更新完,方法返回NO(无需再更新)。

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 
{
UIScrollView *scrollView = self.collectionView;
CGFloat delta = newBounds.origin.y - scrollView.bounds.origin.y;
CGPoint touchLocation = [self.collectionView.panGestureRecognizer locationInView:self.collectionView];
[self.dynamicAnimator.behaviors enumerateObjectsUsingBlock:^(UIAttachmentBehavior *springBehaviour, NSUInteger idx, BOOL *stop) {
CGFloat yDistanceFromTouch = fabsf(touchLocation.y - springBehaviour.anchorPoint.y);
CGFloat xDistanceFromTouch = fabsf(touchLocation.x - springBehaviour.anchorPoint.x);
CGFloat scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / 1500.0f;
UICollectionViewLayoutAttributes *item = springBehaviour.items.firstObject;
CGPoint center = item.center;
if (delta < 0) {
center.y += MAX(delta, delta*scrollResistance);
}
else {
center.y += MIN(delta, delta*scrollResistance);
}
item.center = center;
[self.dynamicAnimator updateItemUsingCurrentState:item];
}];
return NO;
}

在滑动事件中,首先我要计算出滑动方向垂直方向的分量变化值:deltaY(这里以垂直滑动作为栗子)。其实是获取用户手指在屏幕的位置信息。如果我们想时时根据用户操作做出响应上述两个值至关重要。

4)新增行
新增行带来的问题是我们需要动态的为新增行得animator添加behaviors。
so我们需要一个刷新Layout的接口:

@interface ASHSpringyCollectionViewFlowLayout : UICollectionViewFlowLayout
- (void)resetLayout;
@end
- (void)resetLayout {
[self.dynamicAnimator removeAllBehaviors];
[self prepareLayout];
}

之后我们只要在每次重新加载数据源刷新视图之后调用一次该接口就可以了!

[self.collectionView reloadData];
[(ASHSpringyCollectionViewFlowLayout *)[self collectionViewLayout] resetLayout];

上述实现为原生,并无考虑性能优化。想一步做一步而已。

4)使Dynamic Behaviors Tiling化从而提升性能
上述的代码在小数据量(数百cell)还是可以应付的,但是当运行时数据量过大的时候可能就要挂了。

OK,那么要解决这个问题切入时间点在于在item出现或者即将出现得时候。这是我们需要处理的地方。而我们需要做的处理是保存所有展示并正在动画的items的indexpath。即添加一个属性来做保存。

@property (nonatomic, strong) NSMutableSet *visibleIndexPathsSet;

注:用set的原因是其查找跟判断的时间消耗为O(N),这里需要大量的查找跟判断。

再重写我们的prepareLayout方法之前我们要明确啥是tiling化。简而言之就是在cell出屏幕边界的时候移除behaviors在进入屏幕内的时候添加behaviors。难点在于在我们新建一个behaviors时候要够轻量级。这意味着我们需要在用dynamic animator创建以及shouldInvalidateLayoutForBoundsChange: 方法配置之后再次更改一次。
此外为了保证轻量级behaviors我们还需要保存当前边界滑动的delta值:

@property (nonatomic, assign) CGFloat latestDelta;

同时,我们还需要在shouldInvalidateLayoutForBoundsChange:添加代码

self.latestDelta = delta;

而用来查询当前排版的两函数layoutAttributesForElementsInRect:layoutAttributesForItemAtIndexPath:无需变动。

现在最复杂的莫过于tiling机制。我们需要重写prepareLayout

首先我们要移除屏幕之外items的behaviors,接着我们需要往屏幕新出现的items添加behaviors。先来看第一步。

首先还是需要调用 [super prepareLayout] 来获取排版信息,不同的是不再加载整个View的排版信息而是屏幕可见区域items的排版信息。

请注意由于可能会快速的滑动,so我们要稍微的扩大可见区域的范围。不然将造成动画不连贯(闪烁)。

CGRect originalRect = (CGRect){.origin = self.collectionView.bounds.origin, .size = self.collectionView.frame.size};
CGRect visibleRect = CGRectInset(originalRect, -100, -100);    

这里对上对下扩展的100要根据cell大小来定制哦。cell太大就操蛋了。。。

然后就是计算可见区域内得index paths了:

NSArray *itemsInVisibleRectArray = [super layoutAttributesForElementsInRect:visibleRect];
NSSet *itemsIndexPathsInVisibleRectSet = [NSSet setWithArray:[itemsInVisibleRectArray valueForKey:@"indexPath"]];

找到index paths集合后紧接着我们要从这个集合中干掉那些已移除屏幕items中animatorbehaviours(从visibleIndexPathsSet)。

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(UIAttachmentBehavior *behaviour, NSDictionary *bindings) {
BOOL currentlyVisible = [itemsIndexPathsInVisibleRectSet member:[[[behaviour items] firstObject] indexPath]] != nil;
return !currentlyVisible;
}]
NSArray *noLongerVisibleBehaviours = [self.dynamicAnimator.behaviors filteredArrayUsingPredicate:predicate];
[noLongerVisibleBehaviours enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
[self.dynamicAnimator removeBehavior:obj];
[self.visibleIndexPathsSet removeObject:[[[obj items] firstObject] indexPath]];
}];

第二步是计算出即将可见的index paths集合
(从itemsIndexPathsInVisibleRectSet

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes *item, NSDictionary *bindings) {
BOOL currentlyVisible = [self.visibleIndexPathsSet member:item.indexPath] != nil;
return !currentlyVisible;
}];
NSArray *newlyVisibleItems = [itemsInVisibleRectArray filteredArrayUsingPredicate:predicate];

这篇关于UICollectionView与Dynamic Animator 无脑翻译的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/637764

相关文章

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey

Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs),如GPT-4、Claude-3和Gemini的快

论文翻译:ICLR-2024 PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS

PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS https://openreview.net/forum?id=KS8mIvetg2 验证测试集污染在黑盒语言模型中 文章目录 验证测试集污染在黑盒语言模型中摘要1 引言 摘要 大型语言模型是在大量互联网数据上训练的,这引发了人们的担忧和猜测,即它们可能已

excel翻译软件有哪些?如何高效提翻译?

你是否曾在面对满屏的英文Excel表格时感到头疼?项目报告、数据分析、财务报表... 当这些重要的信息被语言壁垒阻挡时,效率和理解度都会大打折扣。别担心,只需3分钟,我将带你轻松解锁excel翻译成中文的秘籍。 无论是职场新人还是老手,这一技巧都将是你的得力助手,让你在信息的海洋中畅游无阻。 方法一:使用同声传译王软件 同声传译王是一款专业的翻译软件,它支持多种语言翻译,可以excel

MonoHuman: Animatable Human Neural Field from Monocular Video 翻译

MonoHuman:来自单目视频的可动画人类神经场 摘要。利用自由视图控制来动画化虚拟化身对于诸如虚拟现实和数字娱乐之类的各种应用来说是至关重要的。已有的研究试图利用神经辐射场(NeRF)的表征能力从单目视频中重建人体。最近的工作提出将变形网络移植到NeRF中,以进一步模拟人类神经场的动力学,从而动画化逼真的人类运动。然而,这种流水线要么依赖于姿态相关的表示,要么由于帧无关的优化而缺乏运动一致性

linux dlopen手册翻译

名称 dlclose, dlopen, dlmopen 打开和关闭一个共享对象 简介 #include <dlfcn.h>void *dlopen(const char*filename, int flags);int dlclose(void *handle);#define _GNU_SOURCE#include <dlfcn.h>void *dlmoopen(Lmid_t lm

从计组中从重温C中浮点数表示及C程序翻译过程

目录 移码​编辑  传统浮点表示格式 浮点数的存储(ieee 754)->修炼内功 例子:   ​编辑 浮点数取的过程   C程序翻译过程 移码  传统浮点表示格式 浮点数的存储(ieee 754)->修炼内功 根据国际标准IEEE(电⽓和电⼦⼯程协会)  32位 例子:    64位    IEEE754对有效数字M和

论文精读-Supervised Raw Video Denoising with a Benchmark Dataset on Dynamic Scenes

论文精读-Supervised Raw Video Denoising with a Benchmark Dataset on Dynamic Scenes 优势 1、构建了一个用于监督原始视频去噪的基准数据集。为了多次捕捉瞬间,我们手动为对象s创建运动。在高ISO模式下捕获每一时刻的噪声帧,并通过对多个噪声帧进行平均得到相应的干净帧。 2、有效的原始视频去噪网络(RViDeNet),通过探

HumanNeRF:Free-viewpoint Rendering of Moving People from Monocular Video 翻译

HumanNeRF:单目视频中运动人物的自由视点绘制 引言。我们介绍了一种自由视点渲染方法- HumanNeRF -它适用于一个给定的单眼视频ofa人类执行复杂的身体运动,例如,从YouTube的视频。我们的方法可以在任何帧暂停视频,并从任意新的摄像机视点或甚至针对该特定帧和身体姿势的完整360度摄像机路径渲染主体。这项任务特别具有挑战性,因为它需要合成身体的照片级真实感细节,如从输入视频中可能

深度评测热门翻译工具,携手你的翻译得力助手

随着互联网技术的飞速发展,全球化交流日益频繁,跨语言沟通的需求也随之激增。对于外语水平有限的朋友来说,翻译器是一个必不可少的工具。今天我就分享几款我用的翻译器吧。 1.福晰在线翻译  链接直达>>https://fanyi.pdf365.cn/doc  该网站以其高度的专业性著称,专为翻译需求而精心打造。它不仅支持用户粘贴部分文字进行即时翻译,更贴心地提供了整份PDF文档的导入翻译功能,极大

idea中配置Translation插件完成翻译功能

文章目录 idea下载插件配置有道云阿里云百度翻译开放平台 idea下载插件 idea中安装Translation插件 使用方法:右下角选择翻译引擎,鼠标选中想翻译的部分,右键翻译即可 之前一直用的微软的翻译,不需要配置,但是最近微软服务器总是抽风,无法使用,故打算配置一下国内的翻译服务。 配置 有道云 只有初始的一点额度,用完就要收费了,不推荐