I am using the code from google maps v2 to draw polygons on loading maps v2 .It loads 300+ polygons in 5 secs but it shows black screen till 5 secs and does not display anything on the screen.How do I show map or should I display loading.. msg till it displays the maps ??I really appreciate any help .I tried many ways but still see black screen as its loading polygon onthe main thread.Thanks in Advance.
LatLng allLatLng= new LatLng((lat1),(long1));
all.add(allLatLng);
polygon = googleMap.addPolygon(new PolygonOptions()
.addAll(all)
.fillColor(Color.Yellow)
.strokeColor(Color.blue)
);
Example to go with the comments
//in onCreate
String json_string = getJsonStringStuff();
new AsyncTask<String, Void, List<List<LatLng>>>() {
#Override protected List<List<LatLng>> doInBackground(String... params) {
String json = params[0];
List<List<LatLng>> mLatLngList = new ArrayList<ArrayList<LatLng>>();
// Parse the json into the list
return mLatLngList;
}
#Override protected void onPostExecute(List<List<LatLng>> result) {
drawPolygonsToMap(result);
}
}.execute(json_string);
Use This to prevent black background
<fragment
android:id="#+id/location_map_fragment"
android:name="com.app.appname.TransparentSupportMapFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white" />
/**
*
* To prevent black background of map in ScrollView
*
*/
public class TransparentSupportMapFragment extends SupportMapFragment {
public TransparentSupportMapFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup view, Bundle savedInstance) {
View layout = super.onCreateView(inflater, view, savedInstance);
FrameLayout frameLayout = new FrameLayout(getActivity());
frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
((ViewGroup) layout).addView(frameLayout,
new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
return layout;
}
public static TransparentSupportMapFragment newInstance(String abc) {
TransparentSupportMapFragment tsf = new TransparentSupportMapFragment();
return tsf;
}
}
Related
I'm trying to layout a custom infoWindow programmatically. I want to load a streetView preview image using Picasso but the image isn't showing up, any idea why?
private View prepareInfoView(Marker marker){
//prepare InfoView programmatically
LinearLayout infoView = new LinearLayout(EarthquakeActivity.this);
LinearLayout.LayoutParams infoViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
infoView.setOrientation(LinearLayout.VERTICAL);
// attach the above layout to the infoView
infoView.setLayoutParams(infoViewParams);
//create street view preview # top
ImageView streetViewPreviewIV = new ImageView(EarthquakeActivity.this);
// this scales the image to match parents WIDTH?, but retain image's height??
LinearLayout.LayoutParams streetViewImageViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
streetViewPreviewIV.setLayoutParams(streetViewImageViewParams);
String imageURL = "https://maps.googleapis.com/maps/api/streetview?size=200x200&location=";
String markerLongitude = Double.toString(marker.getPosition().longitude);
String markerLatitude = Double.toString(marker.getPosition().latitude);
imageURL += markerLatitude + "," + markerLongitude + "&fov=120&heading=0&pitch=0";
Log.wtf("prepareInfoView", imageURL);
Picasso.with(this).load(imageURL).into(streetViewPreviewIV);
infoView.addView(streetViewPreviewIV);
I've tried with and without the api key appending the url.
It did work for a few clicks without the key, but hasn't since, with or without. Is the because it's too slow fetching it so Android gives up and loads the info window without it? Is there a best in class way to do this?
Would another image loading library work better? Google's volley?
Also with
LinearLayout.LayoutParams
I'd like the image to stretch across the width of the info windows, i.e. match_parent, and to scale vertically to maintain original aspect ratio, how do I do this?
This is my answer
In commonsWare new class I add this flag:
#Override
public void onSuccess() {
Log.i(TAG, "image got, should rebuild window");
if (marker != null && marker.isInfoWindowShown()) {
Log.i(TAG, "conditions met, redrawing window");
marker.setTag(new Boolean("True"));
marker.showInfoWindow();
}
}
And in prepareInfoView, I test for the flags absence.
if (marker.getTag() == null ) {
Log.i("prepareInfoView", "fetching image");
Picasso.with(this).load(imageURL).fetch(new MarkerCallback(marker));
}
else {
Log.wtf("prepareInfoView", "building info window");
Party on! :)
Is the because it's too slow fetching it so Android gives up and loads the info window without it?
Picasso loads asynchronously unless the image is cached. And the way Maps V2 works is that the View you return is converted into a Bitmap, and that is what gets rendered. As a result, you have a race condition between Picasso and Maps V2 (does the image get loaded before the Bitmap gets created?), and so it is indeterminate as to whether or not any given info window will work.
You can call showInfoWindow() on the Marker after Picasso has loaded the image, so you can populate the ImageView from Picasso's cache. showInfoWindow(), called on a Marker, triggers Maps V2 to regenerate the info window.
For example, you could change your existing into() call into into(streetViewPreviewIV, new MarkerCallback(marker)), with a MarkerCallback like:
static class MarkerCallback implements Callback {
Marker marker=null;
MarkerCallback(Marker marker) {
this.marker=marker;
}
#Override
public void onError() {
Log.e(getClass().getSimpleName(), "Error loading thumbnail!");
}
#Override
public void onSuccess() {
if (marker != null && marker.isInfoWindowShown()) {
marker.showInfoWindow();
}
}
}
Would another image loading library work better? Google's volley?
They will all suffer from the same issue.
What is working for me is this:
public class MarkerCallback implements Callback {
Marker marker=null;
String URL;
ImageView userPhoto;
MarkerCallback(Marker marker, String URL, ImageView userPhoto) {
this.marker=marker;
this.URL = URL;
this.userPhoto = userPhoto;
}
#Override
public void onError() {
//Log.e(getClass().getSimpleName(), "Error loading thumbnail!");
}
#Override
public void onSuccess() {
if (marker != null && marker.isInfoWindowShown()) {
marker.hideInfoWindow();
Picasso.with(getActivity())
.load(URL)
.into(userPhoto);
marker.showInfoWindow();
}
}
}
All I figured out is,
Picasso loads image asynchronously, so when a marker shows it's info window after clicking by internally calling the method getInfoContents or getInfoWindow method ,
by this time if the image isn't already downloaded or cached by Picasso , then it is not showed on infoWindow.
Picasso tries to load the image into imageview of infoWindow when downloaded, but According to Google maps V2, the infoWindows Once loaded, can't be manipulated, so image is not shown updated on the UI.
But the infowindow view was updated actually but couldn't show for the restriction, so if you just hide and show the infowindow , it is kind of refreshed, and the images are shown on updated infoWindow. you can do this in the following way,
You need to keep the marker reference, you can keep this as Activity/Fragment's member variable.
Picasso.with(context)
.load(marker.getSnippet())
.placeholder(R.drawable.ic_placeholder)
.into(imageView, new Callback() {
#Override
public void onSuccess() {
if (currentClickedMarker != null && currentClickedMarker.isInfoWindowShown()) {
//toggle the marker's infoWindow
currentClickedMarker.hideInfoWindow();
currentClickedMarker.showInfoWindow();
}
}
#Override
public void onError() {
}
});
I struggled with this as well, here is a solution with glide inspired from the accepted answer.
This solution did not work for me without resizing the picture to a proper size. With override() (and centerCrop) it did the trick.
Keep track of the latest picture shown
private String previousImageUrl = null;
And use it to see if you need refreshing of the current image
googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(final Marker marker) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_map_info_window, null);
MyObject myObject = (MyObject) marker.getTag();
final String url = myObject.getImageUrl();
final ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
GlideApp.with(getContext()).load(url)
.override(imageWidth, imageHeight) // made the difference
.centerCrop()
.into(new SimpleTarget<Drawable>() {
#Override
public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
imageView.setImageDrawable(resource);
if (!TextUtils.equals(url, previousImageUrl)) {
previousImageUrl = url;
marker.showInfoWindow();
}
}
});
return view;
}
});
If you are using the accepted answer to fix the problem and it still doesn't work,
you're probably using .fit() .
in other words you should remove .fit() from your Picasso code.
It took me a couple hours to realize it.
I'm using min3D library in my project to visualize a 3D model. This library is based in openGL.
For this, I defined a renderer which manages the GLSurfaceView. At this moment, I see the 3D model in my app, but the background of the surface view is black, and my goal is to make it transparent, this way I would only see the 3D model without the black background.
The min3D library examples, as other SO questions and info I've readed about this, tell that the way to achieve this is by doing this:
_glSurfaceView.setEGLConfigChooser(8,8,8,8, 16, 0);
_glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
and this:
scene.backgroundColor().setAll(0x00000000);
But I don't get to make the background transparent.
First of all, this is my layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/valuesContainer"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
...
</LinearLayout>
<FrameLayout
android:id="#+id/model3d_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/valuesContainer"/>
</RelativeLayout>
The 3D model fragment is setted inside the FrameLayout this way:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_row3d, container, false);
Fragment modelFragment = new Obj3DView();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.model3d_container, modelFragment).commit();
return view;
}
And finally, this this the fragment which shows the 3D model and where I'm trying to modify things to make the surface trasnparent:
public class Obj3DView extends RendererFragment {
private Object3dContainer rowObject3D;
#Override
protected void glSurfaceViewConfig() {
// !important
_glSurfaceView.setEGLConfigChooser(8,8,8,8, 16, 0);
_glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
}
/** Called when the activity is first created. */
#Override
public void initScene() {
scene.backgroundColor().setAll(0x00000000);
scene.lights().add(new Light());
scene.lights().add(new Light());
Light myLight = new Light();
myLight.position.setZ(150);
scene.lights().add(myLight);
IParser myParser = Parser.createParser(Parser.Type.OBJ, getResources(), "com.masermic.rowingsoft:raw/row_obj",true);
myParser.parse();
rowObject3D = myParser.getParsedObject();
rowObject3D.position().x = rowObject3D.position().y = rowObject3D.position().z = 0;
rowObject3D.scale().x = rowObject3D.scale().y = rowObject3D.scale().z = 0.28f;
// Depending on the model you will need to change the scale faceObject3D.scale().x = faceObject3D.scale().y = faceObject3D.scale().z = 0.009f;
scene.addChild(rowObject3D);
}
#Override
public void updateScene() {
rowObject3D.rotation().x += 0.5;
rowObject3D.rotation().z += 1;
rowObject3D.rotation().y += 0.1;
}
}
Note: This fragment extends from RendererFragment(extending fragment) which belongs to the min3D library, and this is the most relevant code of this class:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
_initSceneHander = new Handler();
_updateSceneHander = new Handler();
//
// These 4 lines are important.
//
Shared.context(getActivity());
scene = new Scene(this);
Renderer r = new Renderer(scene);
Shared.renderer(r);
_glSurfaceView = new GLSurfaceView(getActivity());
glSurfaceViewConfig();
_glSurfaceView.setRenderer(r);
_glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
I answer my own question. After searching a lot, I finally got a solution that works. Just have to include this call inside glSurfaceViewConfig():
_glSurfaceView.setZOrderOnTop(true);
This question already has answers here:
Polygon Touch detection Google Map API V2
(7 answers)
Closed 7 years ago.
I am working on a map application on Android and i am using Google Maps Android API V2. I get the polygon data from a web service, convert it by XML parse and can show it on the map without a problem. But isn't there any way to open like pop-up when user touches on any polygon? Or maybe if user wants to change coordinates of selected polygon. I saw many examples, but they are done with javascript or some using different third party. Do someone has any advice? Thanks in advance.
I had the same problem. onMapClickListener is not called when user taps a polygon, it's only called when other overlays (such as Polygons) do not process the tap event. Polygon does process it, as you can see - GM moves the polygon to center of screen. And the event is not passed to onMapClickListener, that's it.
To workaround it, I intercept tap events before GM handles them, in a View wrapping MapFragment, as described here, project clicked point from screen coordinates to map, and then check if it is inside a polygon on the map as described here (other answer tells about it too)
Relevant code:
public class MySupportMapFragment extends SupportMapFragment {
private View mOriginalContentView;
private TouchableWrapper mTouchView;
private BasicMapActivity mActivity;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = (BasicMapActivity) getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
mOriginalContentView = super.onCreateView(inflater, parent,
savedInstanceState);
mTouchView = new TouchableWrapper();
mTouchView.addView(mOriginalContentView);
return mTouchView;
}
#Override
public View getView() {
return mOriginalContentView;
}
class TouchableWrapper extends FrameLayout {
public TouchableWrapper() {
super(mActivity);
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP: {
int x = (int) event.getX();
int y = (int) event.getY();
mActivity.tapEvent(x,y);
break;
}
}
return super.dispatchTouchEvent(event);
}
}
}
BasicMapActivity:
public void tapEvent(int x, int y) {
Log.d(TAG,String.format("tap event x=%d y=%d",x,y));
if(!isEditMode()) {
Projection pp = mMap.getProjection();
LatLng point = pp.fromScreenLocation(new Point(x, y));
for (Shape ss : mPolygons) {
if(ss.isPointInPolygon(point)) {
ss.mMarkers.get(0).marker.showInfoWindow();
}
}
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="au.com.datalink.plugins.MySupportMapFragment" />
</RelativeLayout>
All you have to work with is onMapClickListener which returns the latlng of the press
public abstract void onMapClick (LatLng point)
Called when the user makes a tap gesture on the map, but only if none of the overlays of the map handled the gesture. Implementations of this method are always invoked on the main thread.
Parameters
point The point on the ground (projected from the screen point) that was tapped.
Then check if the latlng is inside the polygon.
How to determine if a point is inside a 2D convex polygon?
I kinda pieced this together but the good news is lat and lng are already doubles.
Good Luck
In this scenario I want to draw a bitmap on Google Maps using gms v2 and each user position update enforces bitmap update. Currently I use following code snippet:
public void init(){
result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas = new Canvas(result);
}
public void update(){
// draw on canvas ...
draw(result);
}
public void draw(Bitmap modifiedBmp) {
if (overlay != null) {
overlay.remove();
}
BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(modifiedBmp);
overlay = map.addGroundOverlay(new GroundOverlayOptions().image(descriptor).positionFromBounds(bounds).zIndex(100));
}
The update() method is called each second. I find this approach extremely inefficient and I'm searching for a better solution (i.e. that doesn't require to add/remove overlay after each update). Drawing primitives on map using addPolygon(...) and addPolyline(...) isn't an option because I require drawing capabilities not present in standard api.
One optimization could be to check if the new position is the same as the old one and don't redraw if that is the case. Also I don't think that the descriptor need to be created each time.
Another approach for moving markers is described here. It's the one from the official sample.
I'm not sure if this is what you want, but this is how I used custom bitmaps in Google Maps.
The marker code:
BitmapDescriptor iconBitmap = BitmapDescriptorFactory
.fromResource(R.drawable.item_map_marker);
MarkerOptions options = new MarkerOptions();
options.position(new LatLng(hs.lat, hs.lng));
options.title(hs.sitename);
options.snippet(hs.street + ", " + hs.suburb);
options.icon(iconBitmap);
mMap.addMarker(options);
The tooltip adapter:
public class MyInfoWindowAdapter implements InfoWindowAdapter {
public interface OnRenderCustomInfoWindow {
public void onRender(Marker marker, View mWindow);
}
private View mWindow;
private OnRenderCustomInfoWindow mRenderer;
public MyInfoWindowAdapter(Context context,
OnRenderCustomInfoWindow onRender) {
mRenderer = onRender;
mWindow = LayoutInflater.from(context).inflate(
R.layout.view_services_map_infowindow, null);
}
#Override
public View getInfoWindow(Marker marker) {
mRenderer.onRender(marker, mWindow);
return mWindow;
}
#Override
public View getInfoContents(Marker marker) {
return null;
}
}
I am developing with Google Maps Add-on. I found a little strange circle in the middle of my MapView. When I scroll the view or tap somewhere else, it's gone.
I debug the view with Hierarchy View tools, you can see is from inside of MapView, definitely not some misplace view from my code.
The red marker is from the overlay, just simply pin on the center of this MapView.
Here is the code, pretty standard MapView code:
mMapView = new MapView(getActivity(), R.string.key_mapAPIKey);
mMapView.setClickable(false);
mMapView.getController().setZoom(DEFAULT_MAP_ZOOM);
mMapView.getController().animateTo(geoPoint);
mMapView.getOverlays().clear();
mMapView.getOverlays().add(new GoogleMapClassicMarkerOverlay(getResources(), geoPoint));
UPDATE-10/30
The Overlay is also ordinary, just to show a single marker in the middle, I remove the overlay but the circle is still there:
public class GoogleMapClassicMarkerOverlay extends ItemizedOverlay<OverlayItem> {
private GeoPoint mGeoPoint;
private OverlayItem mItem;
public GoogleMapClassicMarkerOverlay(Resources res, GeoPoint geoPoint) {
super(boundCenterBottom(new SafeBitmapDrawable(res, R.drawable.map_marker)));
mGeoPoint = geoPoint;
mItem = new OverlayItem(mGeoPoint, "", "");
populate();
}
#Override
protected OverlayItem createItem(int i) {
return mItem;
}
#Override
public int size() {
return 1;
}
}
Anyone has idea how to remove this wired circle?