我有一个自定义地图视图,由一个UIScrollView.滚动视图的子视图由a支持CATiledLayer.这里的一切都很棒.平移和缩放会加载新的地图图块,一切运行良好.
我想要做的是将动画视频帧捕获到此滚动视图.基本上,我想创建一个动画更改滚动视图contentOffset和视频的视频zoomScale.
我知道这个概念是合理的,因为我可以获得私有API函数UIGetScreenImage()来捕获应用程序的屏幕,例如10fps,组合这些图像,我得到平滑的回放动画,并具有滚动视图动画使用的时序曲线.
我的问题当然是我无法使用私有API.通过苹果列出的备选方案会在这里给我留下了非常按说一个有效的选项:问一个CALayer来renderInContext,并采取了UIGraphicsGetImageFromCurrentImageContext()从.
但这似乎与CATiledLayer-backed视图无关.捕获的是块状,未缩放的图像,就好像较高分辨率的图块永远不会加载一样.这有点合理,因为CATiledLayer在后台线程中引入性能并且renderInContext从主线程调用可能无法捕获这些更新.即使我也渲染了平铺图层,结果也是相似的presentationLayer.
是否有Apple认可的方式CATiledLayer在包含滚动视图的动画过程中捕获背景视图的图像?或者在任何时候,就此而言?
当父UIScrollView放大时,我在CATiledLayer上遇到重绘问题.
我在CATiledLayer支持的UIView中呈现PDF页面.它后面还有另一个UIImageView,它包含了CATiledLayer将绘制的页面的低分辨率图像.当我放大时,它按预期工作.CATiledLayer将根据缩放级别渲染更高分辨率的图像.
缩放后会出现此问题.如果我放大然后只留下iPad,显示的图像会模糊然后重新加强.看起来像CATiledLayer被删除,因为我在后备视图中看到模糊的低分辨率图像,然后重新绘制了CATiledLayer,即我看到了平铺效果和图像的重新锐化.如果我只是单独离开应用程序并等待大约30到40秒,就会发生这种情况.我只是在iPad第三代(新iPad,iPad3等)上观察过它.我也在iPad2上测试,我还没有遇到这个问题.
还有其他人遇到过这个问题吗?任何已知的原因,可能还有解决方案?
编辑:
我的UIScrollViewDelegate方法如下:
// currentPage, previousPage, and nextPage are the pdf page views
// that are having the refresh problem
- (void)positionBufferedPages {
// performs math {code omitted}
// then sets the center of the views
[previousPage.view setCenter:...];
[nextPage.view setCenter:...];
}
- (void)hideBufferedPages {
if ([previousPage.view isDescendantOfView:scrollView]) {
[previousPage.view removeFromSuperview];
}
if ([nextPage.view isDescendantOfView:scrollView]) {
[nextPage.view removeFromSuperview];
}
}
- (void)showBufferedPages {
if (![previousPage.view isDescendantOfView:scrollView]) {
[scrollView addSubview:previousPage.view];
}
if (![nextPage.view isDescendantOfView:scrollView]) {
[scrollView addSubview:nextPage.view];
}
if …Run Code Online (Sandbox Code Playgroud) 我必须在iOS5/6(iPhone)上实现一个非常自定义的平铺地图图层/视图,它将图块作为图像和/或数据(JSON)从服务器加载.它就像谷歌地图,但在某些非常具体的点,所以我不能轻易使用如下的解决方案:
CATiledLayer 与...结合 UIScrollView问题是:由于我的特定规格,没有一个解决方案确实对我有所帮助.如果你认为,有一个合适的解决方案,请告诉我!
如果没有:
帮我找到最适合我案例的解决方案!
"但为什么我不能使用这些漂亮的解决方案?"
有一些限制,必须知道:
我们只使用3个缩放级别(0,1和2)
每个瓷砖在下一个缩放级别(=缩放因子3)中有9个子弹(不像大多数其他套件中的4个子弹 = zoomfactor 2)
第一层的初始大小为(以像素为单位/点为一半)768*1024.
第二层宽三倍(zoomfactor 3 !!!) - > 2304*3072
第三层同样宽,高于第二层 - > 6912*9216
来自服务器的每个磁贴都是256x256像素
所以每个子层的数量是瓷砖数量的9倍(第一层为12,第二层为108,第三层为972)
每个磁贴都有一个背景图像(大小约为6KB)(从服务器加载为图像)和前景信息(从服务器加载每个磁贴的JSON - 大小为10-15KB)
- >前景信息JSON包含覆盖图像(例如谷歌中的流量)或要绘制到局部切片坐标空间的局部切片信息(如注释,但每个切片)
我想将整个背景磁贴缓存在磁盘上,因为它们永远不会改变
要么我想在一定时间内缓存每个图块的overlay-tile-images/overlay-tile-information,直到它应该再次重新加载
缩放应该是捏合和双击
我的一些考虑因素:
缓存不是问题.我通过CoreData或类似的方式做到这一点
我想到了一个UIScrollView,以显示平滑的滚动
我想使用捏,所以每次突破下一个缩放级别时,我都必须绘制下一个缩放级别的瓷砖
内容应该只在可见区域绘制(对我来说,在iPhone 5 320x500上)
应删除不可见的切片,以提高内存效率.但是,不应该立即删除它们,只有当一块瓷砖远离可见中心的一定像素/点时才会被删除.应该有一个"显示缓存",即时显示瓷砖,只是加载和显示.或者那里有更好的技术吗?
我可以异步地从磁盘或服务器加载背景,因为我知道哪些图块是可见的.我也是使用tile-JSON.然后我提取瓷砖的JSON信息("覆盖直接图像或信息,如城市名称,我必须将其绘制到瓷砖中")并绘制或加载覆盖(从DB /光盘或服务器)
UIScrollView是否足够高效以处理平铺视图的最大大小
我应该使用CALayer作为子图层来绘制吗?我应该使用Quartz直接在大画布上画画吗?
在Android上,我在水平滚动列表上有可能有大宽度的项目视图.当视图的某些部分在列表中可见时,视图会加载并绘制块"图像".这是一种优化,以避免一次性绘制所有图像,因为它会浪费和缓慢.绘制的内容基本上是音频波形.做事情需要工作我不能将块拆分为列表中的单个视图项.由于android绘图架构的工作原理,这种策略非常有效.
现在我试图在iOS中使用类似的模式,但是我遇到了一些麻烦,我不太确定如何提出解决方案.
在iOS中,我正在使用UICollectionView绘制大宽度单元格的数据,我们需要同样优化加载和绘制可见的块.
解决方案1:
检查UIView可见的部分,并仅绘制那些可见的块.这个解决方案的问题在于,作为UICollectionView卷轴,UIView不会绘制下一个可见的卡盘.以下是我所谈论的例子.
滚动
显示黑色显示并且没有加载任何内容,因为没有提示视图需要再次绘制,因此我们无法加载下一个可见的块.

解决方案2:
使用UIView由a支持的自定义CATiledLayer.这非常有效,因为它会在滚动时绘制出可见的图块UICollectionView.
问题是如果shouldDrawOnMainThread定义了在后台线程或下一个绘图周期中进行绘制.这会在UIView调整大小或内部缩放逻辑启动时出现问题.由于绘图周期未与视图大小调整同步,因此事情发生了变化.
那么我怎么能得到通知,就像CATiledLayer一个部分变得可见,我可以正常画像一个CALayer支持UIView?
更新1
我正在考虑使用preferredLayoutAttributesFittingAttributes一种方法来检查是否需要绘制新的块.每次由于滚动而将单元格移动到新位置时都会调用此方法.希望这不是一个坏主意.:)
- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
Run Code Online (Sandbox Code Playgroud)
更新2
经过多次测试和玩耍.使用解决方案1不是一种选择.当UIView达到一个巨大的宽度时内存使用率下降,而使用CATiledLayer内存使用量是最小的,因为我猜想人们会期望.:/
当我的CATConLayer检索要在后台线程中绘制的图像时,我的应用程序在我的ViewController被取消分配时崩溃了.我收到一条消息
-[MyViewController respondsToSelector:]: message sent to deallocated instance 0x8f58e00
Run Code Online (Sandbox Code Playgroud)
并且调试器显示
0 ___forwarding___
1 __forwarding_prep_0__
2 -[CATiledLayer(CATiledLayerPrivate) canDrawRect:levelOfDetail:]
3 tiled_layer_render
4 CAImageProviderThread
5 CAImageProviderBackgroundThread
6 CA::DispatchGroup::thread
7 thread_fun
8 _pthread_start
Run Code Online (Sandbox Code Playgroud)
现在,我确实想要发布MyViewController的某个实例,因为我不再需要它了.但是当它从后台线程返回时如何阻止它崩溃?
我今天遇到了一个涉及CATiledLayer的有趣的iOS问题.这只发生在设备上 - 而不是在模拟器中.
我的视图通过drawLayer:inContext:delegate callback在其CALayer中绘制.该图层具有CATiledLayer派生的子图层,该图层在重写的drawInContext:方法中执行自己的绘图.
这两个层都通过CGContextDrawPDFPage()呈现pdf内容.(CALayer绘制低分辨率版本,而CATiledLayer子层在顶部绘制高分辨率内容.)
我遇到了一个我将完成视图的场景 - 将其从超级视图中删除并释放它.在视图上调用dealloc().稍后,系统将调用CATiledLayer的drawInContext:方法(在后台线程上).它会绘制,但是从方法返回时,Springboard会崩溃,并且在这样做时,也会关闭我的应用程序.
我通过在视图的dealloc方法中在CATiledLayer中设置一个标志来修复它,告诉它不再渲染.
但我只能想象有一种更优雅的方式.为什么仍然在父图层之后调用CATiledLayer drawInContext:方法,并且父图层的视图被解除分配?关闭视图的正确方法是什么,以免发生这种情况?
我的观点有一个CATiledLayer.视图控制器具有自定义缩放行为,因此-scrollViewDidEndZooming需要重新绘制每个图块.但是,即使-setNeedsDisplay在每次缩放后在图层上调用,也不是所有的图块都被重绘.这导致视图在缩放后有时看起来有问题.(应该只出现在1个图块中的东西出现在多个地方).它经常在另一次变焦后自行修正.
这是相关的代码.updatedRects用于测试 - 它存储请求绘制的唯一矩形-drawLayer.
CanvasView.h:
@interface CanvasView : UIView
@property (nonatomic, retain) NSMutableSet *updatedRects;
@end
Run Code Online (Sandbox Code Playgroud)
CanvasView.m:
@implementation CanvasView
@synthesize updatedRects;
+ (Class)layerClass
{
return [CATiledLayer class];
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
CGRect rect = CGContextGetClipBoundingBox(context);
[updatedRects addObject:[NSValue valueWithCGRect:rect]];
CGContextSaveGState(context);
CGContextTranslateCTM(context, rect.origin.x, rect.origin.y);
// ...draw into context...
CGContextRestoreGState(context);
}
@end
Run Code Online (Sandbox Code Playgroud)
MyViewController.m:
@implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
canvasView.updatedRects = [NSMutableSet set];
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{ …Run Code Online (Sandbox Code Playgroud) 我有一个大约7000x6000px的图像.我需要这个在我的应用程序中的scrollview/imageView,但这是显示的巨大的方式.它应该是一种地图.我希望将应用程序的大小保持在最小,并且图像大约为13mb(以.jpg为单位).在.png中它超过100mb,这是不可接受的.许多人建议CATiledLayer作为一种选择,但我相信这会导致更大的文件大小.无论如何,我试着用它做CATiledLayer,并在TileCutter中创建我自己的瓷砖((.jpg中的瓷砖),尺寸也不算太差.但我到处都有错误.iOS版本CATiledLayer对我来说是一个谜,我找不到解决这个问题的方法.我得到一个错误说一些关于java等价的"索引超出数组的范围",即使该数组具有该特定索引的内容..它有一个返回数组的方法.该数组包含.plist的数据.在返回之前,我注销了数组的内容,给了我很好的数据.电话正试图访问
[array objectAtIndex:0]
并把它放在字典中,但抛出OutOfBounds.当注销整个阵列时,我可以清楚地看到内容,但是在注销时
NSLog("%@",[method objectAtIndex]); I get the same exception.
Run Code Online (Sandbox Code Playgroud)
无论如何,CATiledLayer除了问题,我什么都没给.我一直在对PhotoScroller项目进行逆向工程而没有运气.有没有其他解决方案?
谢谢.
我有一个适用于 iPad 的 pdf 阅读器应用程序,我使用滚动视图来显示每个页面。我将页面保持在视图中,并在页面的任一侧查看一页。我有纵向和横向视图的单独视图。纵向视图显示单个页面,横向查看器显示 2 个页面。
当 iPad 改变方向时,我卸载旧方向的视图并加载新方向的视图。因此,假设它处于纵向视图,然后更改为横向,应用程序会卸载纵向视图并加载横向视图。这一切都很好,除非 pdf 很大。
pdf 是使用 tiledlayers 绘制的。当使用大 pdf 更改方向时,应用程序会崩溃。如果在所有图块绘制之前更改方向,应用程序只会崩溃。我的猜测是它正在崩溃,因为它试图将瓷砖绘制到一个视图而不是已卸载的视图。那么有没有办法在我卸载视图时停止绘制瓷砖?
我创建了新的单视图应用程序(使用iOS 5 sdk和Xcode 4.2进行开发),该应用程序现在由app delegate,视图控制器,scrollView(带CATiledLayer)组成.故事板包含ViewController包含UIScrollView哪些类是ScrollView(我已经创建的类).我的目标是显示大型PDF文件,缩放等.我的项目基于从苹果缩放pdf样本.当我尝试在iPad上运行我的应用程序时,它会在链接期间崩溃,显示我的错误:
Undefined symbols for architecture armv7:
"_OBJC_CLASS_$_CATiledLayer", referenced from:
objc-class-ref in TiledPDFPage.o
Run Code Online (Sandbox Code Playgroud)
所以有谁知道,如何避免这个错误?是否有可能问题在于我没有在代码中创建scrollView但在故事板中?
在我的应用程序中,我使用了以下视图层次结构:
UIView
----UIScrollView
--------TiledView (UIView subclass, uses CATiledLayer for drawing)
----OverlayView (UIView subclass)
Run Code Online (Sandbox Code Playgroud)
简而言之 - TiledView显示大平铺图像我也将自定义旋转应用于该视图:
tiledView.transform = CGAffineTransformMakeRotation(angle);
Run Code Online (Sandbox Code Playgroud)
TiledView的绘图方法:
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
...
NSString *fileName = [NSString stringWithFormat:@"tile_%d_%d.jpg", y + 1, x + 1];
UIImage *image = [UIImage imageNamed:fileName];
[image drawInRect:rect];
}
Run Code Online (Sandbox Code Playgroud)
UIScrollView允许滚动和缩放其内容.
叠加视图覆盖UIScrollView,具有透明背景并执行一些自定义绘图.我使用单独的视图来确保线条宽度和字体大小不受滚动视图中缩放比例的影响.
OverlayView的绘图方法:
- (void)drawRect:(CGRect)rect {
// Drawing code
[super drawRect:rect];
// Custom drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 0, 1);
CGContextSetLineWidth(context, lineWidth);
CGContextBeginPath(context);
CGContextMoveToPoint(context, (int)startPoint.x,(int) …Run Code Online (Sandbox Code Playgroud) 我使用CATiledLayer作为我的UIView的支持层,我把它放在UIScrollView中.在我的视图的init方法中,我正在创建绘制简单线条的CGPathRef对象.当我尝试在drawLayer:inContext中绘制此路径时,当我滚动/缩放时,它偶尔会与EXEC_BAD_ACCESS(很少)崩溃.
代码很简单,我只使用标准的CG*函数:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
tiledLayer.levelsOfDetail = 10;
tiledLayer.levelsOfDetailBias = 5;
tiledLayer.tileSize = CGSizeMake(512.0, 512.0);
CGMutablePathRef mutablePath = CGPathCreateMutable();
CGPathMoveToPoint(mutablePath, nil, 0, 0);
CGPathAddLineToPoint(mutablePath, nil, 700, 700);
path = CGPathCreateCopy(mutablePath);
CGPathRelease(mutablePath);
}
return self;
}
+ (Class) layerClass {
return [CATiledLayer class];
}
- (void) drawRect:(CGRect)rect {
}
- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
CGContextFillRect(ctx, self.bounds);
CGContextSetLineWidth(ctx, 5);
CGContextAddPath(ctx, path);
CGContextDrawPath(ctx, kCGPathStroke); …Run Code Online (Sandbox Code Playgroud) catiledlayer ×12
ios ×8
ipad ×4
calayer ×3
iphone ×3
objective-c ×3
cocoa-touch ×2
uiscrollview ×2
uiview ×2
cgpath ×1
crash ×1
drawing ×1
ios5 ×1
linker ×1
maps ×1
pdf ×1
storyboard ×1