如何通过 LatLng 点的 ArrayList 为标记设置动画? [英] How to animate a marker through an ArrayList of LatLng points?

查看:24
本文介绍了如何通过 LatLng 点的 ArrayList 为标记设置动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Google Maps API V2 获取当前用户的位置,并使用 onLocationChanged 侦听器记录他的路线.当用户记录他们的路线时,我将在每个位置更改处检测到的所有 LatLngs 保存在一个数组列表中.当用户停止记录他们的路线时,我会在数组列表的第一个点放置一个标记.我现在的问题是我希望通过数组列表中的所有点为标记设置动画.有人可以告诉我我该怎么做吗?

需要注意的是数组不需要排序,因为我记录了它们来的点.我曾尝试使用 for 循环来循环遍历数组并发送值,但我从

收到错误<块引用>

final LatLng startLatLng = proj.fromScreenLocation(startPoint);

说未知来源"以及 NullPointer 异常.

这是我的代码:

case R.id.action_replay:进入;for(o=0; o<oldlocPoints.size();++o){if(--o > 1){lastPos = oldlocPoints.get(--o);}toPos = oldlocPoints.get(++o);animateMarker(markerStart, lastPos, toPos);}返回真;

这就是我尝试通过标记设置动画的方式.我遇到的主要困难是在 run() 中它似乎只想要 Final 类型值,所以我不知道如何取悦它.

//通过从记录路线中保存的位置动画标记public void animateMarker(最终标记标记,LatLng lastPos,最终LatLng toPos){最后的长持续时间 = 1600;final Handler handler = new Handler();this.lastPos = lastPos;this.toPos = toPos;最后的长启动 = SystemClock.uptimeMillis();最终输入 o;投影项目 = map.getProjection();点 startPoint = proj.toScreenLocation(lastPos);final LatLng startLatLng = proj.fromScreenLocation(startPoint);Log.d(TAG, "" + lastPos + "" + toPos);最终插值器插值器 = 新的 AccelerateDecelerateInterpolator();handler.post(new Runnable() {@覆盖公共无效运行(){long elapsed = SystemClock.uptimeMillis() - 开始;float t = interpolator.getInterpolation((float) elapsed/duration);double lng = t * toPos.longitude + (1 - t) * startLatLng.longitude;double lat = t * toPos.latitude + (1 - t) * startLatLng.latitude;markerStart.setPosition(new LatLng(lat, lng));//markerStart.setPosition(interpolator.interpolate(t, target, replayEnd));如果 (t <1.0) {//16 毫秒后再次发布 == 每秒 60 帧handler.postDelayed(this, 32);} 别的 {//动画结束}}});}

有人可以帮我吗?

更新我迄今为止最接近的尝试是:

while (i

解决方案

试试这个代码 ::首先是 MarkerAnimation 类:

公共类 MarkerAnimation {静态 GoogleMap 地图;ArrayList_trips = new ArrayList<>();标记_marker;LatLngInterpolator _latLngInterpolator = new LatLngInterpolator.Spherical();public void animateLine(ArrayList Trips,GoogleMap map,Marker marker,Context current){_trips.addAll(旅行);_marker = 标记;动画标记();}公共无效animateMarker(){TypeEvaluatortypeEvaluator = new TypeEvaluator() {@覆盖公共 LatLng 评估(浮动分数,LatLng startValue,LatLng endValue){返回 _latLngInterpolator.interpolate(fraction, startValue, endValue);}};属性<Marker, LatLng>property = Property.of(Marker.class, LatLng.class, "position");ObjectAnimator animator = ObjectAnimator.ofObject(_marker, property, typeEvaluator, _trips.get(0));//ObjectAnimator animator = ObjectAnimator.o(view, "alpha", 0.0f);animator.addListener(new Animator.AnimatorListener() {@覆盖public void onAnimationCancel(Animator animation) {//animDrawable.stop();}@覆盖公共无效onAnimationRepeat(动画师动画){//animDrawable.stop();}@覆盖公共无效onAnimationStart(动画师动画){//animDrawable.stop();}@覆盖公共无效 onAnimationEnd(动画师动画){//animDrawable.stop();如果 (_trips.size() > 1) {_trips.remove(0);动画标记();}}});animator.setDuration(300);动画师开始();}

以及 _latLngInterpolator 是由谷歌开发人员预先编写的:

公共接口 LatLngInterpolator {公共 LatLng 插值(浮动分数,LatLng a,LatLng b);公共类 Spherical 实现 LatLngInterpolator {@覆盖公共 LatLng 插值(浮动分数,LatLng 来自,LatLng 到){//http://en.wikipedia.org/wiki/Slerpdouble fromLat = toRadians(from.latitude);double fromLng = toRadians(from.longitude);double toLat = toRadians(to.latitude);double toLng = toRadians(to.longitude);双 cosFromLat = cos(fromLat);双 cosToLat = cos(toLat);//计算球面插值系数.双角 = computeAngleBetween(fromLat, fromLng, toLat, toLng);双sinAngle = sin(角度);如果 (sinAngle < 1E-6) {返回;}double a = sin((1 - 分数) * 角度)/sinAngle;双 b = sin(分数 * 角度)/sinAngle;//从极坐标转换为矢量并进行插值.double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng);double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng);double z = a * sin(fromLat) + b * sin(toLat);//将插值向量转换回极坐标.双纬度 = atan2(z, sqrt(x * x + y * y));双 lng = atan2(y, x);return new LatLng(toDegrees(lat), toDegrees(lng));}私人双computeAngleBetween(双fromLat,双fromLng,双toLat,双toLng){//半正弦公式双 dLat = fromLat - toLat;双 dLng = fromLng - toLng;返回 2 * asin(sqrt(pow(sin(dLat/2), 2) +cos(fromLat) * cos(toLat) * pow(sin(dLng/2), 2)));}}}

并在您的地图活动中将其称为:

 MarkerAnimation.animateLine(TripPoints,map,MovingMarker,context);

I am using Google Maps API V2 to get the location of the current user and am recording his route by using the onLocationChanged listener. While the user records their route I save all the LatLngs detected at each location change in an arraylist. When the user stops recording their route I place a marker at the first point in the arraylist. My problem now is that I wish to animate the marker through all the points in the arraylist. Can someone please tell me how can I do this?

Things to note is that the array doesn't need sorting because I record the points as they come. I have tried using a for loop to cycle through the array and send the values over but I get an error from the

final LatLng startLatLng = proj.fromScreenLocation(startPoint);

saying "Unknown Source" along with a NullPointer exception.

Here is my code:

case R.id.action_replay:

            int o;

            for(o=0; o<oldlocPoints.size(); ++o){

                if(--o > 1){lastPos = oldlocPoints.get(--o);}
                toPos = oldlocPoints.get(++o);

                animateMarker(markerStart, lastPos, toPos);
            }
 return true;

And this is How I try to animate through the markers. The main difficulty I am encountering is that in run() it only seems to want Final type values so I have no idea how to please it.

    //Animates marker through the locations saved from the recorded route
public void animateMarker(final Marker marker, LatLng lastPos, final LatLng toPos) {
    final long duration = 1600;
    final Handler handler = new Handler();
    this.lastPos = lastPos;
    this.toPos = toPos;
    final long start = SystemClock.uptimeMillis();
    final int o;

    Projection proj = map.getProjection();
    Point startPoint = proj.toScreenLocation(lastPos);
    final LatLng startLatLng = proj.fromScreenLocation(startPoint);

    Log.d(TAG, "" + lastPos + "" + toPos);

    final Interpolator interpolator = new AccelerateDecelerateInterpolator();
    handler.post(new Runnable() {
        @Override
        public void run() {

            long elapsed = SystemClock.uptimeMillis() - start;
            float t = interpolator.getInterpolation((float) elapsed / duration);
            double lng = t * toPos.longitude + (1 - t) * startLatLng.longitude;
            double lat = t * toPos.latitude + (1 - t) * startLatLng.latitude;
            markerStart.setPosition(new LatLng(lat, lng));
            //markerStart.setPosition(interpolator.interpolate(t, target, replayEnd));
            if (t < 1.0) {
                //Post again 16ms later == 60 frames per second
                handler.postDelayed(this, 32);
            } else {
                //Animation ended
            }
        }
    });
}

Can someone please help me?

UPDATE My closest attempt to date is this:

while (i<oldlocPoints.size()){


                final long duration = 32;
                final Handler handler = new Handler();
                final long start = SystemClock.uptimeMillis();
                Projection proj = map.getProjection();
                final LatLng toPos = oldlocPoints.get(i/3);

                Point startPoint = proj.toScreenLocation(oldlocPoints.get(i));
                final LatLng startLatLng = proj.fromScreenLocation(startPoint);

                final Interpolator interpolator = new AccelerateDecelerateInterpolator();
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        long elapsed = SystemClock.uptimeMillis() - start;
                        float t = interpolator.getInterpolation((float) elapsed / duration);
                        double lng = t * toPos.longitude + (1 - t) * startLatLng.longitude;
                        double lat = t * toPos.latitude + (1 - t) * startLatLng.latitude;
                        markerStart.setPosition(new LatLng(lat, lng));
                        //markerStart.setPosition(interpolator.interpolate(t, target, replayEnd));
                        if (t < 1.0) {
                            //Post again 16ms later == 60 frames per second
                            handler.postDelayed(this, 32);
                        } else {
                            //Animation ended
                        }
                    }
                });

                i++;
            }

解决方案

try this code :: first the MarkerAnimation class :

public class MarkerAnimation {
    static GoogleMap map;
    ArrayList<LatLng> _trips = new ArrayList<>() ;
    Marker _marker;
    LatLngInterpolator _latLngInterpolator = new LatLngInterpolator.Spherical();

public void animateLine(ArrayList<LatLng> Trips,GoogleMap map,Marker marker,Context current){
    _trips.addAll(Trips);
    _marker = marker;

    animateMarker();
}


        public void animateMarker() {
            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");

            ObjectAnimator animator = ObjectAnimator.ofObject(_marker, property, typeEvaluator, _trips.get(0));

            //ObjectAnimator animator = ObjectAnimator.o(view, "alpha", 0.0f);
            animator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationCancel(Animator animation) {
                    //  animDrawable.stop();
                }

                @Override
                public void onAnimationRepeat(Animator animation) {
                    //  animDrawable.stop();
                }

                @Override
                public void onAnimationStart(Animator animation) {
                    //  animDrawable.stop();
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    //  animDrawable.stop();
                    if (_trips.size() > 1) {
                        _trips.remove(0);
                        animateMarker();
                    }
                }
            });

            animator.setDuration(300);
            animator.start();
        } 

and the _latLngInterpolator which is pre-written for you by google developers :

public interface LatLngInterpolator {
    public LatLng interpolate(float fraction, LatLng a, LatLng b);

    public class Spherical implements LatLngInterpolator {
        @Override
        public LatLng interpolate(float fraction, LatLng from, LatLng to) {
            // http://en.wikipedia.org/wiki/Slerp
            double fromLat = toRadians(from.latitude);
            double fromLng = toRadians(from.longitude);
            double toLat = toRadians(to.latitude);
            double toLng = toRadians(to.longitude);
            double cosFromLat = cos(fromLat);
            double cosToLat = cos(toLat);

            // Computes Spherical interpolation coefficients.
            double angle = computeAngleBetween(fromLat, fromLng, toLat, toLng);
            double sinAngle = sin(angle);
            if (sinAngle < 1E-6) {
                return from;
            }
            double a = sin((1 - fraction) * angle) / sinAngle;
            double b = sin(fraction * angle) / sinAngle;

            // Converts from polar to vector and interpolate.
            double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng);
            double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng);
            double z = a * sin(fromLat) + b * sin(toLat);

            // Converts interpolated vector back to polar.
            double lat = atan2(z, sqrt(x * x + y * y));
            double lng = atan2(y, x);
            return new LatLng(toDegrees(lat), toDegrees(lng));
        }

        private double computeAngleBetween(double fromLat, double fromLng, double toLat, double toLng) {
            // Haversine's formula
            double dLat = fromLat - toLat;
            double dLng = fromLng - toLng;
            return 2 * asin(sqrt(pow(sin(dLat / 2), 2) +
                    cos(fromLat) * cos(toLat) * pow(sin(dLng / 2), 2)));
        }
    }
}

and call it on your map activity as :

 MarkerAnimation.animateLine(TripPoints,map,MovingMarker,context); 

这篇关于如何通过 LatLng 点的 ArrayList 为标记设置动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆