Snapchat更新状态栏iOS7更新



在snapchat的最新更新中,当你"向右滑动查看消息"时,状态栏会以一种渐变的方式从黑色变成白色。

https://i.stack.imgur.com/4OlRg.jpg

他们如何在不使用私有API的情况下做到这一点,或者他们使用私有API吗?

我查到了什么:

乍一看,我以为他们只是在做其他人做的事情,(就像radio目前所做的那样)通过屏幕捕获整个屏幕,然后修改/动画该屏幕。

但是…你不能从那个屏幕捕获方法访问或动画UIImage,所以尽管你可以移动/裁剪那个屏幕截图,你不能改变它的外观。

所以…我对它进行了测试,当状态栏处于这种状态(半黑半白)时,它仍然是LIVE,因为它不是截图,并且它响应收费变化/信号变化等,据我所知,如果不使用私有API,这是不可能的。

这让我很好奇,所以我玩了一下这个应用程序,并在越狱设备上使用Spark Inspector检查了应用程序的视图层次结构,我发现了一些事情。

关于他们没有使用截图,你是不正确的。你正在离开的那一边的状态栏是一个快照,不会改变。当一分钟过去时,你可以很容易地看到,你正在过渡到的视图的新状态栏会发生变化,因为它是真实的,但旧的状态栏不会,因为它是快照。这使得错觉很容易解决。

下面是高层发生的事情:

  1. 当你开始转换时,应用程序在当前状态下拍摄状态栏的快照(很可能它实际上是拍摄整个UIScreen的快照,并简单地将状态栏从它中裁剪出来),并在转换中将包含该快照的窗口附加到视图的顶部,锚定到最终转换位置并被"from"视图控制器的视图掩盖。这个窗口看起来在UIWindowLevelStatusBar之上有一个windowLevel,所以它能够覆盖真正的状态栏。

  2. 然后,"to"视图控制器接管实际状态栏并将其更改为"light content"状态。这给人一种巧妙的错觉,即单个状态栏会随着过渡边框改变颜色,但真正的状态栏实际上总是位于快照窗口下方,如果不是快照窗口位于其上方,在过渡开始时确实会立即可见。

在Dima回答的基础上,我认为一些基本的实现可以帮助人们开始。正如Dima所说,它不是移动状态栏,而是移动状态栏的图像。

免责声明:我YOLO这个实现,所以我不保证它是否可以开箱工作

从iOS7开始,你可以使用

拍照
UIView *screen = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];

所以基本上状态栏是从图片中裁剪出来的,并添加到UIWindow中,windowLevelUIWindowStatusLevelBar之上,所以你可以在真实的状态栏上看到它。比如:

UIWindow *statusBarWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
statusBarWindow.windowLevel = UIWindowLevelStatusBar + 1; // higher
statusBarWindow.hidden = NO; // fun fact you don't have to add a UIWindow to anything, just setting hidden = NO should display it
statusBarWindow.backgroundColor = [UIColor clearColor]; // since visible, make it clear until we actually add the screen shot to it so as to not block anything 
...
// The view that will hold the screen shot
// Later, I think we're going to need to play with contentInsets to make the view look like its staying still, so we're making it a UIScrollView in case
UIScrollView *statusBarView = [[UIScrollView alloc] initWithFrame:[UIApplication sharedApplication].statusBarFrame];
statusBarView.clipsToBounds = YES;
// Now we add the screen shot we took to this status bar view
[scrollingStatusBarView addSubview:statusBarView];
[statusBarView addSubview:screen]; // screen is the UIScrollView from previous code block (the screen shot)
// Now add this statusBarView with the image to the window we created
[statusBarWindow addSubview:statusBarView];

现在剩下的就取决于你的实现是什么样子了但是从这里开始你只需要处理移动视图用平移,或者任何动作导致新视图从侧面进来


当滑动开始时,配置你的新状态栏(下面的那个),无论样式,背景,什么:

[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:NO];
// anything else you might feel like doing 

现在我们有一些有趣的事情发生了。随着过渡的移动,你将不得不使用它滚动的量来"剪切",抵消statusBarView的量。statusBarView.frame必须从x=offset开始,否则它将显示在实际的状态栏上(因为它的窗口更高),但是如果你不改变contentInsets,那么图片将随着过渡滑动。因此,为了创造这种错觉,你需要将原点推到右边,同时增加相同数量的左侧内容插入,这样它就会出现在相同的位置。

因此在任何处理滑动动作的方法中:

注意:这很大程度上取决于个人实现,可能需要一些实验

 // if you're using an animation to handle the transition you can match up this change in x position with the animation
// if you're doing via pan gesture you could try something like:
CGFloat offset = self.viewThatIsScrolling.contentOffset.x; // may be negative depending on direction that is being swiped
if (midTransition) { // you can use the offset value here to check
    // NOTE: again, will depend on which direction this animation is happening in. I'll assume a new view coming in from left (so swiping right)
    statusBarView.frame = CGRectMake(offset, 0, self.statusBarView.frame.width, 20.0f); // move the origin over to the right
    statusBarView.contentInsets = UIEdgeInsetsMake(0, offset, 0, 0); // make the picture start 'offset' pixels to the left so it'll look like it hasn't moved
} 

(旁注:您也可以尝试使用转换,而不是显式设置框架:statusBarView.transform = CGAffineTransformMakeTranslation(offset -previousOffsetAmount, 0);。我在这里使用了preousoffsetamount因为你只想让它移动一个新的量这样它就可以匹配。如果你走这条路的话,这就需要被跟踪)

最后,一旦"滑动"完成,不要忘记从窗口中完全删除截图:

// if continuing from before:
if (midTransition) {
    ...
} else { // the view has been slid completely
    [statusBarView removeFromSuperview];
    statusBarView = nil;
    // I'm keeping the UIWindow where it is for now so it doesn't have to be recreated and because it has a clear background anyways
}
// if this is being done via animation the above can be called the animation finishes

我可能真的有兴趣尝试让这个工作,所以会更新如果这样。

最新更新