Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 与新苹果音乐应用程序中的动态状态栏相同_Ios_Objective C_User Interface_Dynamic_Statusbar - Fatal编程技术网

Ios 与新苹果音乐应用程序中的动态状态栏相同

Ios 与新苹果音乐应用程序中的动态状态栏相同,ios,objective-c,user-interface,dynamic,statusbar,Ios,Objective C,User Interface,Dynamic,Statusbar,是否可以在新的苹果音乐应用程序中动态着色状态栏 编辑: iOS 8.4中的新苹果音乐应用程序具有此功能 打开应用程序 选择并播放歌曲(状态栏为白色) 向下滑动播放器控制器以查看“我的音乐”控制器(它有黑色的状态栏,可能您必须返回导航层次结构) 现在只需向上/向下滑动即可查看动态状态栏的更改 编辑2: 苹果的文档似乎不允许我们现在就使用它(ios8.4)。将来可能会在iOS 9上提供 编辑3: 在iOS 9中似乎还不可用。正在考虑如何在没有专用API的情况下实现此功能 我认为可能有一个解决方

是否可以在新的苹果音乐应用程序中动态着色状态栏

编辑:

iOS 8.4中的新苹果音乐应用程序具有此功能

  • 打开应用程序
  • 选择并播放歌曲(状态栏为白色)
  • 向下滑动播放器控制器以查看“我的音乐”控制器(它有黑色的状态栏,可能您必须返回导航层次结构)
  • 现在只需向上/向下滑动即可查看动态状态栏的更改
编辑2:

苹果的文档似乎不允许我们现在就使用它(
ios8.4
)。将来可能会在iOS 9上提供

编辑3:
在iOS 9中似乎还不可用。

正在考虑如何在没有专用API的情况下实现此功能

我认为可能有一个解决方案,第二个UIWindow覆盖您的状态栏

也许可以将状态栏的屏幕截图(从主窗口拍摄)不断地显示在图像上,对其应用一些过滤器,并在第二个窗口(在“真实”状态栏上方)显示此“假状态栏图像”


你可以用第二个“假”状态栏做你想做的事。

乍一看,它看起来像是从状态栏操纵快照,但状态栏两端都是活动的,所以情况并非如此

乍一看,它看起来像是iOS 8.4中引入的一些新api,但在查看该api后,我找不到任何与此相关的内容

我觉得很奇怪,苹果会在自己的应用程序中使用私有API。这会给开发人员带来一些非常糟糕的例子,但同样,没有任何公共工具可以让您在live statusbar上拥有两种样式


这就给我们留下了私有api或黑魔法

我99.99%确信使用公共API无法做到这一点(很容易),因为我尝试了几乎所有的方法(我个人也不认为这是他们状态栏的神奇方法,但相反,他们的应用程序能够检索状态栏视图,然后只对其应用掩码)

我敢肯定的是,你可以做你自己的状态栏,有一个库,不幸的是,非常旧的一个,所以我真的不能说这是否有效,但似乎仍然有人使用它

但使用图书馆的方式,我认为可能会有一个解决方案,当然,需要大量的工作,但是可行的,尽管不是“活的”。简而言之,您可以这样做:

  • 拍摄前20个像素的屏幕截图(状态栏)
  • 从这个屏幕截图中,(你可以改进它,让它搜索黑色边缘,这样你可以保留绿色电池和透明度)这将使你的叠加遮罩和假状态栏
  • 覆盖状态栏:背景视图遮罩实际状态栏和刚刚创建的alpha图像
  • ,所有被遮掩的东西都会变成白色
  • 根据用户滚动更改遮罩的高度
现在,您应该能够正确滚动并正确更改颜色。它留下的唯一问题是状态栏不存在,但它真的存在吗?一旦你向外滚动,你立即移除覆盖,让它刷新。当您滚动到最顶端时,也会执行相同的操作,但在这种情况下,您会将状态栏的颜色更改为白色(无动画),以使其适合您的状态。它不会只活一小段时间


希望有帮助

重复Jiri的答案,这会让你非常接近。替换为。要处理视图控制器之间的模式转换,我使用。我们假设self.view中有一个imageView:“art”和frame:CGRect(0,0,self.view.bounds.size.width,self.view.bounds.size.width)。需要一点按摩,但你明白要点了。注意:虽然我们没有“带电”,但我们最多只能关机一秒钟,电池颜色也不会保留。此外,还需要将CWStatusBarNotification.m中的动画时间设置为零。(notificationAnimationDuration属性)

因为我们对计时器有很强的引用,并且设置和失效发生在同一个线程上,所以不必担心计时器无法失效。 最终结果应如下所示:


思考私有APIMAGE:顶部白色部分是第一个VC,带有白色状态栏和相册封面的部分是另一个VC(位于第一个VC上方)。问题是状态栏的上半部分为深色,下半部分为浅色?不,这不是问题。iOS 8.4中的新苹果音乐应用程序具有此功能。您只需打开应用程序,选择一首歌曲(状态栏为白色),然后向下滑动此控制器以查看“我的音乐”控制器(状态栏为黑色)。现在只需向上/向下滑动即可查看动态状态栏的更改。感谢更新的信息。我知道,这个问题没有简单的解决办法。您可以查看此项目以供参考,它使用的方法与我在回答中建议的类似(但实现可滚动的状态栏行为)。作者拍摄状态栏的快照,并将其作为图像添加到假状态栏窗口中。为什么苹果使用私有API会很奇怪呢?我相信苹果在后台使用了很多私有的东西,但是开发者显然无法使用这些东西。。我觉得有点不对劲。不管是谁否决了这个答案,你能不能提供你的意见,说明为什么这个答案不好,这样我们就可以重复一下了?非常感谢。奖励这个答案是因为它提供了私人api意见,并提供了一个示例(即使它不成功)。真正的答案是,我们可能都必须等待。他们也在使用私有API来制作in/out表视图A-Z索引的动画,它肯定不是公开的,而且Apple Music中有做私有UI事情的先例:(
#import "CWStatusBarNotification.h"

#define kStatusTextOffset       5.4  // (rough guess of) space between window's origin.y and status bar label's origin.y

@interface M_Player () <UIGestureRecognizerDelegate> 

@property (retain) UIView *fakeStatusBarView;
@property (retain) CWStatusBarNotification *fakeStatusBar;
@property (retain) UIImageView *statusImgView;
@property (retain) UIImageView *statusImgViewCopy;
@property (retain) UIWindow *window;
@property (strong, nonatomic) NSTimer *statusTimer;

@end

@implementation M_Player
@synthesisze fakeStatusBarView, fakeStatusBar, statusImgView, statusImgViewCopy, window, statusTimer;

-(void)viewDidLoad{

    self.window = [[UIApplication sharedApplication] delegate].window;

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleStatusBarDrag:)];
    pan.delegate = self;
    [self.view addGestureRecognizer:pan];
}

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];

    if (!fakeStatusBar){
        [self buildFakeStatusBar];
    }

    if (!statusTimer) {
        [self setupStatusBarImageUpdateTimer];
    }

     // optional
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    [self setNeedsStatusBarAppearanceUpdate]; 


-(void)viewDidDisappear:(BOOL)animated{
   [super viewDidDisappear:animated];

   [self destroyStatusBarImageUpdateTimer];
-(void)destroyFakeStatusBar{
    [statusImgView removeFromSuperview];
    statusImgView = nil;
    [fakeStatusBarView removeFromSuperview];
    fakeStatusBarView = nil;
    fakeStatusBar = nil;
}

-(void)buildFakeStatusBar{
    UIWindow *statusBarWindow =  [[UIApplication sharedApplication] valueForKey:@"_statusBarWindow"];  // This window is actually still fullscreen. So we need to capture just the top 20 points.

    UIGraphicsBeginImageContext(self.view.bounds.size);
    [statusBarWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CGRect rect = CGRectMake(0, 0, self.view.bounds.size.width, 20);
    CGImageRef imageRef = CGImageCreateWithImageInRect([viewImage CGImage], rect);
    UIImage *statusImg = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    statusImg = [statusImg imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];  // This allows us to set the status bar content's color via the imageView's .tintColor property

    statusImgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)];
    statusImgView.image = statusImg;
    statusImgView.tintColor = [UIColor colorWithWhite:0.859 alpha:1.000];  // any color you want

    statusImgViewCopy = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)];
    statusImgViewCopy.image = statusImg;
    statusImgViewCopy.tintColor = statusImgView.tintColor;


    fakeStatusBarView = nil;
    fakeStatusBar = nil;
    fakeStatusBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)];
    [fakeStatusBarView addSubview:statusImgView];

    fakeStatusBar = [CWStatusBarNotification new];
    fakeStatusBar.notificationStyle = CWNotificationStyleStatusBarNotification;
    [fakeStatusBar displayNotificationWithView:fakeStatusBarView forDuration:CGFLOAT_MAX];
}

-(void)handleStatusBarDrag:(UIPanGestureRecognizer*)gestureRecognizer{
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {

    }

    if (gestureRecognizer.state == UIGestureRecognizerStateChanged){
        CGPoint convertedPoint = [self.window convertPoint:art.frame.origin fromView:self.view];
        CGFloat originY = convertedPoint.y - kStatusTextOffset;

        if (originY > 0 && originY <= 10) {  // the range of change we're interested in
            //NSLog(@"originY:%f statusImgView.frame:%@", originY, NSStringFromCGRect(statusImgView.frame));

            // render in context from new originY using our untouched copy as reference view
            UIGraphicsBeginImageContext(self.view.bounds.size);
            [statusImgViewCopy.layer renderInContext:UIGraphicsGetCurrentContext()];
            UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            CGRect rect = CGRectMake(0, kStatusTextOffset + originY, self.view.bounds.size.width, 20);
            CGImageRef imageRef = CGImageCreateWithImageInRect([viewImage CGImage], rect);
            UIImage *statusImg = [UIImage imageWithCGImage:imageRef];
            CGImageRelease(imageRef);

            statusImgView.image = statusImg;
            statusImgView.transform = CGAffineTransformMakeTranslation(0, kStatusTextOffset + originY);

        }

       // destroy
        if (originY > 90) {
            [self destroyFakeStatusBar];
        }
    }

    if (gestureRecognizer.state == UIGestureRecognizerStateEnded){

    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}
-(void)setupStatusBarImageUpdateTimer{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^(){
            // main thread
            if (!statusTimer) {
                statusTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleStatusTimer:) userInfo:nil repeats:YES];
                [[NSRunLoop currentRunLoop] addTimer:statusTimer forMode:NSRunLoopCommonModes];
            }
        });
    });
}

-(void)destroyStatusBarImageUpdateTimer{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^(){
            // main thread
            [statusTimer invalidate];
            statusTimer = nil;
        });
    });
}

-(void)handleStatusTimer:(NSTimer*)timer{
    UIWindow *statusBarWindow =  [[UIApplication sharedApplication] valueForKey:@"_statusBarWindow"];

    UIGraphicsBeginImageContext(CGSizeMake(self.view.bounds.size.width, 20));
    [statusBarWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CGRect rect = CGRectMake(0, 0, self.view.bounds.size.width, 20);
    CGImageRef imageRef = CGImageCreateWithImageInRect([viewImage CGImage], rect);
    UIImage *statusImg = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    statusImg = [statusImg imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    statusImgViewCopy.image = statusImg;
}