Staram się dostosować do własnych potrzeb InfoWindow
po kliknięciu znacznika za pomocą nowego interfejsu API Map Google w wersji 2. Chcę, żeby wyglądało to w oryginalnej aplikacji Google do tworzenia map. Lubię to:
Kiedy mam w ImageButton
środku, nie działa - całość InfoWindow
jest zaznaczona, a nie tylko ImageButton
. Czytam, że dzieje się tak, ponieważ nie ma View
samego siebie, ale jest to migawka, więc poszczególnych elementów nie można od siebie odróżnić.
EDYCJA: W dokumentacji (dzięki Disco S2 ):
Jak wspomniano w poprzedniej sekcji o oknach informacyjnych, okno informacyjne nie jest widokiem na żywo, ale widok jest renderowany jako obraz na mapie. W rezultacie nasłuchiwania ustawione w widoku są ignorowane i nie można rozróżnić zdarzeń kliknięcia w różnych częściach widoku. Odradza się umieszczanie interaktywnych elementów - takich jak przyciski, pola wyboru lub wprowadzanie tekstu - w niestandardowym oknie informacyjnym.
Ale jeśli Google go używa, musi być jakiś sposób, aby to zrobić. Czy ktokolwiek ma jakiś pomysł?
źródło
View.draw(Canvas)
) ... Oznacza to, że wszelkie późniejsze zmiany w widoku nie zostaną odzwierciedlone przez okno informacyjne na mapie. Aby później zaktualizować okno informacyjne Ponadto okno informacyjne nie będzie respektować żadnej z interaktywności typowych dla normalnego widoku, takich jak zdarzenia dotyku lub gestu. Możesz jednak wysłuchać ogólnego zdarzenia kliknięcia w całym oknie informacyjnym, jak opisano w poniższej sekcji. ... w twoim przykładzie jest tylkoOdpowiedzi:
Sam szukałem rozwiązania tego problemu bez powodzenia, więc musiałem rzucić własny, którym chciałbym się tutaj z Wami podzielić. (Proszę wybaczyć mój zły angielski) (To trochę szalone, aby odpowiedzieć innemu Czechowi po angielsku :-))
Pierwszą rzeczą, jakiej próbowałem, było użycie starego, dobrego
PopupWindow
. To całkiem proste - wystarczy tylko wysłuchać,OnMarkerClickListener
a następnie pokazać niestandardowyPopupWindow
znak nad znacznikiem. Inni faceci na StackOverflow zasugerowali to rozwiązanie i na pierwszy rzut oka wygląda całkiem dobrze. Ale problem z tym rozwiązaniem pojawia się, gdy zaczynasz przesuwać mapę. Musisz przenieśćPopupWindow
jakoś samemu, co jest możliwe (słuchając niektórych wydarzeń onTouch), ale IMHO nie może sprawić, aby wyglądał wystarczająco dobrze, szczególnie na niektórych powolnych urządzeniach. Jeśli zrobisz to w prosty sposób, „przeskakuje” z jednego miejsca do drugiego. Możesz także użyć animacji, aby dopracować te skoki, ale w ten sposóbPopupWindow
zawsze będzie to „krok do tyłu” tam, gdzie powinno być na mapie, co mi się nie podoba.W tym momencie myślałem o innym rozwiązaniu. Uświadomiłem sobie, że tak naprawdę nie potrzebuję tak dużo swobody - aby pokazać swoje niestandardowe widoki ze wszystkimi dostępnymi możliwościami (takimi jak animowane paski postępu itp.). Myślę, że istnieje dobry powód, dla którego nawet inżynierowie Google nie robią tego w aplikacji Mapy Google. Wszystko, czego potrzebuję, to przycisk lub dwa w oknie InfoWindow, które pokażą stan naciśnięcia i wywołają pewne działania po kliknięciu. Wymyśliłem więc inne rozwiązanie, które dzieli się na dwie części:
Pierwsza część:
pierwszą częścią jest możliwość złapania kliknięć przycisków, aby wywołać akcję. Mój pomysł jest następujący:
MapFragment
(lubMapView
) wewnątrz niestandardowej grupy ViewGroup (moja nazywa się MapWrapperLayout)MapWrapperLayout
'dispatchTouchEvent i (jeśli aktualnie wyświetla się InfoWindow) najpierw skieruj MotionEvent do wcześniej utworzonego InfoWindow. Jeśli nie zużywa MotionEvents (na przykład dlatego, że nie kliknąłeś żadnego klikalnego obszaru w InfoWindow itp.), To (i tylko wtedy) pozwól, by zdarzenia zejść do nadklasy MapWrapperLayout, aby ostatecznie zostały dostarczone na mapę.Oto kod źródłowy MapWrapperLayout:
Wszystko to sprawi, że widoki wewnątrz InfoView znów będą „na żywo” - OnClickListeners zacznie się uruchamiać itp.
Druga część: Pozostały problem polega na tym, że na ekranie nie widać żadnych zmian interfejsu użytkownika programu InfoWindow. Aby to zrobić, musisz ręcznie wywołać Marker.showInfoWindow. Teraz, jeśli wykonasz jakąś stałą zmianę w swoim InfoWindow (np. Zmieniając etykietę przycisku na coś innego), to wystarczy.
Ale pokazanie stanu naciśnięcia przycisku lub czegoś takiego jest bardziej skomplikowane. Pierwszym problemem jest to, że (przynajmniej) nie byłem w stanie sprawić, aby InfoWindow pokazywał stan naciśnięcia przycisku normalnego. Nawet jeśli długo naciskałem przycisk, po prostu nie został wciśnięty na ekranie. Wierzę, że jest to coś, co jest obsługiwane przez samą strukturę mapy, co prawdopodobnie upewnia się, że nie pokazuje żadnego stanu przejściowego w oknach informacyjnych. Ale mogłem się mylić, nie próbowałem tego dowiedzieć.
To, co zrobiłem, to kolejny paskudny hack - załączyłem
OnTouchListener
przycisk do przycisku i ręcznie przełączyłem jego tło, gdy przycisk został naciśnięty lub zwolniony do dwóch niestandardowych drawables - jednego z przyciskiem w normalnym stanie, a drugiego w stanie wciśniętym. To nie jest bardzo miłe, ale działa :). Teraz mogłem zobaczyć, jak przycisk przełącza się między stanem normalnym a naciśnięciem na ekranie.Jest jeszcze jedna usterka - jeśli klikniesz przycisk zbyt szybko, nie pokaże on stanu naciśnięcia - po prostu pozostanie w swoim normalnym stanie (chociaż samo kliknięcie jest uruchamiane, więc przycisk „działa”). Przynajmniej tak pokazuje się na moim Galaxy Nexusie. Ostatnią rzeczą, którą zrobiłem, jest to, że nieco opóźniłem przycisk w stanie wciśniętym. Jest to również dość brzydkie i nie jestem pewien, jak to działałoby na niektórych starszych, wolnych urządzeniach, ale podejrzewam, że nawet sama struktura mapy robi coś takiego. Możesz spróbować sam - po kliknięciu całego okna InfoWindow pozostaje on dłużej w stanie wciśniętym, niż zwykłe przyciski (ponownie - przynajmniej na moim telefonie). I tak to działa nawet w oryginalnej aplikacji Google Maps.
W każdym razie napisałem sobie niestandardową klasę, która obsługuje zmiany stanu przycisków i wszystkie inne rzeczy, o których wspomniałem, więc oto kod:
Oto niestandardowy plik układu InfoWindow, którego użyłem:
Testuj plik układu działania (
MapFragment
znajdujący się wMapWrapperLayout
):I na koniec kod źródłowy działania testowego, który łączy to wszystko razem:
Otóż to. Do tej pory testowałem to tylko na moim Galaxy Nexusie (4.2.1) i Nexusie 7 (również 4.2.1), wypróbuję to na niektórych telefonach z Piernika, kiedy będę miał okazję. Ograniczeniem, które do tej pory znalazłem, jest to, że nie możesz przeciągać mapy z miejsca, w którym znajduje się przycisk na ekranie i przesuwać mapy. Prawdopodobnie można to jakoś pokonać, ale na razie mogę z tym żyć.
Wiem, że to brzydki hack, ale po prostu nie znalazłem nic lepszego i tak bardzo potrzebuję tego wzorca projektowego, że naprawdę byłby to powód, aby wrócić do frameworku map v1 (który przy okazji. Naprawdę bardzo chciałbym uniknąć dla nowej aplikacji z fragmentami itp.). Po prostu nie rozumiem, dlaczego Google nie oferuje programistom oficjalnego sposobu na przycisk w InfoWindows. To taki powszechny wzorzec projektowy, zresztą ten wzór jest używany nawet w oficjalnej aplikacji Google Maps :). Rozumiem powody, dla których nie mogą po prostu sprawić, by Twoje widoki były „na żywo” w InfoWindows - prawdopodobnie zabiłoby to wydajność podczas przesuwania i przewijania mapy. Ale powinien istnieć sposób na osiągnięcie tego efektu bez korzystania z widoków.
źródło
view.setBackground(bgDrawablePressed);
zif (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(bgDrawablePressed); }else{ view.setBackground(bgDrawablePressed); }
do pracy w Android Gingerbread, uwaga: jest jeszcze jedna wystąpienieview.setBackground
w kodzie.Widzę, że to pytanie jest już stare, ale wciąż ...
W naszej firmie stworzyliśmy bibliotekę sipmle, aby osiągnąć to, co jest pożądane - interaktywne okno informacyjne z widokami i wszystkim. Możesz to sprawdzić na github .
Mam nadzieję, że to pomoże :)
źródło
Oto moje podejście do problemu. Tworzę
AbsoluteLayout
nakładkę, która zawiera okno informacyjne (zwykły widok z wszelkimi możliwościami interakcji i rysowania). Następnie zaczynam,Handler
który synchronizuje pozycję okna informacyjnego z pozycją punktu na mapie co 16 ms. Brzmi szalenie, ale tak naprawdę działa.Wersja demonstracyjna wideo: https://www.youtube.com/watch?v=bT9RpH4p9mU (należy wziąć pod uwagę, że wydajność jest zmniejszona z powodu jednoczesnego działania emulatora i nagrywania wideo).
Kod wersji demo: https://github.com/deville/info-window-demo
Artykuł zawierający szczegóły (w języku rosyjskim): http://habrahabr.ru/post/213415/
źródło
Dla tych, którzy nie mogli dostać
choose007's
odpowiedziJeśli
clickListener
nie zawsze działa poprawnie wchose007's
rozwiązaniu, spróbuj wdrożyćView.onTouchListener
zamiastclickListener
. Obsługa zdarzenia dotykowego za pomocą dowolnej akcjiACTION_UP
lubACTION_DOWN
. Z jakiegoś powodu mapyinfoWindow
powodują dziwne zachowanie podczas wysyłania doclickListeners
.Edycja: Tak zrobiłem krok po kroku
Najpierw napompuj własne okno informacyjne (zmienną globalną) gdzieś w swojej aktywności / fragmencie. Mój jest w obrębie fragmentu. Upewnij się również, że widok główny w układzie okna informacyjnego jest liniowy (z jakiegoś powodu układ względny zajmował całą szerokość ekranu w oknie informacyjnym)
Następnie w wywołaniu zwrotnym onMapReady w Google Maps Android API (wykonaj to, jeśli nie wiesz, co to jest onMapReady Mapy> Dokumentacja - Pierwsze kroki )
MapWrapperLayout
inicjalizacja http://stackoverflow.com/questions/14123243/google-maps-android-api-v2- Interactive-infowindow-like-in-original-android-go / 15040761 # 15040761 39 - domyślna wysokość znacznika 20 - przesunięcie między domyślna dolna krawędź InfoWindow i jej dolna krawędź zawartości * /Metoda SetInfoWindow
Uchwyt znacznika kliknij osobno
źródło
Tylko spekulacja, nie mam wystarczającego doświadczenia, aby spróbować ...) -:
Ponieważ GoogleMap jest fragmentem, powinno być możliwe złapanie znacznika zdarzenia onClick i wyświetlenie niestandardowego widoku fragmentu . Fragment mapy będzie nadal widoczny w tle. Czy ktoś tego próbował? Czy jest jakiś powód, dla którego to nie działa
Wadą jest to, że fragment mapy zostałby zamrożony na tle, dopóki niestandardowy fragment informacji nie zwróci do niego kontroli.
źródło
Dla tego pytania zbudowałem przykładowy projekt studia na Androida.
wyjściowe zrzuty ekranu: -
Pobierz pełny kod źródłowy projektu Kliknij tutaj
Uwaga: musisz dodać klucz API w Androidmanifest.xml
źródło
To jest naprawdę proste.
Po prostu dodaj powyższy kod do swojej klasy, w której korzystasz z GoogleMap. R.layout.info_window_layout to nasz niestandardowy układ, który pokazuje widok, który pojawi się w miejscu okna informacyjnego. Właśnie dodałem tutaj widok tekstu. Możesz dodać tutaj dodatkowy widok, aby był podobny do przyciągania próbki. Mój info_window_layout był
Mam nadzieję, że to pomoże. Pracujący przykład niestandardowego okna informacyjnego znajduje się pod adresem stronie http://wptrafficanalyzer.in/blog/customizing-infowindow-contents-in-google-map-android-api-v2-using-infowindowadapter/#comment-39731
ZMIENIONO: Ten kod pokazuje, jak możemy dodać niestandardowy widok do infoWindow. Ten kod nie obsługiwał kliknięć elementów widoku niestandardowego. Jest więc blisko odpowiedzi, ale nie do końca odpowiedź, dlatego nie jest akceptowana jako odpowiedź.
źródło