Ios 镜像UIWebView的最佳方式
我需要将UIWebView的CALayer镜像到较小的CALayer。较小的CALayer本质上是较大的UIWebView的一个pip。我做这件事有困难。唯一接近的是CAReplicatorLayer,但鉴于原件和副本必须以CAReplicatorLayer为父级,我无法在不同屏幕上拆分原件和副本 我试图做的一个例子: 用户需要能够与较小的CALayer交互,并且两者都需要同步 我尝试过使用RenderContext和CADisplayLink来实现这一点。不幸的是,有一些延迟/口吃,因为它试图重新绘制每一帧,每秒60次。我需要一种方法来进行镜像,而无需在每个帧上重新绘制,除非实际发生了更改。因此,我需要一种方法来知道炉匠(或儿童炉匠)何时变脏 我不能简单地拥有两个UIWebView,因为两个页面可能不同(定时关闭、背景不同等等)。我无法控制正在显示的网页。我也不能显示整个iPad屏幕,因为屏幕上还有其他不应该显示在外部屏幕上的元素 在iOS 6中,较大的CALayer和较小的“pip”CALayer都需要平滑地匹配帧对帧。我不需要支持早期版本Ios 镜像UIWebView的最佳方式,ios,uiwebview,calayer,cadisplaylink,Ios,Uiwebview,Calayer,Cadisplaylink,我需要将UIWebView的CALayer镜像到较小的CALayer。较小的CALayer本质上是较大的UIWebView的一个pip。我做这件事有困难。唯一接近的是CAReplicatorLayer,但鉴于原件和副本必须以CAReplicatorLayer为父级,我无法在不同屏幕上拆分原件和副本 我试图做的一个例子: 用户需要能够与较小的CALayer交互,并且两者都需要同步 我尝试过使用RenderContext和CADisplayLink来实现这一点。不幸的是,有一些延迟/口吃,因为它试
解决方案必须是AppStore可接受的。我认为您使用CADisplayLink的想法很好。主要的问题是你试图刷新每一帧。您可以使用
frameInterval
属性自动降低帧速率。或者,您可以使用timestamp
属性了解上次更新发生的时间
另一个可能有效的选项是:要知道图层是否脏,为什么不让一个对象作为所有图层的代理,每当每个图层需要绘制时,都会触发它的
drawLayer:inContext:
?然后只需相应地更新其他图层。如注释中所述,如果主要需要知道何时更新图层(而不是如何更新),我将原始答案移动到“旧答案”行后,并添加注释中讨论的内容:
第一(100%苹果审查安全;-)
- 您可以定期拍摄原始UIView的“屏幕截图”,并比较生成的NSData(旧数据和新数据)->如果数据不同,则图层内容会发生更改。不需要比较全分辨率的屏幕截图,但您可以使用较小的屏幕截图,以获得更好的性能
- 在该链接中,您可以找到一个示例项目,每当UIWebView层变脏时,该项目都会向您发出警报;-)李>
// here you start a timer, 50fps
// the timer is started on a background thread to avoid blocking it when you scroll the webview
- (IBAction)enableMirror:(id)sender {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); //0ul --> unsigned long
dispatch_async(queue, ^{
// 0.04f --> 25 fps
NSTimer __unused *timer = [NSTimer scheduledTimerWithTimeInterval:0.02f target:self selector:@selector(copyImageIfNeeded) userInfo:nil repeats:YES];
// need to start a run loop otherwise the thread stops
CFRunLoopRun();
});
}
// this method create an UIImage with the content of the given view
- (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
// the method called by the timer
-(void)copyImageIfNeeded
{
// this method is called from a background thread, so the code before the dispatch is executed in background
UIImage *newImage = [self imageWithView:self.webView];
// the copy is made only if the two images are really different (compared byte to byte)
// this comparison method is cpu intensive
// UNCOMMENT THE IF AND THE {} to enable the frame comparison
//if (!([self image:self.mirrorView.image isEqualTo:newImage]))
//{
// this must be called on the main queue because it updates the user interface
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
self.mirrorView.image = newImage;
});
//}
}
// method to compare the two images - not performance friendly
// it can be optimized, because you can "store" the old image and avoid
// converting it more and more...until it's changed
// you can even try to generate the nsdata in background when the frame
// is created?
- (BOOL)image:(UIImage *)image1 isEqualTo:(UIImage *)image2
{
NSData *data1 = UIImagePNGRepresentation(image1);
NSData *data2 = UIImagePNGRepresentation(image2);
return [data1 isEqual:data2];
}