23

使用v2 API在Google地圖上標記動畫的最佳方式是什麼?在Google地圖v2上設置動畫標記

我正在研究一個以地圖爲中心的遊戲,我跟蹤人的位置並將它們顯示在地圖上以供彼此查看。隨着人們的移動,我想創建一個標記,從現在到最新的位置。每個人都有一個方向,所以我需要適當地旋轉標記。

使用新的Google Maps API來完成此操作的最佳方法是什麼?

+0

可能[duplicate](http://stackoverflow.com/questions/13972401/google-map-v2-marker-animation)?如果在你選擇的解決方案中,你需要插入經度,密切關注第180次子午線上的符號翻轉。 – hleinone 2013-02-13 23:58:38

+0

@hleinone不完全。您提到的那個解決方案可以:a)移動相機b)將標記移動到不同的位置。 我需要b),它可以簡單地通過做Marker.setPosition()來完成。但是,更改標記的圖標(我將沿着運動方向顯示旋轉的圖像)不起作用。看來,需要清除地圖上的所有標記以使圖標發生變化。 – 2013-02-14 00:09:45

+0

用於動畫折線路線https://github.com/amalChandran/google-maps-route-animation – amalBit 2017-01-13 05:06:38

回答

47

一些谷歌工程師們提供了一個很好的演示視頻有關如何從起點動畫標記到終點,所有的各種版本的Android的一些優雅的示例代碼:

相關的代碼是在這裏:

https://gist.github.com/broady/6314689

這是一個很好的演示視頻,

http://youtu.be/WKfZsCKSXVQ

OLD DEPRECATED回答以下

在文檔中提到,標記圖標不能改變:

圖標

在隨即出現的位圖爲標記。如果圖標未設置,則顯示默認圖標。您可以使用defaultMarker(float)指定默認圖標的替代顏色。 創建標記後,無法更改圖標。

Google Maps API v2 Documentation

你將不得不跟蹤特定的標記,可能使用類似於這裏所描述的方法:Link a Marker to an Object,然後找出哪些標記需要更新。在標記上調用.remove(),然後根據所需的「方向」創建一個旋轉的圖像,使用該圖像創建一個新標記,然後將新標記添加到地圖。

您不需要「清除」地圖,只需刪除要修改的標記,創建一個新標記,然後將其添加回地圖。

不幸的是,新的Maps API還不夠靈活。希望谷歌繼續改進它。

+1

這是一個答案?我真的不知道它是如何回答如何動畫標記運動的...... – Ted 2013-12-14 12:39:38

+0

這是一個答案,因爲在提問時沒有辦法讓標記動畫化。如果您可以提供動畫標記的動畫,請自行回答問題。 – DiscDev 2013-12-16 15:28:40

+0

@Ted - 我做了一些搜索,發現了一個「真實」的答案並更新了我的帖子。看看上面的內容,它非常簡潔易懂。 – DiscDev 2013-12-20 17:25:42

5

標記具有API v2修訂版7中新增的新功能。 Marker.setIcon,所以你可以使用多個圖標來顯示方向。

+2

你有沒有用setIcon試過動畫?在我的情況下,有時眨眼不好(太快或太慢)... – mrroboaat 2013-10-22 14:31:39

+0

@aat我知道它仍然存在問題。畢竟它是IPC電話。也許Googlers可以添加像iOS一樣的真實動畫支持。 – 2013-10-22 15:31:02

+0

肯定同意 – mrroboaat 2013-10-22 15:35:54

3

用法示例DiscDev's ansrwer(上圖):

LatLng fromLocation = new LatLng(38.5, -100.4); // Whatever origin coordinates 
LatLng toLocation = new LatLng(37.7, -107.7); // Whatever destination coordinates 
Marker marker = mMap.addMarker(new MarkerOptions().position(firstLocation)); 
MarkerAnimation.animateMarkerToICS(marker, toLocation, new LatLngInterpolator.Spherical()); 

而對於那些你們誰使用GPS /或接收位置更新的任何位置提供者:

Marker ourGlobalMarker; 
// We've got a location from some provider of ours, now we can call: 
private void updateMarkerPosition(Location newLocation) { 

    LatLng newLatLng = new LatLng(newLocation.getLatitude(), newLocation.getLongitude()); 

    if(ourGlobalMarker == null) { // First time adding marker to map 
     ourGlobalMarker = mMap.addMarker(new MarkerOptions().position(newLatLng)); 
    } 
    else { 
     MarkerAnimation.animateMarkerToICS(ourGlobalMarker, newLatLng, new LatLngInterpolator.Spherical()); 
    }   
} 

重要:

1MarkerAnimation.java如果動畫durat ion設置爲X, ,並且您正在以小於X的速率接收位置更新,將運行多個動畫,並且您可能會看到標記閃爍。

爲了避免這種情況,animationMarkerToICS方法(我把這裏animationMarkerToICS爲例),應該是這個樣子,

全面的方法實現:

private static Animator animator; // MAKING ANIMATOR GLOBAL INSTEAD OF LOCAL TO THE STATIC FUNCTION 

... 

// Ice Cream Sandwich compatible 
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 
public static void animateMarkerToICS(Marker marker, LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { 

    TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() { 
     @Override 
     public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { 
      return latLngInterpolator.interpolate(fraction, startValue, endValue); 
     } 
    }; 
    Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position"); 

    // ADD THIS TO STOP ANIMATION IF ALREADY ANIMATING TO AN OBSOLETE LOCATION 
    if(animator != null && animator.isRunning()) { 
     animator.cancel(); 
     animator = null; 
    } 
    animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, finalPosition); 
    animator.setDuration((long) ANIMATION_DURATION); 
    animator.start(); 
} 

享受。

+0

我們如何設置縮放級別? – Sophie 2017-09-06 16:30:03

+0

縮放與此問題無關,請查看[這裏](https://stackoverflow.com/questions/13932441/android-google-maps-v2-set-zoom-level-for-mylocation)以獲取縮放 – Mercury 2017-09-07 06:54:18

0
//Your code   
    double bearing = 0.0; 
      bearing = getBearing(new LatLng(
               currentPosition.latitude 
               ,currentPosition.longitude), 
             new LatLng(
               nextPosition.latitude, 
               nextPosition.longitude)); 

      bearing -= 90; 
          CameraPosition cameraPosition = new CameraPosition 
            .Builder() 
            .target(new LatLng(nextPosition.latitude, nextPosition.longitude)) 
            .bearing((float) bearing) 
            .zoom(ZOOM_LEVEL).build(); 


          mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 5000, null); 

       animatedMarker(currentPosition,nextPosition,busMarker); 



       //Method for finding bearing between two points 
        private float getBearing(LatLng begin, LatLng end) { 
         double lat = Math.abs(begin.latitude - end.latitude); 
         double lng = Math.abs(begin.longitude - end.longitude); 
         if (begin.latitude < end.latitude && begin.longitude < end.longitude) 
          return (float) (Math.toDegrees(Math.atan(lng/lat))); 
         else if (begin.latitude >= end.latitude && begin.longitude < end.longitude) 
          return (float) ((90 - Math.toDegrees(Math.atan(lng/lat))) + 90); 
         else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude) 
          return (float) (Math.toDegrees(Math.atan(lng/lat)) + 180); 
         else if (begin.latitude < end.latitude && begin.longitude >= end.longitude) 
          return (float) ((90 - Math.toDegrees(Math.atan(lng/lat))) + 270); 
         return -1; 
        } 

    private void animatedMarker(final LatLng startPosition,final LatLng nextPosition,final Marker mMarker) 
    { 

     final Handler handler = new Handler(); 
     final long start = SystemClock.uptimeMillis(); 
     final Interpolator interpolator = new AccelerateDecelerateInterpolator(); 
     final float durationInMs = 3000; 
     final boolean hideMarker = false; 

     handler.post(new Runnable() { 
      long elapsed; 
      float t; 
      float v; 

      @Override 
      public void run() { 
       // Calculate progress using interpolator 
       elapsed = SystemClock.uptimeMillis() - start; 
       t = elapsed/durationInMs; 
       v = interpolator.getInterpolation(t); 

       LatLng currentPosition = new LatLng(
         startPosition.latitude * (1 - t) + nextPosition.latitude * t, 
         startPosition.longitude * (1 - t) + nextPosition.longitude * t); 

       mMarker.setPosition(currentPosition); 

       // Repeat till progress is complete. 
       if (t < 1) { 
        // Post again 16ms later. 
        handler.postDelayed(this, 16); 
       } else { 
        if (hideMarker) { 
         mMarker.setVisible(false); 
        } else { 
         mMarker.setVisible(true); 
        } 
       } 
      } 
     }); 

    } 
相關問題