android - studio - hacer buffer en google earth
¿Cómo puedo dibujar un círculo objetivo estático en Google Maps? (1)
He estado buscando dibujar un círculo para un radio estático en la parte superior de Google Maps y todas las respuestas que encontré describen dibujar marcadores y círculos que están vinculados a una coordenada de latitud larga.
Lo que requiero es esto:
Este círculo y el marcador flotan sobre el fragmento de Google Maps , es decir: cuando desplazas y haces zoom, permanece estático . Y aquí está la parte complicada: quiero poder obtener el área cubierta en el mapa para su procesamiento (por ejemplo: el lat, largo del marcador central y el radio del círculo dependiendo del nivel de zoom en el mapa).
¿Cómo puedo conseguir esto? Gracias por adelantado.
Puede crear una View
personalizada para dibujar el círculo. He basado mi ejemplo en Dibujar círculo transparente lleno afuera
Aquí puede encontrar un tutorial sobre cómo crear vistas personalizadas.
En mi ejemplo, estoy creando una RadarOverlayView
personalizada con un parámetro de radius
que utilizo para calcular el área.
Mi código de vista personalizada:
public class RadarOverlayView extends LinearLayout {
private Bitmap windowFrame;
private float radius = 0f;
private int centerX = 0;
private int centerY = 0;
public RadarOverlayView(Context context) {
super(context);
}
public RadarOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs, R.styleable.RadarOverlayView, 0, 0);
try {
radius = a.getDimension(R.styleable.RadarOverlayView_radius, 0f);
} finally {
a.recycle();
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (windowFrame == null) {
createWindowFrame();
}
canvas.drawBitmap(windowFrame, 0, 0, null);
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public boolean isClickable() {
return false;
}
protected void createWindowFrame() {
windowFrame = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas osCanvas = new Canvas(windowFrame);
centerX = getWidth() / 2;
centerY = getHeight() / 2;
if (radius > 0) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// Draw the circunference
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
paint.setAlpha(200);
paint.setStrokeWidth(5);
osCanvas.drawCircle(centerX, centerY, radius, paint);
// Draw the circle
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setAlpha(100);
osCanvas.drawCircle(centerX, centerY, radius, paint);
// Draw the center icon
paint.setAlpha(255);
Bitmap centerBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
osCanvas.drawBitmap(centerBitmap, centerX - centerBitmap.getWidth() / 2,
centerY - centerBitmap.getHeight() / 2,
paint);
}
}
@Override
public boolean isInEditMode() {
return true;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
windowFrame = null;
}
public float getRadius() {
return radius;
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
}
Mi attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RadarOverlayView">
<attr name="radius" format="dimension" />
</declare-styleable>
</resources>
Mi diseño activity_maps.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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="@+id/map"
android:name="myPackage.MySupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity"/>
<myPackage.RadarOverlayView
android:id="@+id/radar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
app:radius="150dp" />
</RelativeLayout>
Mi actividad:
public class MapsActivity extends FragmentActivity implements GoogleMap.OnCameraChangeListener {
private GoogleMap mMap;
private RadarOverlayView radarView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
radarView = (RadarOverlayView) findViewById(R.id.radar);
setUpMapIfNeeded();
}
@Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.getUiSettings().setAllGesturesEnabled(true);
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.setOnCameraChangeListener(this);
}
@Override
public void onCameraChange(final CameraPosition cameraPosition) {
// Compute the area of the circle each time the camera changes
LatLng center = mMap.getProjection().fromScreenLocation(
new Point(radarView.getCenterX(), radarView.getCenterY()));
LatLng right = mMap.getProjection().fromScreenLocation(
new Point(radarView.getCenterX() + Math.round(radarView.getRadius()),
radarView.getCenterY()));
Location locationCenter = new Location("center");
locationCenter.setLatitude(center.latitude);
locationCenter.setLongitude(center.longitude);
Location locationRight = new Location("right");
locationRight.setLatitude(right.latitude);
locationRight.setLongitude(right.longitude);
double geoRadius = locationCenter.distanceTo(locationRight);
double geoArea = Math.PI * Math.pow(geoRadius, 2);
// Uncomment to inspect the difference between
// RadarOverlayView circle and geographic circle:
// mMap.clear();
// Circle circle = mMap.addCircle(new CircleOptions()
// .center(cameraPosition.target)
// .radius(geoRadius)
// .strokeColor(Color.GREEN)
// .fillColor(Color.BLUE));
Toast.makeText(this, "Area: " + geoArea, Toast.LENGTH_SHORT).show();
}
}
El resultado se ve así y muestra una Toast
con el área cubierta por el círculo cada vez que cambia la cámara:
Limitaciones
El ejemplo dibuja un círculo perfecto en una View
, pero no se garantiza que este círculo sea geográficamente preciso según el nivel de zoom.
Puede ver que, en niveles de zoom altos, hay una gran diferencia entre el círculo dibujado por la vista personalizada y un círculo geográficamente preciso (basado en el objetivo y el radio de la cámara) si descomenta el código mMap.addCircle
en el método onCameraChange
:
Esta diferencia que es causada por la proyección del mapa (WGS84), es enorme con altos niveles de zoom y disminuye a niveles de zoom más bajos: