Google Maps-制作类似抓取应用程序的动画以显示路径方向 [英] Google Maps - making an animation like grab app to show the path direction
问题描述
我想制作一个动画,该动画在路径上做一个移动标记.
I would like to make an animation which does a moving marker along a path.
因此,我考虑了如何使用比路径线稍暗的标记来执行此操作.并非常缓慢地移除和更新其位置,以使其看起来像是在移动.但我只是不认为这就是视频中发生的情况.因为市场完全构成了路径的形状.它流动完美.
so i thought about how to do this using a marker that is slightly darker than the path line. and removing and updating its position very slowly so that it looks like its moving. but i just don't think that's what's happening in the video. because the market takes on the shape of the path entirely. it flows perfectly.
这是我到目前为止所拥有的:
here is what i have so far:
fun showLineAtUsersLocation(loc_destination: LatLng) {
val currentLoc = activity.getCachedCurrentLoc()
val pattern = Arrays.asList(Dash(), Gap(convertDpToPixel(6).toFloat()))
val polyLineOptions: PolylineOptions = PolylineOptions()
.add(currentLoc)
.add(loc_destination)
.geodesic(true)
.pattern(pattern)
.width(convertDpToPixel(8).toFloat())
googleMap.addPolyline(polyLineOptions)
}
但这只是显示从一个点到另一个点的覆盖线.并没有真正走这条路.我应该找什么呢?
but this is just showing an overlay line from one point to the other. not really following a path. What should i be looking for instead?
我看到ios具有一个适用于此GMSStyleSpan的类处理图片.但我找不到在android中的等效项.我没有看到span类或style类,对此我可以参考任何想法吗?甚至在标记上甚至带有AnomatedVectorDrawable
I saw that ios has a has a class good for this GMSStyleSpan to manipuate the image. but i cannot find the equivalent in android. i dont see a span class or style class i can get a reference to any ideas on this ? or even with AnomatedVectorDrawable on the marker instead
推荐答案
对于此类(实际上是任何一种)动画,您可以使用View Canvas动画.这种方法需要基于 MapView
- 自定义视图,它实现了:
For such (and actually any kind of) animation you can use View Canvas animation. This approach requires MapView
-based custom view, that implements:
-
在MapView画布上绘制;
drawing over the MapView canvas;
自定义线条样式(用圆圈代替简单的线条);
customizing line styles (circles instead of a simple line);
地图纬度/经度坐标的绑定路径
binding path to Lat/Lon coordinates of map
执行动画.
在MapView上绘制需要覆盖dispatchDraw()
.自定义线条样式需要 setPathEffect()
Paint
类的a>方法,该方法可为圆形图章"(以像素为单位),它将重复每个前进"(也以像素为单位),类似于:
Drawing over the MapView needs to override dispatchDraw()
. Customizing line styles needs setPathEffect()
method of Paint
class that allows to create create path for "circle stamp" (in pixels), which will repeated every "advance" (in pixels too), something like that:
mCircleStampPath = new Path();
mCircleStampPath.addCircle(0,0, CIRCLE_RADIUS, Path.Direction.CCW);
mCircleStampPath.close();
用于将屏幕上的路径绑定到纬度/经度坐标 GoogleMap
对象,因此自定义视图应实现OnMapReadyCallback
来接收它.对于连续动画,可以使用 postInvalidateDelayed()
.因此,使用基于MapView
的自定义EnhancedMapView
的完整源代码:
For binding path on screen to Lat/Lon coordinates Projection.toScreenLocation()
needed, that requires GoogleMap
object so custom view should implements OnMapReadyCallback
for receive it. For continuous animation postInvalidateDelayed()
can be used. So, with full source code of MapView
-based custom EnhancedMapView
:
public class EnhancedMapView extends MapView implements OnMapReadyCallback {
private static final float CIRCLE_RADIUS = 10;
private static final float CIRCLE_ADVANCE = 3.5f * CIRCLE_RADIUS; // spacing between each circle stamp
private static final int FRAMES_PER_SECOND = 30;
private OnMapReadyCallback mMapReadyCallback;
private GoogleMap mGoogleMap;
private LatLng mPointA;
private LatLng mPointB;
private float mCirclePhase = 0; // amount to offset before the first circle is stamped
private Path mCircleStampPath;
private Paint mPaintLine;
private final Path mPathFromAtoB = new Path();
public EnhancedMapView(@NonNull Context context) {
super(context);
init();
}
public EnhancedMapView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public EnhancedMapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public EnhancedMapView(@NonNull Context context, @Nullable GoogleMapOptions options) {
super(context, options);
init();
}
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
drawLineFomAtoB(canvas);
canvas.restore();
// perform continuous animation
postInvalidateDelayed(1000 / FRAMES_PER_SECOND);
}
private void drawLineFomAtoB(Canvas canvas) {
if (mGoogleMap == null || mPointA == null || mPointB == null) {
return;
}
final Projection mapProjection = mGoogleMap.getProjection();
final Point pointA = mapProjection.toScreenLocation(mPointA);
final Point pointB = mapProjection.toScreenLocation(mPointB);
mPathFromAtoB.rewind();
mPathFromAtoB.moveTo(pointB.x, pointB.y);
mPathFromAtoB.lineTo(pointA.x, pointA.y);
// change phase for circles shift
mCirclePhase = (mCirclePhase < CIRCLE_ADVANCE)
? mCirclePhase + 1.0f
: 0;
mPaintLine.setPathEffect(new PathDashPathEffect(mCircleStampPath, CIRCLE_ADVANCE, mCirclePhase, PathDashPathEffect.Style.ROTATE));
canvas.drawPath(mPathFromAtoB, mPaintLine);
}
private void init() {
setWillNotDraw(false);
mCircleStampPath = new Path();
mCircleStampPath.addCircle(0,0, CIRCLE_RADIUS, Path.Direction.CCW);
mCircleStampPath.close();
mPaintLine = new Paint();
mPaintLine.setColor(Color.BLACK);
mPaintLine.setStrokeWidth(1);
mPaintLine.setStyle(Paint.Style.STROKE);
mPaintLine.setPathEffect(new PathDashPathEffect(mCircleStampPath, CIRCLE_ADVANCE, mCirclePhase, PathDashPathEffect.Style.ROTATE));
postInvalidate();
}
@Override
public void getMapAsync(OnMapReadyCallback callback) {
mMapReadyCallback = callback;
super.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
invalidate();
}
});
if (mMapReadyCallback != null) {
mMapReadyCallback.onMapReady(googleMap);
}
}
public void setPoints(LatLng pointA, LatLng pointB) {
mPointA = pointA;
mPointB = pointB;
}
}
MainActivity
喜欢:
public class MainActivity extends AppCompatActivity {
private static final String MAP_VIEW_BUNDLE_KEY = "MapViewBundleKey";
static final LatLng MAIDAN = new LatLng(50.450891, 30.522843);
static final LatLng SOPHIA = new LatLng(50.452967, 30.514498);
static final LatLng INITIAL_MAP_CENTER = new LatLng(50.452011, 30.518766);
static final int INITIAL_ZOOM = 15;
private GoogleMap mGoogleMap;
private EnhancedMapView mMapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAP_VIEW_BUNDLE_KEY);
}
mMapView = (EnhancedMapView) findViewById(R.id.mapview);
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mMapView.setPoints(MAIDAN, SOPHIA);
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(INITIAL_MAP_CENTER, INITIAL_ZOOM));
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle mapViewBundle = outState.getBundle(MAP_VIEW_BUNDLE_KEY);
if (mapViewBundle == null) {
mapViewBundle = new Bundle();
outState.putBundle(MAP_VIEW_BUNDLE_KEY, mapViewBundle);
}
mMapView.onSaveInstanceState(mapViewBundle);
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}
@Override
protected void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
}
和activity_main.xml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.test.just.googlemapsgeneral.views.EnhancedMapView
android:id="@+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</RelativeLayout>
您得到类似的东西:
NB!您应该使用 Path
而不是绘制线条.那只是方法,而不是完整的解决方案.
NB! You should use Path
instead of drawing lines. And that is just approach, not complete solution.
这篇关于Google Maps-制作类似抓取应用程序的动画以显示路径方向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!