2014-05-11 16 views
6

W najnowszej aktualizacji snapchat, po "przesuń palcem w prawo dla wiadomości" pasek stanu zmienia kolor z czarnego na biały w sposób gradientowy.Pasek stanu aktualizacji Snapchat Aktualizacja iOS7

http://imgur.com/osJI20u

Jak robią to bez używania prywatnych API, czy są one za pomocą prywatnych API?

Co Przyjrzeliśmy się:

Na pierwszy rzut oka myślałem, że są one po prostu robi to, co wszyscy inni, (jak Rdio obecnie robi) przez ekran przechwytywania całego ekranu, a następnie zmodyfikowanie/animacji ten zrzut ekranu.

Ale ... nie można uzyskać dostępu lub animować UIImage z tej metody przechwytywania ekranu, więc chociaż można przesunąć/przyciąć ten zrzut ekranu, nie można zmienić jego wyglądu.

Więc ... przetestowałem to i kiedy pasek stanu jest w tym stanie (połowa czerni/połowa biała), wciąż jest ŻYWO, ponieważ nie jest zrzutem ekranu i reaguje na zmiany ładowania/zmiany sygnału itp. , o ile mogę powiedzieć, że to niemożliwe bez korzystania z prywatnego API.

+0

Być może wielokrotnie ekranują się one na pasku stanu i wielokrotnie modyfikują te przydziały ekranu podczas przejścia. A może wykrywają zmiany w baterii/czasie/sygnale, a następnie ograniczanie ekranu tylko wtedy, gdy te rzeczy się zmieniają. –

+2

Najwyraźniej ma miejsce jakaś głęboka magia. – CrimsonChris

Odpowiedz

15

To mnie zainteresowało, więc grałem trochę z aplikacją i sprawdziłem hierarchię widoku aplikacji za pomocą Spark Inspector na urządzeniu z jailbreakiem i znalazłem kilka rzeczy.

Nie masz racji, że nie używają zrzutu ekranu. Pasek stanu po stronie, z której nawigujesz, jest migawką i nie zmienia się. Możesz to łatwo zobaczyć, gdy minie minuta, nowy pasek stanu dla widoku, do którego przechodzisz, zmieni się, ponieważ jest prawdziwy, ale stary nie będzie, ponieważ jest migawką. To sprawia, że ​​iluzja jest łatwa do opracowania.

Tutaj jest to, co dzieje się na wysokim poziomie:

  1. Po rozpoczęciu przejścia, aplikacja wykonuje migawkę na pasku stanu (najprawdopodobniej jest to faktycznie biorąc migawkę całego UIScreen i po prostu przycinając pasek stanu z niego) w jego bieżącym stanie i dołącza okno zawierające tę migawkę do górnej części widoku w przejściu, zakotwiczone do końcowej pozycji przejścia i zamaskowane przez widok kontrolera widoku "od". Wygląda na to, że okno ma wartość windowLevel powyżej UIWindowLevelStatusBar, dzięki czemu jest w stanie objąć pasek stanu rzeczywistego.

  2. Następnie kontroler widoku "do" przejmuje aktualny pasek stanu i zmienia go w stan "treść light". Przedstawia to sprytne złudzenie, że pojedynczy pasek stanu zmienia kolor z granicą przejściową, ale prawdziwy pasek stanu faktycznie znajduje się zawsze pod oknem migawki i rzeczywiście byłby widoczny natychmiast po rozpoczęciu przejścia, gdyby nie było to okno z migawką na górze tego.

+1

Masz rację, widok, który pochodzi z przechwytywania ekranu, a widok, który ma używać prawdziwego paska stanu, jest tym, co mnie oszuka. Bezczelny z nowym oknem powyżej. Sądzę, że Apple może to tylko zniechęcić, ale wciąż pozwala na to! –

+0

Hej Dima, dobra odpowiedź. Możesz rzucić okiem na to pytanie http://stackoverflow.com/questions/31378595/same-dynamic-status-bar-as-is-in-new-apple-music-app.Wygląda na to, że nowa aplikacja muzyczna robi to właśnie za pomocą paska stanu, ale z pewnością działa na obu końcach. (nie używa snapshotu jak snapchat). – Segev

+0

Dzięki za komentarz. Wygląda na to, że to najprawdopodobniej prywatny interfejs API, ale będę też miał na to oko. Mają podobną funkcjonalność w nakładce centrum powiadomień z przesunięciem (gdzie pasek statusu zsuwa się dynamicznie wraz z widokiem) od co najmniej roku, więc na pewno mają jakieś sztuczki w rękawie, które nie zostały nam jeszcze dostarczone. – Dima

1

Zbudowanie tego, na co odpowiedział Dima, myślałem, że może pomóc podstawowa implementacja, aby ludzie zaczęli. Jak Dima powiedział, że nie przesuwa paska stanu, przesuwając obraz paska stanu.

Zastrzeżone: I YOLO'd tę realizację tak robię żadnych gwarancji na to, czy będzie działać po wyjęciu z pudełka

Rozpoczynając iOS7 można zrobić zdjęcie za pomocą

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

So zasadniczo pasek stanu jest przycinany ze zdjęcia i dodawany do UIWindow z windowLevel powyżej UIWindowStatusLevelBar, dzięki czemu można go zobaczyć na prawdziwym pasku stanu. Coś jak:

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]; 

teraz reszta zależy od tego, co się realizacja wygląda jak, ale tutaj naprawdę wystarczy do obsługi przesuwania widoku z jednej patelni, czy cokolwiek działanie powoduje nowy widok przyjść z boku.


Kiedy przesuwając rozpoczyna skonfigurować swój nowy pasek statusu (ten pod spodem) z jakiegokolwiek stylu, tło, cokolwiek:

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

Teraz mamy coś ciekawego dzieje się tutaj. W miarę przemieszczania się przejścia, będziesz musiał użyć kwoty przewiniętej, aby "wyciąć" tę wartość z offu z statusBarView. statusBarView.frame będzie musiał zaczynać się od x = offset, bo inaczej wyświetli się na aktualnym pasku stanu (ponieważ jego okno jest wyższe), ale jeśli nie zmienisz contentInsets, obraz będzie się przesuwać wraz z przejściem. Aby stworzyć iluzję, musisz przesunąć pochodzenie w prawo, zwiększając lewą zawartość o tę samą wartość, aby wyglądało na to, że znajduje się w tym samym miejscu.

Więc wewnątrz cokolwiek jest metoda obsługi działań przesuwny:

Uwaga: To będzie silnie zależeć od osobistych wdrażania i prawdopodobnie będzie wziąć kilka eksperymentów

// 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 

} 

(marginesie: można również spróbuj użyć transformacji, zamiast jawnie ustawiać ramkę: statusBarView.transform = CGAffineTransformMakeTranslation(offset -previousOffsetAmount, 0);. Używam poprzedniej wartościOffsetAmount, ponieważ chcesz ją przesunąć o dowolną nową kwotę, aby mogła się dopasować. Będzie to musiało być śledzone w jakiś sposób, jeśli to zrobisz trasa)

I wreszcie po „przesuwane” jest zrobione, nie zapomnij, aby usunąć zrzut ekranu z okna całkowicie:

// 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 

I rzeczywiście może być zainteresowany stara się uzyskać to do pracy, więc zaktualizuje się, jeśli tak.