首页 文章

在Google Map v2上制作动画标记

提问于
浏览
26

使用v2 API在Google Map 上制作标记动画的最佳方法是什么?

我正在开发一个以 Map 为中心的游戏,我在这里跟踪人物的位置并在 Map 上显示它们以供彼此查看 . 随着人们的移动,我想要将一个标记从他当前的动态设置为最新的位置 . 每个人都有方向,所以我需要适当地旋转标记 .

使用新版Google Maps API的最佳方法是什么?

4 回答

  • 53

    Usage Example for DiscDev's answer(上图):

    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());
        }         
    }
    

    IMPORTANT:

    1MarkerAnimation.java 内如果动画持续时间设置为X,并且您以小于X的速率接收位置更新,则将触发多个动画,并且您可能会看到标记动画稍微闪烁(这不是一个很好的用户体验) .

    为了避免这种情况, animationMarkerToICS 方法(例如我在这里 animationMarkerToICS )应该看起来像这样,

    full method implementation:

    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

    从v2的rev.7开始,Marker添加了一个新功能 . Marker.setIcon,这样您就可以使用多个图标来显示方向 .

  • 5
    //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);
                        }
                    }
                }
            });
    
        }
    
  • 6

    对于所有不同版本的Android,一些Google工程师提供了一个很好的演示视频,其中包含一些关于如何为起点到终点设置标记动画的优雅示例代码:

    相关代码在这里:

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

    还有一个很好的演示视频,其中包含了所有这些视频 .

    http://youtu.be/WKfZsCKSXVQ

    OLD DEPRECATED ANSWER BELOW

    在文档中,提到标记图标无法更改:

    图标为标记显示的位图 . 如果未设置图标,则会显示默认图标 . 您可以使用defaultMarker(float)指定默认图标的替代着色 . 创建标记后,无法更改图标 .

    Google Maps API v2 Documentation

    您将不得不跟踪特定标记,可能使用类似于此处描述的方法:Link a Marker to an Object,然后确定需要更新的标记 . 在标记上调用 .remove() ,然后根据所需的"direction"创建旋转图像,使用该图像创建新标记,并将新标记添加到 Map 中 .

    您无需“清除” Map ,只需删除要修改的标记,创建一个新标记,然后将其添加回 Map .

    不幸的是,新的Maps API还不是很灵活 . 希望Google继续改进它 .

相关问题