M.Y*_*ran 0 android google-maps marker
这可能是一个愚蠢的问题,但我找不到任何解决方案,以前关于这个问题的答案现在让我发布我的问题,我需要在谷歌地图标记中的圆形图像周围产生涟漪效应,现在让我发布我迄今为止尝试过的内容:
@Override
public void onLocationChanged(final Location location) {
mLastLocation=location;
GradientDrawable d = new GradientDrawable();
d.setShape(GradientDrawable.OVAL);
d.setSize(500,500);
d.setColor(0x555751FF);
d.setStroke(5, Color.TRANSPARENT);
Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth()
, d.getIntrinsicHeight()
, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
d.draw(canvas);
final int radius = 100;
final GroundOverlay circle = mMap.addGroundOverlay(new GroundOverlayOptions()
.position(new LatLng(location.getLatitude(),location.getLongitude()), 2 * radius).image(BitmapDescriptorFactory.fromBitmap(createMarker(TrackingActivity.this,new LatLng(location.getLatitude(),location.getLongitude())))));
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.setIntValues(0, radius);
valueAnimator.setDuration(3000);
valueAnimator.setEvaluator(new IntEvaluator());
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float animatedFraction = valueAnimator.getAnimatedFraction();
circle.setTransparency(animatedFraction);
// circle.setDimensions(animatedFraction * radius * 2);
}
});
valueAnimator.start();
// mMap.addMarker(new MarkerOptions().position(new LatLng(location.getLatitude(),location.getLongitude())).icon(BitmapDescriptorFactory.fromBitmap(createMarker(this,new LatLng(location.getLatitude(),location.getLongitude())))));
closeDialog();
public Bitmap createMarker(Context context, LatLng point) {
int px = context.getResources().getDimensionPixelSize(R.dimen.map_marker_diameter);
View markerView = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.circle_imgview, null);
markerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
markerView.layout(0, 0, px, px);
markerView.buildDrawingCache();
CircleImageView bedNumberTextView = markerView.findViewById(R.id.circleimg);
Bitmap mDotMarkerBitmap = Bitmap.createBitmap(px, px, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mDotMarkerBitmap);
Picasso.with(this).load("https://fww").into(bedNumberTextView);
markerView.draw(canvas);
return mDotMarkerBitmap;
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码使我的整个圆形图像产生涟漪,但我只想在我的圆形图像周围产生涟漪,我该如何实现这一点。即使我尝试使用第三方涟漪动画并将我的图像包裹在该动画中,但它无法实现我如何实现这个朋友。提前致谢!!
试试这个代码。它很容易实现。我希望此代码对您有所帮助。
MapRipple.class
public class MapRipple {
private GoogleMap mGoogleMap;
private LatLng mLatLng, mPrevLatLng;
private BitmapDescriptor mBackgroundImageDescriptor;
private float mTransparency = 0.5f;
private volatile double mDistance = 100;
private int mNumberOfRipples = 1;
private int mFillColor = Color.TRANSPARENT;
private int mStrokeColor = Color.BLACK;
private int mStrokeWidth = 5;
private long mDurationBetweenTwoRipples = 1000;
private long mRippleDuration = 2000;
private ValueAnimator mAnimators[];
private Handler mHandlers[];
private GroundOverlay mGroundOverlays[];
private GradientDrawable mBackground;
private boolean isAnimationRunning = false;
public MapRipple(GoogleMap googleMap, LatLng latLng, Context context) {
mGoogleMap = googleMap;
mLatLng = latLng;
mPrevLatLng = latLng;
mBackground = (GradientDrawable) ContextCompat.getDrawable(context, R.drawable.map_background);
mAnimators = new ValueAnimator[4];
mHandlers = new Handler[4];
mGroundOverlays = new GroundOverlay[4];
}
public MapRipple withTransparency(float transparency) {
mTransparency = transparency;
return this;
}
public MapRipple withDistance(double distance) {
mDistance = distance;
return this;
}
public MapRipple withLatLng(LatLng latLng) {
mPrevLatLng = mLatLng;
mLatLng = latLng;
return this;
}
public MapRipple withNumberOfRipples(int numberOfRipples) {
if (numberOfRipples > 4 || numberOfRipples < 1) {
numberOfRipples = 4;
}
mNumberOfRipples = numberOfRipples;
return this;
}
public MapRipple withFillColor(int fillColor) {
mFillColor = fillColor;
return this;
}
public MapRipple withStrokeColor(int strokeColor) {
mStrokeColor = strokeColor;
return this;
}
@Deprecated
public void withStrokewidth(int strokeWidth) {
mStrokeWidth = strokeWidth;
}
public MapRipple withStrokeWidth(int strokeWidth) {
mStrokeWidth = strokeWidth;
return this;
}
public MapRipple withDurationBetweenTwoRipples(long durationBetweenTwoRipples) {
mDurationBetweenTwoRipples = durationBetweenTwoRipples;
return this;
}
public boolean isAnimationRunning() {
return isAnimationRunning;
}
public MapRipple withRippleDuration(long rippleDuration) {
mRippleDuration = rippleDuration;
return this;
}
private final Runnable mCircleOneRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[0] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(0);
}
};
private final Runnable mCircleTwoRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[1] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(1);
}
};
private final Runnable mCircleThreeRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[2] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(2);
}
};
private final Runnable mCircleFourRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[3] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(3);
}
};
private void startAnimation(final int numberOfRipple) {
ValueAnimator animator = ValueAnimator.ofInt(0, (int) mDistance);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setDuration(mRippleDuration);
animator.setEvaluator(new IntEvaluator());
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int animated = (int) valueAnimator.getAnimatedValue();
mGroundOverlays[numberOfRipple].setDimensions(animated);
if (mDistance - animated <= 10) {
if (mLatLng != mPrevLatLng) {
mGroundOverlays[numberOfRipple].setPosition(mLatLng);
}
}
}
});
animator.start();
mAnimators[numberOfRipple] = animator;
}
private void setDrawableAndBitmap() {
mBackground.setColor(mFillColor);
mBackground.setStroke(UiUtil.dpToPx(mStrokeWidth), mStrokeColor);
mBackgroundImageDescriptor = UiUtil.drawableToBitmapDescriptor(mBackground);
}
public void stopRippleMapAnimation() {
if (isAnimationRunning) {
try {
for (int i = 0; i < mNumberOfRipples; i++) {
if (i == 0) {
mHandlers[i].removeCallbacks(mCircleOneRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
if (i == 1) {
mHandlers[i].removeCallbacks(mCircleTwoRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
if (i == 2) {
mHandlers[i].removeCallbacks(mCircleThreeRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
if (i == 3) {
mHandlers[i].removeCallbacks(mCircleFourRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
}
} catch (Exception e) {
//no need to handle it
}
}
isAnimationRunning = false;
}
public void startRippleMapAnimation() {
if (!isAnimationRunning) {
setDrawableAndBitmap();
for (int i = 0; i < mNumberOfRipples; i++) {
if (i == 0) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleOneRunnable, mDurationBetweenTwoRipples * i);
}
if (i == 1) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleTwoRunnable, mDurationBetweenTwoRipples * i);
}
if (i == 2) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleThreeRunnable, mDurationBetweenTwoRipples * i);
}
if (i == 3) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleFourRunnable, mDurationBetweenTwoRipples * i);
}
}
}
isAnimationRunning = true;
}
}
Run Code Online (Sandbox Code Playgroud)
R.drawable.map_background
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:width="150dp"
android:height="150dp" />
<stroke
android:width="0.5dp"
android:color="#000000" />
</shape>
Run Code Online (Sandbox Code Playgroud)
PolyUtil类
public class PolyUtil {
private PolyUtil() {}
private static double tanLatGC(double lat1, double lat2, double lng2, double lng3) {
return (tan(lat1) * sin(lng2 - lng3) + tan(lat2) * sin(lng3)) / sin(lng2);
}
private static double mercatorLatRhumb(double lat1, double lat2, double lng2, double lng3) {
return (mercator(lat1) * (lng2 - lng3) + mercator(lat2) * lng3) / lng2;
}
private static boolean intersects(double lat1, double lat2, double lng2,
double lat3, double lng3, boolean geodesic) {
// Both ends on the same side of lng3.
if ((lng3 >= 0 && lng3 >= lng2) || (lng3 < 0 && lng3 < lng2)) {
return false;
}
// Point is South Pole.
if (lat3 <= -PI/2) {
return false;
}
// Any segment end is a pole.
if (lat1 <= -PI/2 || lat2 <= -PI/2 || lat1 >= PI/2 || lat2 >= PI/2) {
return false;
}
if (lng2 <= -PI) {
return false;
}
double linearLat = (lat1 * (lng2 - lng3) + lat2 * lng3) / lng2;
// Northern hemisphere and point under lat-lng line.
if (lat1 >= 0 && lat2 >= 0 && lat3 < linearLat) {
return false;
}
// Southern hemisphere and point above lat-lng line.
if (lat1 <= 0 && lat2 <= 0 && lat3 >= linearLat) {
return true;
}
// North Pole.
if (lat3 >= PI/2) {
return true;
}
return geodesic ?
tan(lat3) >= tanLatGC(lat1, lat2, lng2, lng3) :
mercator(lat3) >= mercatorLatRhumb(lat1, lat2, lng2, lng3);
}
public static boolean containsLocation(LatLng point, List<LatLng> polygon, boolean geodesic) {
return containsLocation(point.latitude, point.longitude, polygon, geodesic);
}
public static boolean containsLocation(double latitude, double longitude, List<LatLng> polygon, boolean geodesic) {
final int size = polygon.size();
if (size == 0) {
return false;
}
double lat3 = toRadians(latitude);
double lng3 = toRadians(longitude);
LatLng prev = polygon.get(size - 1);
double lat1 = toRadians(prev.latitude);
double lng1 = toRadians(prev.longitude);
int nIntersect = 0;
for (LatLng point2 : polygon) {
double dLng3 = wrap(lng3 - lng1, -PI, PI);
// Special case: point equal to vertex is inside.
if (lat3 == lat1 && dLng3 == 0) {
return true;
}
double lat2 = toRadians(point2.latitude);
double lng2 = toRadians(point2.longitude);
// Offset longitudes by -lng1.
if (intersects(lat1, lat2, wrap(lng2 - lng1, -PI, PI), lat3, dLng3, geodesic)) {
++nIntersect;
}
lat1 = lat2;
lng1 = lng2;
}
return (nIntersect & 1) != 0;
}
private static final double DEFAULT_TOLERANCE = 0.1; // meters.
public static boolean isLocationOnEdge(LatLng point, List<LatLng> polygon, boolean geodesic,
double tolerance) {
return isLocationOnEdgeOrPath(point, polygon, true, geodesic, tolerance);
}
public static boolean isLocationOnEdge(LatLng point, List<LatLng> polygon, boolean geodesic) {
return isLocationOnEdge(point, polygon, geodesic, DEFAULT_TOLERANCE);
}
public static boolean isLocationOnPath(LatLng point, List<LatLng> polyline,
boolean geodesic, double tolerance) {
return isLocationOnEdgeOrPath(point, polyline, false, geodesic, tolerance);
}
public static boolean isLocationOnPath(LatLng point, List<LatLng> polyline,
boolean geodesic) {
return isLocationOnPath(point, polyline, geodesic, DEFAULT_TOLERANCE);
}
private static boolean isLocationOnEdgeOrPath(LatLng point, List<LatLng> poly, boolean closed,
boolean geodesic, double toleranceEarth) {
int idx = locationIndexOnEdgeOrPath(point, poly, closed, geodesic, toleranceEarth);
return (idx >= 0);
}
public static int locationIndexOnPath(LatLng point, List<LatLng> poly,
boolean geodesic, double tolerance) {
return locationIndexOnEdgeOrPath(point, poly, false, geodesic, tolerance);
}
public static int locationIndexOnPath(LatLng point, List<LatLng> polyline,
boolean geodesic) {
return locationIndexOnPath(point, polyline, geodesic, DEFAULT_TOLERANCE);
}
private static int locationIndexOnEdgeOrPath(LatLng point, List<LatLng> poly, boolean closed,
boolean geodesic, double toleranceEarth) {
int size = poly.size();
if (size == 0) {
return -1;
}
double tolerance = toleranceEarth / EARTH_RADIUS;
double havTolerance = hav(tolerance);
double lat3 = toRadians(point.latitude);
double lng3 = toRadians(point.longitude);
LatLng prev = poly.get(closed ? size - 1 : 0);
double lat1 = toRadians(prev.latitude);
double lng1 = toRadians(prev.longitude);
int idx = 0;
if (geodesic) {
for (LatLng point2 : poly) {
double lat2 = toRadians(point2.latitude);
double lng2 = toRadians(point2.longitude);
if (isOnSegmentGC(lat1, lng1, lat2, lng2, lat3, lng3, havTolerance)) {
return Math.max(0, idx - 1);
}
lat1 = lat2;
lng1 = lng2;
idx++;
}
} else {
double minAcceptable = lat3 - tolerance;
double maxAcceptable = lat3 + tolerance;
double y1 = mercator(lat1);
double y3 = mercator(lat3);
double[] xTry = new double[3];
for (LatLng point2 : poly) {
double lat2 = toRadians(point2.latitude);
double y2 = mercator(lat2);
double lng2 = toRadians(point2.longitude);
if (max(lat1, lat2) >= minAcceptable && min(lat1, lat2) <= maxAcceptable) {
// We offset longitudes by -lng1; the implicit x1 is 0.
double x2 = wrap(lng2 - lng1, -PI, PI);
double x3Base = wrap(lng3 - lng1, -PI, PI);
xTry[0] = x3Base;
// Also explore wrapping of x3Base around the world in both directions.
xTry[1] = x3Base + 2 * PI;
xTry[2] = x3Base - 2 * PI;
for (double x3 : xTry) {
double dy = y2 - y1;
double len2 = x2 * x2 + dy * dy;
double t = len2 <= 0 ? 0 : clamp((x3 * x2 + (y3 - y1) * dy) / len2, 0, 1);
double xClosest = t * x2;
double yClosest = y1 + t * dy;
double latClosest = inverseMercator(yClosest);
double havDist = havDistance(lat3, latClosest, x3 - xClosest);
if (havDist < havTolerance) {
return Math.max(0, idx - 1);
}
}
}
lat1 = lat2;
lng1 = lng2;
y1 = y2;
idx++;
}
}
return -1;
}
private static double sinDeltaBearing(double lat1, double lng1, double lat2, double lng2,
double lat3, double lng3) {
double sinLat1 = sin(lat1);
double cosLat2 = cos(lat2);
double cosLat3 = cos(lat3);
double lat31 = lat3 - lat1;
double lng31 = lng3 - lng1;
double lat21 = lat2 - lat1;
double lng21 = lng2 - lng1;
double a = sin(lng31) * cosLat3;
double c = sin(lng21) * cosLat2;
double b = sin(lat31) + 2 * sinLat1 * cosLat3 * hav(lng31);
double d = sin(lat21) + 2 * sinLat1 * cosLat2 * hav(lng21);
double denom = (a * a + b * b) * (c * c + d * d);
return denom <= 0 ? 1 : (a * d - b * c) / sqrt(denom);
}
private static boolean isOnSegmentGC(double lat1, double lng1, double lat2, double lng2,
double lat3, double lng3, double havTolerance) {
double havDist13 = havDistance(lat1, lat3, lng1 - lng3);
if (havDist13 <= havTolerance) {
return true;
}
double havDist23 = havDistance(lat2, lat3, lng2 - lng3);
if (havDist23 <= havTolerance) {
return true;
}
double sinBearing = sinDeltaBearing(lat1, lng1, lat2, lng2, lat3, lng3);
double sinDist13 = sinFromHav(havDist13);
double havCrossTrack = havFromSin(sinDist13 * sinBearing);
if (havCrossTrack > havTolerance) {
return false;
}
double havDist12 = havDistance(lat1, lat2, lng1 - lng2);
double term = havDist12 + havCrossTrack * (1 - 2 * havDist12);
if (havDist13 > term || havDist23 > term) {
return false;
}
if (havDist12 < 0.74) {
return true;
}
double cosCrossTrack = 1 - 2 * havCrossTrack;
double havAlongTrack13 = (havDist13 - havCrossTrack) / cosCrossTrack;
double havAlongTrack23 = (havDist23 - havCrossTrack) / cosCrossTrack;
double sinSumAlongTrack = sinSumFromHav(havAlongTrack13, havAlongTrack23);
return sinSumAlongTrack > 0; // Compare with half-circle == PI using sign of sin().
}
public static List<LatLng> simplify(List<LatLng> poly, double tolerance) {
final int n = poly.size();
if (n < 1) {
throw new IllegalArgumentException("Polyline must have at least 1 point");
}
if (tolerance <= 0) {
throw new IllegalArgumentException("Tolerance must be greater than zero");
}
boolean closedPolygon = isClosedPolygon(poly);
LatLng lastPoint = null;
if (closedPolygon) {
final
| 归档时间: |
|
| 查看次数: |
1400 次 |
| 最近记录: |