Bekerja dengan antarmuka di Google Maps SDK untuk Android

Artikel ini akan bermanfaat bagi mereka yang sebelumnya tidak menggunakan Google Maps SDK dalam pekerjaan mereka.

Di bawah pemotong, metode dasar bekerja dengan peta dijelaskan, seperti menambahkan dan mengelola spidol, cara memindahkan kamera di atas peta, mengendalikan zoom, membangun rute dan geocoding. Serta keterbatasan dan cara untuk menghindarinya.

gambar
Sumber

Untuk menulis artikel, saya terinspirasi oleh pengalaman saya sendiri, yang saya peroleh saat menulis aplikasi untuk kurir menggunakan peta Google dalam pekerjaan mereka. Jadi semua tangkapan layar dan kemungkinan penyebutan logika bisnis akan terjadi dalam konteks membangun antarmuka kurir.

Sayangnya, Google Maps SDK untuk Android tidak memungkinkan Anda untuk mengubah posisi tombol kontrol, yang disebut Kontrol UI, ini termasuk: IndoorLevelPicker - menampilkan denah bangunan, Kompas - kompas, tombol Lokasiku - buka peta di lokasi saat ini, bilah alat Peta - tombol untuk membangun rute dan membuka peta, serta ZoomControls - menambah dan mengurangi skala peta.

Dengan menggunakan bilah alat Peta dan ZoomControls sebagai contoh, mari kita lihat kesulitan apa yang dapat timbul karena ketidakmampuan untuk mengubah posisi kontrol dan cara menyiasatinya.

gambar
Masalah menampilkan kontrol UI dari SDK (disorot dalam warna oranye) dan rekanan khusus mereka (disorot dalam warna hijau)

Dalam hal ini, kami memiliki tombol di sudut kanan bawah (tombol aksi mengambang) untuk masuk ke daftar alamat pesanan pengiriman, pada gambar di sebelah kiri Anda dapat melihat bahwa ZoomControls berada di bawahnya dan secara praktis tidak dapat diakses untuk mengklik. Pada gambar di sebelah kanan, ketika Anda mengklik penanda, tombol dari bilah alat Peta muncul, mereka juga muncul di bawah tombol untuk pergi ke daftar pesanan.

Solusi

Hal pertama yang perlu kita lakukan adalah menyembunyikan tampilan tombol asli. Anda dapat melakukan ini dengan mengganti metode onMapReady, ini dipanggil saat kartu siap digunakan.

Jangan tampilkan tombol Kontrol zoom dan jangan tampilkan tombol membangun rute dari SDK
private GoogleMap mMap; private UiSettings uiSettings; @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; uiSettings = mMap.getUiSettings(); //   Zoom uiSettings.setZoomControlsEnabled(false); //         SDK uiSettings.setMapToolbarEnabled(false); } 


Kami menambahkan tombol yang diperlukan ke tata letak, di mana mereka harus sesuai dengan desain kami:

gambar
Lokasi tombol kontrol peta khusus

Kemudian, dalam metode onCreateView, tentukan tindakan yang harus terjadi ketika tombol kita diklik:

Penangan untuk tombol untuk menambah dan mengurangi skala, serta membangun rute
 private ImageButton imageButtonZoomIn; private ImageButton imageButtonZoomOut; private ImageButton imageButtonRoute; private GoogleMap mMap; @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { //  imageButtonZoomIn = view.findViewById(R.id.imageButtonZoomIn); imageButtonZoomIn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mMap.animateCamera(CameraUpdateFactory.zoomIn()); } }); //  imageButtonZoomOut = view.findViewById(R.id.imageButtonZoomOut); imageButtonZoomOut.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mMap.animateCamera(CameraUpdateFactory.zoomOut()); } }); //      imageButtonRoute = view.findViewById(R.id.imageButtonRoute); imageButtonRoute.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String latitude = String.valueOf(activMarker.getPosition().latitude); String longitude = String.valueOf(activMarker.getPosition().longitude); Uri gmmIntentUri = Uri.parse("google.navigation:q=" + latitude + "," + longitude); Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); mapIntent.setPackage("com.google.android.apps.maps"); try{ if (mapIntent.resolveActivity(Objects.requireNonNull(getActivity()).getPackageManager()) != null) { startActivity(mapIntent); } }catch (NullPointerException e){ Log.e(TAG, "onClick: NullPointerException: Couldn't open map." + e.getMessage() ); Toast.makeText(getActivity(), "Couldn't open map", Toast.LENGTH_SHORT).show(); } } }); } 


Kekhasan metode animateCamera adalah bahwa skala berubah dengan lancar, dan tidak secara instan, dan jika, misalnya, Anda perlu mematikan animasi tombol zoom tertentu ketika skala maksimum atau minimum tercapai, Anda perlu mendefinisikan kembali metode onCameraIdle , yang disebut ketika skala peta berubah.

Mengaktifkan dan menonaktifkan tombol zoom
  @Override public void onCameraIdle() { if (mMap.getCameraPosition().zoom == mMap.getMinZoomLevel()){ //  ,     imageButtonZoomOut.setEnabled(false); imageButtonZoomIn.setEnabled(true); }else if (mMap.getCameraPosition().zoom == mMap.getMaxZoomLevel()){ //  ,     imageButtonZoomOut.setEnabled(true); imageButtonZoomIn.setEnabled(false); }else { //       imageButtonZoomOut.setEnabled(true); imageButtonZoomIn.setEnabled(true); } } 


Untuk melakukan tindakan apa pun dengan marker (kecuali untuk menyeret dan menjatuhkan), misalnya, buat pesanan baru, hapus penanda yang ditempatkan secara acak, buka pesanan yang ada atau panggil telepon seperti ditunjukkan dalam pesanan, tambahkan tombol kontrol yang sesuai ke tata letak dan daftarkan penangannya.

gambar
Tombol Kontrol Penanda

Memproses klik pada peta untuk menambahkan penanda dan menampilkan tombol kontrol khusus
 private GoogleMap mMap; private ImageButton imageButtonRoute; @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { imageButtonRoute.setVisibility(View.GONE); if (myMarker !=null){ //   myMarker.remove(); } //    myMarker = mMap.addMarker(new MarkerOptions() .position(latLng) //   .title(Objects.requireNonNull(getContext()).getString(R.string.title_on_marker_to_new_order)) // true ,         .draggable(true)); myMarker.setTag(null); //    imageButtonAddMarker.setVisibility(View.VISIBLE); imageButtonRemoveMarker.setVisibility(View.VISIBLE); } }); } 


Kami menunjukkan apa yang ingin kami lakukan dengan marker ketika kami mengklik tombol add order
 private ImageButton imageButtonAddMarker; private Marker myMarker; @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { imageButtonAddMarker = view.findViewById(R.id.imageButtonAddMarker); imageButtonAddMarker.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myMarker !=null && myMarker.getTag()==null) { //    imageButtonAddMarker.setVisibility(View.GONE); imageButtonRemoveMarker.setVisibility(View.GONE); //  ,          listener.openOrderContentsFragmentFromMap(null, myMarker); //   ,     myMarker.remove(); } } }); } 


Fitur lain adalah bahwa tidak ada tombol di SDK untuk menghapus penanda pada kartu. Untuk melakukan ini, kami juga membuat tombol sendiri:

Tentukan apa yang ingin kita lakukan dengan marker ketika kita mengklik tombol delete marker
 private ImageButton imageButtonRemoveMarker; private Marker myMarker; @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { imageButtonRemoveMarker = view.findViewById(R.id.imageButtonRemoveMarker); imageButtonRemoveMarker.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myMarker !=null && myMarker.getTag()==null){ //   imageButtonAddMarker.setVisibility(View.GONE); imageButtonRemoveMarker.setVisibility(View.GONE); //    myMarker.remove(); } } }); } 


Ketika mengklik penanda, judulnya terbuka, mengklik yang juga dapat digunakan untuk melakukan tindakan apa pun, ketika saya mengklik judul penanda baru, saya membuat pesanan baru untuk pengiriman ke kurir, dan pada penanda pesanan yang ada saya membuka informasi pengiriman rinci, termasuk daftar barang

Tetapkan tindakan saat mengklik pada jendela info penanda
 private GoogleMap mMap; @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; mMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() { @Override public void onInfoWindowClick(Marker marker) { if (marker.getTag()==null) { //    : //      listener.openOrderContentsFragmentFromMap(null, marker); if (myMarker != null) { //   ,     myMarker.remove(); } } else { //     : //         listener.openOrderContentsFragment((Long) marker.getTag()); } } }); } 


Proses mengeluarkan beberapa marker (baca daftar pesanan) ke kartu pada prinsipnya tidak berbeda dengan output satu marker. Marker terdiri dari koordinat (posisi), judul (title), teks kecil di bawah judul (snippet) dan tag (setTag) - itu dapat digunakan untuk mengidentifikasi banyak penanda pada peta.

gambar
Beberapa penanda peta

Menggambar banyak marker dengan koordinat yang diberikan
 public void drawListMarker(List<InfoMarker> latLngList) { if (latLngList == null || latLngList.size() == 0) { return; } //    mMap.clear(); LatLngBounds.Builder builder = new LatLngBounds.Builder(); boolean fiarstGreean = true; int count = 1; for (InfoMarker latLng : latLngList) { BitmapDescriptor icon; if (fiarstGreean){ //      //..           icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN); fiarstGreean = false; } else { icon = latLng.getIcon(); } //      mMap.addMarker(new MarkerOptions().position(latLng.getLatLng()).title(String.valueOf(count)).snippet(latLng.getTitle()).icon(icon)).setTag(latLng.getIdOrder()); builder.include(latLng.getLatLng()); count++; } //       CameraUpdate cameraUpdate; if (loaded) { cameraUpdate = CameraUpdateFactory .newLatLngBounds(builder.build(), 100); } else { cameraUpdate = CameraUpdateFactory.newLatLng(builder.build().getCenter()); } mMap.moveCamera(cameraUpdate); mMap.animateCamera(CameraUpdateFactory.zoomIn()); mMap.animateCamera(CameraUpdateFactory.zoomTo(10), 1000, null); } 


Beberapa kata tentang geocoder

Geocoder digunakan untuk mendapatkan alamat berdasarkan koordinat. Menempatkan penanda di peta dan mengklik tombol tambah pesanan, kita mendapatkan koordinat geografis dari titik yang diinginkan, yaitu lintang dan bujur. Tetapi untuk kenyamanan pengguna, akan menyenangkan untuk menunjukkan alamat dalam bentuk yang dapat dibaca manusia, mis., Misalnya, negara, kota, jalan, rumah.

Google Maps SDK berisi kelas Geocoder , dengan memanggil metode getFromLocation Anda bisa mendapatkan array alamat pada koordinat yang ditentukan.

Agar tidak memblokir utas UI terlalu lama, terutama jika Internet lambat atau tidak dapat diakses, melalui panggilan - kami akan menggunakan RxJava:

gambar
Alamat titik yang dihasilkan pada peta berdasarkan koordinat geografis

Menggunakan Java RX untuk mengakses Google geocoder
 LatLng position = myMarker.getPosition(); Location location = new Location("new"); location.setLatitude(position.latitude); location.setLongitude(position.longitude); LocationRepostiory locationRepostiory = new LocationRepostiory(context, location); locationRepostiory.getLastLocation(). observeOn(SchedulerProvider.getInstance().ui()). subscribeOn(SchedulerProvider.getInstance().computation()). subscribe(locationString -> { if(editTextAddress.length()==0){ //       ,      editTextAddress.setText(locationString); } }, throwable -> { }); 


Teks kelas LocationRepostiory di mana geocoding terbalik terjadi
 public class LocationRepostiory { private Context context; private Location location; public LocationRepostiory(Context context, Location location) { this.context = context; this.location = location; } public Single<String> getLastLocation() { return Single.create(this::subscribeOnLocation); } private void subscribeOnLocation(SingleEmitter<String> e) { Geocoder geocoder = new Geocoder(context, Locale.getDefault()); String errorMessage = ""; List<Address> addresses = null; try { //     addresses = geocoder.getFromLocation( location.getLatitude(), location.getLongitude(), // In this sample, get just a single address. 1); } catch (IOException ioException) { //,      I/O. errorMessage = context.getString(R.string.service_not_available); Log.e(TAG, errorMessage, ioException); } catch (IllegalArgumentException illegalArgumentException) { // ,       errorMessage = context.getString(R.string.invalid_lat_long_used); Log.e(TAG, errorMessage + ". " + "Latitude = " + location.getLatitude() + ", Longitude = " + location.getLongitude(), illegalArgumentException); } //  ,     if (addresses == null || addresses.size() == 0) { if (errorMessage.isEmpty()) { errorMessage = context.getString(R.string.no_address_found); Log.e(TAG, errorMessage); } } else { Address address = addresses.get(0); ArrayList<String> addressFragments = new ArrayList<String>(); //      . for (int i = 0; i <= address.getMaxAddressLineIndex(); i++) { e.onSuccess(address.getAddressLine(i)); } } } } 

Source: https://habr.com/ru/post/id484100/


All Articles