背景
之前似乎已经在 SO 上提出了许多类似的问题(最值得注意的是android google maps 在使用 GoogleMap.AnimateCamera() 时未加载地图以及如何在 Android 中顺利平移 GoogleMap?),但没有一个答案或评论自始至终发布这些线程让我对如何做到这一点有了一个坚定的想法。
我最初认为它会像调用一样简单,animateCamera(CameraUpdateFactory.newLatLng(), duration, callback)
但就像上面第一个链接的 OP 一样,我得到的只是一个灰色或非常模糊的地图,直到动画完成,即使我把它放慢到几十秒长!
我设法找到并实现了这个帮助程序类,它可以很好地允许瓷砖沿途渲染,但即使延迟为 0,每个动画之间也存在明显的延迟。
代码
好的,是时候写一些代码了。这是(稍作修改的)助手类:
package com.coopmeisterfresh.googlemaps.NativeModules;
import android.os.Handler;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.GoogleMap;
import java.util.ArrayList;
import java.util.List;
public class CameraUpdateAnimator implements GoogleMap.OnCameraIdleListener {
private final GoogleMap mMap;
private final GoogleMap.OnCameraIdleListener mOnCameraIdleListener;
private final List<Animation> cameraUpdates = new ArrayList<>();
public CameraUpdateAnimator(GoogleMap map, GoogleMap.
OnCameraIdleListener onCameraIdleListener) {
mMap = map;
mOnCameraIdleListener = onCameraIdleListener;
}
public void add(CameraUpdate cameraUpdate, boolean animate, long delay) {
if (cameraUpdate != null) {
cameraUpdates.add(new Animation(cameraUpdate, animate, delay));
}
}
public void clear() {
cameraUpdates.clear();
}
public void execute() {
mMap.setOnCameraIdleListener(this);
executeNext();
}
private void executeNext() {
if (cameraUpdates.isEmpty()) {
mOnCameraIdleListener.onCameraIdle();
} else {
final Animation animation = cameraUpdates.remove(0);
new Handler().postDelayed(() -> {
if (animation.mAnimate) {
mMap.animateCamera(animation.mCameraUpdate);
} else {
mMap.moveCamera(animation.mCameraUpdate);
}
}, animation.mDelay);
}
}
@Override
public void onCameraIdle() {
executeNext();
}
private static class Animation {
private final CameraUpdate mCameraUpdate;
private final boolean mAnimate;
private final long mDelay;
public Animation(CameraUpdate cameraUpdate, boolean animate, long delay) {
mCameraUpdate = cameraUpdate;
mAnimate = animate;
mDelay = delay;
}
}
}
以及我实现它的代码:
// This is actually a React Native Component class, but I doubt that should matter...?
public class NativeGoogleMap extends SimpleViewManager<MapView> implements
OnMapReadyCallback, OnRequestPermissionsResultCallback {
// ...Other unrelated methods removed for brevity
private void animateCameraToPosition(LatLng targetLatLng, float targetZoom) {
// googleMap is my GoogleMap instance variable; it
// gets properly initialised in another class method
CameraPosition currPosition = googleMap.getCameraPosition();
LatLng currLatLng = currPosition.target;
float currZoom = currPosition.zoom;
double latDelta = targetLatLng.latitude - currLatLng.latitude;
double lngDelta = targetLatLng.longitude - currLatLng.longitude;
double latInc = latDelta / 5;
double lngInc = lngDelta / 5;
float zoomInc = 0;
float minZoom = googleMap.getMinZoomLevel();
float maxZoom = googleMap.getMaxZoomLevel();
if (lngInc > 15 && currZoom > minZoom) {
zoomInc = (minZoom - currZoom) / 5;
}
CameraUpdateAnimator animator = new CameraUpdateAnimator(googleMap,
() -> googleMap.animateCamera(CameraUpdateFactory.zoomTo(
targetZoom), 5000, null));
for (double nextLat = currLatLng.latitude, nextLng = currLatLng.
longitude, nextZoom = currZoom; Math.abs(nextLng) < Math.abs(
targetLatLng.longitude);) {
nextLat += latInc;
nextLng += lngInc;
nextZoom += zoomInc;
animator.add(CameraUpdateFactory.newLatLngZoom(new
LatLng(nextLat, nextLng), (float)nextZoom), true);
}
animator.execute();
}
}
问题
有没有更好的方法来完成这个看似简单的任务?我在想也许我需要将我的动画移动到工作线程或其他东西;那会有帮助吗?
感谢阅读(我知道这是一个努力:P)!
2021 年 9 月 30 日更新
我已经根据 Andy 在评论中的建议更新了上面的代码,虽然它可以工作(尽管有相同的滞后和渲染问题),但最终的算法需要更复杂一些,因为我想缩小到纵向三角洲的中途点,然后随着旅程的继续返回。
一次完成所有这些计算,同时平滑地渲染所有必要的图块,对于我正在测试的廉价手机来说似乎太过分了。或者这是 API 本身的限制?无论如何,我怎样才能让所有这些工作顺利进行,而队列动画之间没有任何延迟?