Rysowanie interfejsu użytkownika to tylko jeden z etapów tworzenia widoku niestandardowego. Musisz także wykonać te czynności: Spraw, aby widok odpowiadał na dane wejściowe użytkownika w sposób zbliżony rzeczywiste działania, które naśladujesz.
Spraw, aby obiekty w aplikacji działały tak samo jak prawdziwe. Na przykład: obrazy w aplikacji przestają istnieć i pojawiają się w innym miejscu. że nie robią tego w prawdziwym świecie. Zamiast tego przenieś zdjęcia z jednego miejsca do innego użytkownika.
Użytkownicy wyczuwają nawet subtelne zachowania i działania interfejsu i najlepiej reagują na naśladujące prawdziwy świat. Jeśli na przykład użytkownik przesuwa obiekt interfejsu, zapewnią na początku poczucie bezwładności, które opóźni ruch. Na koniec ruchu, daj im poczucie pędu, które przenosi obiekt poza flirtowanie.
Na tej stronie pokazujemy, jak za pomocą funkcji platformy Androida dodawać ich rzeczywiste zachowania do widoku niestandardowego.
Dodatkowe powiązane informacje znajdziesz w Zdarzenia wejściowe – omówienie oraz Animacja właściwości .
Uchwyć gesty wprowadzania
Podobnie jak wiele innych platform interfejsu, Android obsługuje model zdarzeń wejściowych. Użytkownik
te działania zmieniają się w zdarzenia, które wywołują wywołania zwrotne.
aby dostosować sposób, w jaki aplikacja odpowiada użytkownikowi. Najczęściej używane dane wejściowe
zdarzenie w systemie Android to dotyk, który uruchamia
onTouchEvent(android.view.MotionEvent)
Zastąp tę metodę obsługi zdarzenia w ten sposób:
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return super.onTouchEvent(event) }
Java
@Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
Zdarzenia dotknięcia nie są szczególnie przydatne. Nowoczesne interfejsy dotykowe
określić interakcje za pomocą gestów, takich jak klikanie, ciągnięcie, pchanie
przesuwać i powiększać. Aby przekonwertować nieprzetworzone zdarzenia dotyku na gesty, Android
zapewnia
GestureDetector
Utwórz GestureDetector
, przekazując instancję klasy
który stosuje
GestureDetector.OnGestureListener
Jeśli chcesz przetworzyć tylko kilka gestów, możesz rozszerzyć
GestureDetector.SimpleOnGestureListener
zamiast implementować GestureDetector.OnGestureListener
.
za pomocą prostego interfejsu online. Na przykład ten kod tworzy klasę, która rozszerza
GestureDetector.SimpleOnGestureListener
i zastąpienia
onDown(MotionEvent)
Kotlin
private val myListener = object : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { return true } } private val detector: GestureDetector = GestureDetector(context, myListener)
Java
class MyListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } } detector = new GestureDetector(getContext(), new MyListener());
Niezależnie od tego, czy korzystasz z usługi GestureDetector.SimpleOnGestureListener
,
zawsze stosuj
onDown()
która zwraca true
. Jest to konieczne, ponieważ wszystkie gesty
rozpocząć od komunikatu onDown()
. Jeśli zwrócisz false
od onDown()
, jak
GestureDetector.SimpleOnGestureListener
, system zakłada, że
chcesz zignorować resztę gestu. Inne metody
GestureDetector.OnGestureListener
nie są wywoływane. Tylko zwrot
false
od onDown()
, jeśli chcesz zignorować całą
gest.
Po zaimplementowaniu GestureDetector.OnGestureListener
i utworzeniu
wystąpienia GestureDetector
, możesz użyć
GestureDetector
na potrzeby interpretowania zdarzeń dotknięcia otrzymywanych w
onTouchEvent()
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return detector.onTouchEvent(event).let { result -> if (!result) { if (event.action == MotionEvent.ACTION_UP) { stopScrolling() true } else false } else true } }
Java
@Override public boolean onTouchEvent(MotionEvent event) { boolean result = detector.onTouchEvent(event); if (!result) { if (event.getAction() == MotionEvent.ACTION_UP) { stopScrolling(); result = true; } } return result; }
Gdy przekazujesz onTouchEvent()
zdarzenie dotknięcia, które nie jest rejestrowane
rozpoznać jako część gestu, zwraca false
. Następnie możesz uruchomić
za pomocą własnego kodu
wykrywania gestów.
Utwórz ruch, który może być fizycznie
Gesty to skuteczny sposób sterowania urządzeniami z ekranem dotykowym, ale mogą są sprzeczne z intuicją i trudne do zapamiętania, chyba że generują fizycznie miarodajnych wyników.
Załóżmy na przykład, że chcesz zaimplementować gest przesuwania w poziomie, który ustawia element narysowany w widoku obracający się wokół osi pionowej. Ten gest ma sens, jeśli interfejs szybko porusza się w kierunku przesunięcia, a potem zwalnia, jakby użytkownik naciskał koło zamachowe i zaczyna kręcić się wokół własnej osi.
Dokumentacja
animowanie przewijania
gest zawiera szczegółowe objaśnienie, jak wdrożyć własny styl
zachowanie użytkownika. Jednak symulowanie działania koła zamachowego nie jest takie proste. Dużo fizyki
i matematyki są niezbędne, aby model wiatraka działał prawidłowo. Na szczęście
Android udostępnia klasy pomocnicze symulujące to i inne zachowania.
Scroller
jest podstawą do obsługi gestów przesuwania przypominających koło zamachowe.
Aby rozpocząć romans, zadzwoń:
fling()
z prędkością początkową oraz minimalną i maksymalną x i y
jego wartości. Jako wartości prędkości możesz użyć wartości obliczonej przez
GestureDetector
Kotlin
fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { scroller.fling( currentX, currentY, (velocityX / SCALE).toInt(), (velocityY / SCALE).toInt(), minX, minY, maxX, maxY ) postInvalidate() return true }
Java
@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY); postInvalidate(); return true; }
Wywołanie fling()
powoduje skonfigurowanie modelu fizycznego dla rzutu.
gest. Następnie zaktualizuj Scroller
, wywołując
Scroller.computeScrollOffset()
w regularnych odstępach czasu. computeScrollOffset()
aktualizuje
wewnętrzny stan obiektu Scroller
, odczytując bieżącą godzinę i
za pomocą modelu fizycznego do obliczenia pozycji x i y w tej
obecnie się znajdujesz. Zadzwoń do nas
getCurrX()
oraz
getCurrY()
aby je pobrać.
Większość widoków przekazuje x i y obiektu Scroller
.
bezpośrednio
scrollTo()
Ten przykład wygląda trochę inaczej: wykorzystuje bieżącą pozycję przewijania x –
aby ustawić kąt obrotu widoku.
Kotlin
scroller.apply { if (!isFinished) { computeScrollOffset() setItemRotation(currX) } }
Java
if (!scroller.isFinished()) { scroller.computeScrollOffset(); setItemRotation(scroller.getCurrX()); }
Klasa Scroller
oblicza za Ciebie pozycję przewijania, ale
nie stosuje automatycznie tych pozycji w widoku. Zastosuj nowe współrzędne
na tyle często, by przewijanie animacji wyglądało płynnie. Są 2 sposoby
wykonaj następujące czynności:
- Wymuszanie ponownego rysowania przez wywołanie
postInvalidate()
po rozmowie z:fling()
. Ta technika wymaga oblicz odsunięcia przewijania w argumencieonDraw()
i wywołuj funkcjępostInvalidate()
za każdym razem, gdy przesunięcie przewijania zmian. - Skonfiguruj
ValueAnimator
aby uruchomić animację na czas trwania przelotu i dodać detektor do procesu. aktualizacje animacji przez wywołanieaddUpdateListener()
Ta technika pozwala animować właściwości elementuView
Płynne przejścia
Użytkownicy oczekują, że nowoczesny interfejs będzie płynnie przechodzić między stanami: elementy interfejsu pojawianie się i znikanie, a nie pojawianie się i znikanie, a początek ruchów i kończy się płynnie, zamiast zaczynać i zatrzymywać. Android animacja właściwości ułatwia płynne przejścia.
Aby można było korzystać z systemu animacji, za każdym razem, gdy właściwość zmieni, co wpływa na
wyglądu, nie zmieniaj bezpośrednio właściwości. Zamiast tego użyj
ValueAnimator
, aby wprowadzić zmianę. W poniższym przykładzie
że modyfikacja wybranego komponentu podrzędnego w widoku spowoduje, że cały wyrenderowany
widoku, obróć widok tak, aby wskaźnik wyboru był wyśrodkowany.
ValueAnimator
zmienia obrót w ciągu kilkuset
milisekund, a nie od razu ustawić nową wartość rotacji.
Kotlin
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply { setIntValues(targetAngle) duration = AUTOCENTER_ANIM_DURATION start() }
Java
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0); autoCenterAnimator.setIntValues(targetAngle); autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION); autoCenterAnimator.start();
Jeśli wartość, którą chcesz zmienić, jest jedną z podstawowych wartości View
tworzenie animacji jest jeszcze łatwiejsze, ponieważ widoki mają wbudowany
ViewPropertyAnimator
zoptymalizowaną pod kątem jednoczesnej animacji wielu właściwości, na przykład
następujący przykład:
Kotlin
animate() .rotation(targetAngle) .duration = ANIM_DURATION .start()
Java
animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();