Autor Wątek: Jak napisać płynnego scrolla ?  (Przeczytany 1953 razy)

Offline Adam B

  • Użytkownik

# Wrzesień 16, 2012, 13:14:25
Hej,

Postanowiłem napisać dla aplikacji Androidowej własnego scrolla (w języku JAVA) - ten, który jest w systemie do końca mi nie odpowiada. Scroll już istnieje i działa, ale mam problem z płynnością animacji po oderwaniu palca od ekranu.

Na wstępie podaje dane wylogowane do konsoli:
Delta: 0.022, ScrollYSpeed: 455.96915 ScrollY*Delta: 10.031322
Delta: 0.023, ScrollYSpeed: 438.67862 ScrollY*Delta: 10.089608
Delta: 0.023, ScrollYSpeed: 421.1819 ScrollY*Delta: 9.687183
Delta: 0.022, ScrollYSpeed: 405.75 ScrollY*Delta: 8.9265
Delta: 0.022, ScrollYSpeed: 390.0921 ScrollY*Delta: 8.5820265
Delta: 0.022, ScrollYSpeed: 374.957 ScrollY*Delta: 8.249054
Delta: 0.022, ScrollYSpeed: 360.99817 ScrollY*Delta: 7.94196
Delta: 0.026, ScrollYSpeed: 344.9228 ScrollY*Delta: 8.967993
Delta: 0.023, ScrollYSpeed: 330.71472 ScrollY*Delta: 7.6064386
Delta: 0.022, ScrollYSpeed: 317.62158 ScrollY*Delta: 6.9876747
Delta: 0.022, ScrollYSpeed: 304.99133 ScrollY*Delta: 6.7098093
Delta: 0.022, ScrollYSpeed: 292.81198 ScrollY*Delta: 6.4418635
Delta: 0.022, ScrollYSpeed: 280.5139 ScrollY*Delta: 6.1713057
Delta: 0.022, ScrollYSpeed: 268.17126 ScrollY*Delta: 5.899768
Delta: 0.022, ScrollYSpeed: 256.90808 ScrollY*Delta: 5.6519775
Delta: 0.025, ScrollYSpeed: 245.0903 ScrollY*Delta: 6.127258
Delta: 0.024, ScrollYSpeed: 233.32597 ScrollY*Delta: 5.5998235
Delta: 0.022, ScrollYSpeed: 223.05963 ScrollY*Delta: 4.907312
Delta: 0.022, ScrollYSpeed: 213.24501 ScrollY*Delta: 4.69139
Delta: 0.022, ScrollYSpeed: 203.86223 ScrollY*Delta: 4.484969
Delta: 0.022, ScrollYSpeed: 195.30002 ScrollY*Delta: 4.2966003
Delta: 0.024, ScrollYSpeed: 186.31622 ScrollY*Delta: 4.4715896
Delta: 0.024, ScrollYSpeed: 177.37305 ScrollY*Delta: 4.2569532
Delta: 0.022, ScrollYSpeed: 169.92339 ScrollY*Delta: 3.7383144

 - Jak widać "delta" skacze od 22 do 25 ms (delta pomiędzy tym, a ostatnim wywołaniem funkcji)
 - ScrollYSpeed - to prędkość jaką posiada aktualnie scroll (pikseli/s)
 - A ostatnia wartość to przesunięcie jakie ma odbyć się na "elementach skrolowanych" - z danych można wywnioskować, że niekiedy wartość przeskakuje np. z 6 na 5, a potem znowu 6 (to chyba jest główną przyczyną efektu cięcia ?)

 - pomiędzy wywołaniami funkcji skrolującej uruchamiana jest też funkcja zmniejszająca prędkość skrola (ScrollYSpeed).
 - Do przesunięcia elementów wewnątrz scrolla jest użyta funkcja scrollBy(int x, int y), która jest systemowa.

Pozdrawiam!

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Shusty

  • Użytkownik

# Wrzesień 16, 2012, 17:33:40
Jeśli problemem jest skacząca delta, to zrób to w pętli stałokrokowej.

Offline Xirdus

  • Redaktor

# Wrzesień 16, 2012, 20:37:31
Jeśli problemem jest skacząca delta, to zrób to w pętli stałokrokowej.
Jakoś tak wątpię żeby to pomogło. Jeśli to problem z API systemowym, to twoja propozycja jeszcze bardziej skoki pogorszy.



Ja myślę, że źle przesuwasz. Zamiast każdorazowo obcinać floata i przekazywać do funkcji 5 czy 6, zapisuj sobie pożądaną pozycję ekranu w pomocniczym floacie, a ekran przesuwaj tak, by jak najlepiej się z tym floatem pokrywał. Aczkolwiek to tylko czysty strzał - nie podałeś za wiele szczegółów, po których można by dojść do sedna problemu. Mógłbyś pokazać kod na przykład?

Offline Adam B

  • Użytkownik

# Wrzesień 16, 2012, 23:01:22
Jakoś tak wątpię żeby to pomogło. Jeśli to problem z API systemowym, to twoja propozycja jeszcze bardziej skoki pogorszy.



Ja myślę, że źle przesuwasz. Zamiast każdorazowo obcinać floata i przekazywać do funkcji 5 czy 6, zapisuj sobie pożądaną pozycję ekranu w pomocniczym floacie, a ekran przesuwaj tak, by jak najlepiej się z tym floatem pokrywał. Aczkolwiek to tylko czysty strzał - nie podałeś za wiele szczegółów, po których można by dojść do sedna problemu. Mógłbyś pokazać kod na przykład?

Jeżeli chodzi o zapamiętywanie "reszty powstałej z rzutowania" flota na inta to coś takiego mam - działa i ma się dobrze :)

Tutaj wypis z LOGA:

-----START FUNCTION-----
 _mDeltaTime: 0.024
 _mScrollYValue: 13.469114
 _mYRestFromLastCall: -0.049380302
 _mScrollYValue + _mYRestFromLastCall: 13.419734
 SETTER: _mYRestFromLastCall = 0.419734
 (int) scrollYValue: 13
 -----------------
 
 -----START FUNCTION-----
 _mDeltaTime: 0.037
 _mScrollYValue: 19.972141
 _mYRestFromLastCall: 0.419734
 _mScrollYValue + _mYRestFromLastCall: 20.391876
 SETTER: _mYRestFromLastCall = 0.39187622
 (int) scrollYValue: 20
 -----------------
 
 -----START FUNCTION-----
 _mDeltaTime: 0.037
 _mScrollYValue: 18.735952
 _mYRestFromLastCall: 0.39187622
 _mScrollYValue + _mYRestFromLastCall: 19.127829
 SETTER: _mYRestFromLastCall = 0.1278286
 (int) scrollYValue: 19
 -----------------
 
 -----START FUNCTION-----
 _mDeltaTime: 0.022
 _mScrollYValue: 10.725338
 _mYRestFromLastCall: 0.1278286
 _mScrollYValue + _mYRestFromLastCall: 10.853167
 SETTER: _mYRestFromLastCall = -0.14683342
 (int) scrollYValue: 11
-----------------

Na logu widać też wyraźne skoki delty (specjalnie wybrałem takie logi) od 22 do 37 ms.
Zastanawiam się jako można skutecznie walczyć z czymś takim ? Chyba, że wyjść z założenia, że maszyna wirtualna Javy tak ma i nic się na to nie poradzi?

Pozdrawiam

Offline rhdbisgrt

  • Użytkownik

# Wrzesień 16, 2012, 23:17:28
Jeżeli chodzi o zapamiętywanie "reszty powstałej z rzutowania" flota na inta to coś takiego mam - działa i ma się dobrze :)

Tutaj wypis z LOGA:

-----START FUNCTION-----
 _mDeltaTime: 0.024
 _mScrollYValue: 13.469114
 _mYRestFromLastCall: -0.049380302
 _mScrollYValue + _mYRestFromLastCall: 13.419734
 SETTER: _mYRestFromLastCall = 0.419734
 (int) scrollYValue: 13
 -----------------
 
 -----START FUNCTION-----
 _mDeltaTime: 0.037
 _mScrollYValue: 19.972141
 _mYRestFromLastCall: 0.419734
 _mScrollYValue + _mYRestFromLastCall: 20.391876
 SETTER: _mYRestFromLastCall = 0.39187622
 (int) scrollYValue: 20
 -----------------
 
 -----START FUNCTION-----
 _mDeltaTime: 0.037
 _mScrollYValue: 18.735952
 _mYRestFromLastCall: 0.39187622
 _mScrollYValue + _mYRestFromLastCall: 19.127829
 SETTER: _mYRestFromLastCall = 0.1278286
 (int) scrollYValue: 19
 -----------------
 
 -----START FUNCTION-----
 _mDeltaTime: 0.022
 _mScrollYValue: 10.725338
 _mYRestFromLastCall: 0.1278286
 _mScrollYValue + _mYRestFromLastCall: 10.853167
 SETTER: _mYRestFromLastCall = -0.14683342
 (int) scrollYValue: 11
-----------------

Na logu widać też wyraźne skoki delty (specjalnie wybrałem takie logi) od 22 do 37 ms.
Zastanawiam się jako można skutecznie walczyć z czymś takim ? Chyba, że wyjść z założenia, że maszyna wirtualna Javy tak ma i nic się na to nie poradzi?

Pozdrawiam

Nie wiem ale mysle ze niekoniecznie. Sprobuj np powylaczac inne programy i zobaczyc

 Ja mam np cos takiego ze rwie mi plynnosc ramek jesli mam wlaczonego Proces Explorera Sysinternals, :/ wrzuca on do traya wskaznik aktualnego obciazenia procka i updatuje to co sekunde, wtedy to raz na sekunde kazda ramka w mojej gierce zalicza skok +30 milisekund :/

Mozna to o ile pamietam wyealiminowac zwiekszajac priorytet procesu prawia na maksa albo wylaczajac Proces Explorera, bez tego jest w miare plynnie (poki np nie właczyć itunesa ;-) zwłaszcza gdy doczytuje nowa piosenke na starcie OIP) :>

//edit , nie doczytalem ze chodzi o androida, to moze miec mniejsze zastosowanie - ale jesli chodzi o skoki pod winda to wlasnie tak mam jak mowie, apka zalezy od aktywnosci innych procesow i do konca nie bardzo wiem co na to poradzic, choc w praktyce chyba nie jest tak zle, ale tez scrolle sa chyba tym co najbardziej rwie, czesto w profesjonalnych duzych grach widywalem rwace scrolle

« Ostatnia zmiana: Wrzesień 17, 2012, 00:01:00 wysłana przez rhdbisgrt »

Offline deadeye

  • Użytkownik

# Wrzesień 17, 2012, 13:00:52
Z mojego doświadczenia nie możesz zrobić płynnej animacji w wątku UI przed Androidem 4.1 (pierwszy w którym wprowadzono optymalizacje animacji i vsync).
Natomiast można z osobnego wątku. Są różne sposoby, ale podstawa to nie modyfikować layoutów ani nie powodować ich przetwarzania. Można to zrobić przez zmianę wartości translationX i translationY view który przesuwasz, albo lepiej wyświetlać scrollowane dane na czymś w stylu SurfaceView samemu. W obu przypadkach trzeba to zrobić z niezależnego wątku aby było idealnie płynne.

Offline deadeye

  • Użytkownik

# Wrzesień 17, 2012, 15:53:13
BTW porównanie samego Google jak animacje systemowe cieły się jeszcze w 4.0 http://www.youtube.com/watch?v=FCVMvvXHqxU

(choć w 3.0 było jeszcze znacznie gorzej).

Offline Adam B

  • Użytkownik

# Wrzesień 17, 2012, 21:04:44
Z mojego doświadczenia nie możesz zrobić płynnej animacji w wątku UI przed Androidem 4.1 (pierwszy w którym wprowadzono optymalizacje animacji i vsync).
Natomiast można z osobnego wątku. Są różne sposoby, ale podstawa to nie modyfikować layoutów ani nie powodować ich przetwarzania. Można to zrobić przez zmianę wartości translationX i translationY view który przesuwasz, albo lepiej wyświetlać scrollowane dane na czymś w stylu SurfaceView samemu. W obu przypadkach trzeba to zrobić z niezależnego wątku aby było idealnie płynne.

Czy możesz dać jakiś przykład odnośnie wyświtlania/modyfikowania View na SurfaceView?? Jak byś chciał skrolować np textView po surfaceView ?? Proszę o jakiś nawet pseudokodzik...