2015-07-13 37 views
18

是否可以動態着色statusBar這是新的Apple Music應用程序與新Apple音樂應用程序中的動態狀態欄相同

enter image description here

編輯:

新的蘋果音樂應用中的iOS 8.4有這個功能。

  • 打開應用程序。
  • 選擇並播放一首歌曲(狀態欄爲白色)
  • 向下滑動播放器控制器以查看「我的音樂」控制器(它具有黑色狀態欄,也許您將不得不返回導航層級結構)。
  • 現在只需向上/向下滑動即可查看動態狀態欄更改。

編輯2:

蘋果文檔似乎並沒有讓我們現在(​​)使用它。未來可能會有iOS 9

編輯3: 似乎並不在iOS 9產品尚未推出。

+0

思考私有API –

+0

圖片:上白色部分是第一個VC,與白色的狀態欄和專輯封面的部分是另一個VC(第一個VC以上)。 –

+0

問題是,狀態欄的上半部分爲深色,下半部分爲淺色? –

回答

-1

思考如何在沒有私有API的情況下實現這一點。

我想可能會有第二個UIWindow覆蓋您的statusBar的解決方案。

Adding view on StatusBar in iPhone

也許是可能使持續狀態欄的截圖(從主窗口獲取)添加到圖像,適用於它的一些過濾器和顯示你的第二個窗口,在這個「假狀態欄圖像」(上述「真正的'statusBar)。

你可以用第二個「假」狀態欄做你想做的事。

0

乍一看,它看起來像是從狀態欄上操作快照,但狀態欄在兩端都是實時的,所以情況並非如此。

乍一看,它看起來像是在iOS 8.4中引入的一些新的api,但在審查api後,我找不到與此相關的任何內容。

我覺得蘋果會在自己的應用中使用私人apis,這似乎很奇怪。這對開發人員來說會造成一些非常糟糕的例子,但是再次,沒有任何公開內容會讓您在生活狀態欄上擁有兩種樣式。

這給我們留下了私人API或黑魔法。

+0

那麼如何用黑魔法或私有API來完成這項工作? –

+0

如果Apple使用私有API,爲什麼它會很奇怪? – Legoless

+0

我相信蘋果在舞臺後面使用了很多私人東西,但對於開發人員顯然不能使用的視覺來說,感覺有點偏離我。 – Segev

2

我99.99%肯定這不能使用公共API(很容易)來完成,因爲我試過自己幾乎所有的東西(我個人也不認爲這是他們的狀態欄的一些神奇的方法,但相反,他們的應用程序能夠檢索狀態欄視圖,然後將掩碼應用於它)。

我可以肯定的是,你可以做你自己的StatusBar,並有MTStatusBarOverlay圖書館,不幸的是很舊的,所以我不能確定它是否有效,但似乎仍然有人使用它。

但是使用圖書館的方式做到這一點,我認爲可能有解決方案,肯定需要大量的工作,但是可行的,儘管不是「活」。概括地說,你會做這樣的:前20個像素的

  • 採取截圖(狀態欄)
  • 從這個截圖,remove everything that is not black(你可以改善它,它會搜索黑邊,這樣就可以保持綠色電池和透明度)這會讓你的覆蓋面具,還僞造狀態欄
  • 疊加狀態欄有:背景視圖掩蓋實際的狀態欄,你剛剛創建
  • Apply mask to that image阿爾法圖像,一切都掩蓋下會改變顏色,白色底紋
  • 根據用戶滾動更改蒙版的高度

現在,您應該可以正確滾動並正確更改顏色。它留下的唯一問題是狀態欄不存在,但它是真的嗎?一旦你滑出,你立即刪除你的覆蓋,讓它刷新。當您滾動到頂部時,您會做同樣的事情,但在這種情況下,您將狀態欄的顏色更改爲白色(無動畫),因此它適合您的狀態。它只會在短時間內停止運行。

希望它有幫助!

+0

對於誰低估了這個答案,請你提供你的意見,爲什麼它不好,所以我們可以迭代它?謝謝! –

+0

獎勵這個答案,因爲它提供私人API意見,並提供了一個例子(即使它的痛苦)。真正的答案是,我們都可能不得不等待這一點。 –

+0

他們使用私有API進行動畫進/出表視圖A-Z索引,它絕對不是公開可用的,並且在Apple Music中有做私人UI事情的先例:( – Luke

2

在Jiri的答案上迭代,這會讓你非常接近。用CWStatusBarNotification代替MTStatusBarOverlay。爲了處理視圖控制器之間的模式轉換,我使用了MusicPlayerTransition。我們在self.view中使用frame:CGRect(0,0,self.view.bounds.size.width,self.view.bounds.size.width)假設imageView:「art」。需要一點按摩,但你得到的主旨。注意:雖然我們不是「現場」,但我們最不可能停止的時間是一秒鐘,電池的顏色也不會保留。另外,您需要將CWStatusBarNotification.m中的動畫時間設置爲零。 (notificationAnimationDuration屬性)。

#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; 
} 

要與實際狀態欄,設置你的計時器保持你的狀態欄截屏同步。在viewWillAppear中觸發它,並在viewDidDisappear中將其終止。

-(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; 
} 

因爲我們有很強的參考定時器和設置和無效發生在同一個線程,有沒有擔心計時器未能無效。 最終的結果應該是這個樣子:

enter image description here

相關問題