I have this code
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(mainLocation);
builder.include(userLocation);
LatLngBounds bounds = builder.build();
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 0);
mMap.animateCamera(cu);
And this works it shows bounds but i would like to show bounds on the top half of the screen (is there a way to put offset y?).
(Hope this picture will explain things better)
If I understand you correctly, what you get now is that map is centered, meaning your provided locations are centered on the map. And you want those locations to be on the upper part of the screen.
It seems there is not such an API, that would allow to apply padding to bottom only.
You can add a fake location to LatLngBounds.Builder at the lower part of the screen, now the CameraUpdate would include that point also, which will shift your 2 real points on the upper part.
You can use the setPadding method from the GoogleMap object.
In your case you will need to add a bottom padding:
mMap.setPadding(0, 0, 0, 150);
Maybe late, but i solved this. I make bottom padding for map, before call animateCamera, and return padding after update.
val heightValue = (Resources.getSystem().displayMetrics.heightPixels * 0.5).toInt()
map.setPadding(0,0,0,heightValue)
val update = CameraUpdateFactory.newLatLngBounds(bounds,50)
map.animateCamera(update,object:GoogleMap.CancelableCallback{
override fun onFinish() {
inUi {
map.setPadding(0,0,0,0)
}
}
override fun onCancel() {}
})
Here is the best solution I found to achieve this effect.
You force the padding you need before animating the camera, and immediately after, you reset the padding to whatever ever value.
map.setPadding(left, top, right, bottom) // In your example, this will be the only non-zero value.
animateCamera(cameraUpdate) // Trigger the animation
map.setPadding(0, 0, 0, 0) // Reset the padding
Related
My activity contains a MapFragment in a LinearLayout. I do the following
in onCreate:
I inflate this layout using setContentView in the onCreate method of
my activity.
Get a handle to the GoogleMap using getMap().
in onStart:
I get some place coordinates from an SQLite Database
add corresponding markers to the map
add these points to a LatLngBounds.Builder
animate the camera using newLatLngBounds(Builder.build(), 10)
According to maps api reference, I shouldn't call newLatLngBounds(LatLngBounds bounds, int padding) before making sure that the map has a size. I indeed get an IllegalStateException at this point. But what is the right method for waiting until the map has a size?
The solution by rusmus didn't work for me. I used this one instead:
map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
map.animateCamera(cameraUpdate);
}
});
If you know the map size, you can avoid waiting and move the camera before the map is displayed. We finally used the display size as an approximation of the map size (but you could find out the exact size if you want to be more precise):
final DisplayMetrics display = getResources().getDisplayMetrics();
final int padding = display.widthPixels / 20;
final CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(
boundsBuilder.build(), display.widthPixels, display.heightPixels, padding);
map.moveCamera(cameraUpdate);
I have succesfully used the following code in the past:
final LatLngBounds.Builder builder = new LatLngBounds.Builder();
final View mapView = fragment.getView();
final GoogleMap map = fragment.getMap():
//Add points to builder. And get bounds...
final LatLngBounds bounds = builder.build();
// Pan to see all markers in view.
// Cannot zoom to bounds until the map has a size.
if (mapView.getViewTreeObserver().isAlive()) {
mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50), 1500, null);
}
});
}
With the latest GoogleServices you can use MapFragment.getMapAsync.
Directly from the docs
Sets a callback object which will be triggered when the GoogleMap instance is ready to be used.
I am trying to zoom on a map
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(mBounds, this.getResources().getDisplayMetrics().widthPixels,
height, padding);
mMap.animateCamera(cameraUpdate, duration, null);
And after that I want to scroll the map vertically
CameraUpdate cameraUpdate =
CameraUpdateFactory.scrollBy(0, amountToScroll);
mMap.animateCamera(cameraUpdate, duration, null);
The thing is ... it is not working. If I call the scroll right after the zoom, only the scroll is taken into account. If I scroll the map once the zoom animation is finished I will have 2 animations.
I would like to do both operations with the same animation, is it possible?
If you call animateCamera multiple times, only the last one will finish its action.
The easy fix would be to use moveCamera instead of the first call to animateCamera, but that's not a nice solution from UX perspective.
The other way would be to do the math yourself and fill mBounds with the bounds you really want to show.
The easiest way to do it is to use CancelableCallback. You should check the first action is complete and then call the second:
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, size.x, height, 0), new CancelableCallback() {
#Override
public void onFinish() {
CameraUpdate cu_scroll = CameraUpdateFactory.scrollBy(0, 500);
mMap.animateCamera(cu_scroll);
}
#Override
public void onCancel() {
}
});
I am writing an application in android using Google map-V2 API. I want to over lay action bar just as in the Google map application. And I enabled "My Location " button. The problem now is that my location button is under the action bar. Is there any way to re-position this button. I want to make an app some what similar to Maps. I am new to android so please help.
You can set padding to the map.
This solved the problem - overlays over the map on the top (I used 48 dips, but you can overlay action bar and then get actual height of it (?android:attr/actionBarSize))
mapFragment.getMap().setPadding(0, dpToPx(48), 0, 0);
(DP to PX function is from this SO answer)
You can reposition your location button easily
View plusMinusButton = suppormanagerObj.getView().findViewById(1);
View locationButton = suppormanagerObj.getView().findViewById(2);
// and next place it, for exemple, on bottom right (as Google Maps app)
RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) locationButton.getLayoutParams();
// position on right bottom
rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
you can also set padding after setting alignment of the location button
mMap.setPadding(0, 0, 30, 105);
You can not alter the MyLocationButton in any way, but enable and disable it. There is already a request for this.
Feel free to disable the button and just implement your own one.
You would have something like this:
mMap.getUiSettings().setMyLocationButtonEnabled(false);
I solved this problem in my map fragment by re positioning my location button to the right bottom corner of view using code below,
here is my Maps Activity.java :-
add this lines of code in onCreate() method,
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapView = mapFragment.getView();
mapFragment.getMapAsync(this);
and here is onMapReady() code :-
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMyLocationEnabled(true);
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
if (mapView != null &&
mapView.findViewById(Integer.parseInt("1")) != null) {
// Get the button view
View locationButton = ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));
// and next place it, on bottom right (as Google Maps app)
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
locationButton.getLayoutParams();
// position on right bottom
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
layoutParams.setMargins(0, 0, 30, 30);
}
}
I hope, this will solve your problem. Thanks.
Instead of the findViewById solutions, I used the findViewWithTag to get a reference to the button. Using a string seemed more readable and reliable to me.
View myLocationButton = mMap.findViewWithTag("GoogleMapMyLocationButton");
RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) myLocationButton.getLayoutParams();
rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
Just use GoogleMap.setPadding(left, top, right, bottom), which allows you to indicate parts of the map that may be obscured by other views. Setting padding re-positions the standard map controls, and camera updates will use the padded region.
https://developers.google.com/maps/documentation/android/map#map_padding
I have a google map (com.google.android.gms.maps.GoogleMap) where I have some markers set.
I am able to, separately,
1) adjust zoom level and center the map on a boundary:
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(getZoomBounds(), 10));
and
2) center the map above one of the markers:
LatLng poiSelectedLatLng = new LatLng(markerSelected.getPosition().latitude
+ offset, markerSelected.getPosition().longitude);
mMap.animateCamera(CameraUpdateFactory.newLatLng(poiSelectedLatLng));
but, for the life of me, I can't just do both, adjust the zoom level using newLatLngBounds and then center the map somewhere else. Whatever I do last is what I see happening in the map.
How do I do this?
For future visitors this is how you can chain camera animations:
map.animateCamera(CameraUpdateFactory.newLatLngBounds(getZoomBounds(), 10), 2000, new CancelableCallback() {
#Override
public void onFinish() {
LatLng poiSelectedLatLng = new LatLng(markerSelected.getPosition().latitude + offset, markerSelected.getPosition().longitude);
map.animateCamera(CameraUpdateFactory.newLatLng(poiSelectedLatLng));
}
#Override
public void onCancel() {
}
});
Also see AnimateCameraChainingExampleActivity.java for an example how to chain infinitely.
Try using both moveCamera and animateCamera...
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(getZoomBounds(), 10));
LatLng poiSelectedLatLng = new LatLng(markerSelected.getPosition().latitude
+ offset, markerSelected.getPosition().longitude);
mMap.animateCamera(CameraUpdateFactory.newLatLng(poiSelectedLatLng));
moveCamera will move directly to that spot while animateCamera will provide the moving effect. They are linear in nature so one will happen after the other however layering them as I have done above will provide the potential effect you are looking for.
If you are trying to see the actual movement of both calls on the UI you will need to register for the callback post the completion of the animation as needed.
This question already has answers here:
Change position of Google Maps API's "My location" button
(17 answers)
Closed 4 years ago.
I have added a map fragment (API v2) to my app with the map covering the whole screen and a semi-transparent actionbar on top.
The activity uses a theme with android:windowActionBarOverlay set to true.
I have also enabled the "MyLocationButton" on the map, but since the map covers the full height of the screen, the button is covered by the action bar.
How can I make the map fragment draw the location button below the action bar or at the bottom of the screen instead?
Instead of creating your own button, just move the build in button according to the action bar size.
This code works for me and the button is just where the button should be (like in google maps):
// Gets the my location button
View myLocationButton = getSherlockActivity().findViewById(R.id.MainContainer).findViewById(2);
// Checks if we found the my location button
if (myLocationButton != null){
int actionBarHeight = 0;
TypedValue tv = new TypedValue();
// Checks if the os version has actionbar in it or not
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
if (getSherlockActivity().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
// Before the action bar was added to the api
else if(getSherlockActivity().getTheme().resolveAttribute(com.actionbarsherlock.R.attr.actionBarSize, tv, true)){
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
// Sets the margin of the button
ViewGroup.MarginLayoutParams marginParams = new ViewGroup.MarginLayoutParams(myLocationButton.getLayoutParams());
marginParams.setMargins(0, actionBarHeight + 20, 20, 0);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
myLocationButton.setLayoutParams(layoutParams);
}
Just put this code in the onActivityCreated (if you will put it in the onCreateOptionsMenu, it will not support version before 3.0 - because the life cycle there is different.
Another thing, the "R.id.MainContainer" is the container of the map fragment.
I'm using ActionBar Sherlock, but it will work also for regular action bar with a few modifications..
Below (especially in fixMapControlLocations) i've addressed this with ActionBarSherlock.
Issues I had were on narrow screens, and the split action bar having the wrong offset depending on rotation. The isNarrow check through sherlock lets me know if its narrow.
Another key change is i'm setting the padding of the myLocation's parent's parent view. This picks up all controls inside, and based on hierarchyviewer is how google maps is doing it. The Google attribution logo is on the next parent up the tree in a Surface object. Not looking like that is easily movable, so i'm probably just going to end up loosing the bottom action bar's transparency effect to stay in compliance.
protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
setUpMapIfNeeded();
getSupportActionBar().setBackgroundDrawable(d);
getSupportActionBar().setSplitBackgroundDrawable(d);
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the
// map.
if (map == null) {
// Try to obtain the map from the SupportMapFragment.
map = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getExtendedMap();
// Check if we were successful in obtaining the map.
if (map != null) {
setUpMap();
}
}
}
private void setUpMap() {
fixMapControlLocations();
.....
}
private void fixMapControlLocations() {
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
int actionBarHeight = 0;
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
{
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
View myLocationParent = ((View)mapFragment.getView().findViewById(1).getParent());
View myLocationParentParent = ((View)myLocationParent.getParent());
myLocationParentParent.setPadding(0, actionBarHeight, 0, isNarrow()?actionBarHeight:0);
}
public boolean isNarrow() {
return ResourcesCompat.getResources_getBoolean(getApplicationContext(),
R.bool.abs__split_action_bar_is_narrow);
}
You can accomplish this with the recently-added GoogleMap.setPadding() method:
map.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
From the API docs:
This method allows you to define a visible region on the map, to signal to the map that portions of the map around the edges may be obscured, by setting padding on each of the four edges of the map. Map functions will be adapted to the padding. For example, the zoom controls, compass, copyright notices and Google logo will be moved to fit inside the defined region, camera movements will be relative to the center of the visible region, etc.
Also see the description of how padding works in GoogleMap.
This has already been filed as an enhancement (please star it if you haven't already) http://code.google.com/p/gmaps-api-issues/issues/detail?id=4670
As a temporary workaround I have added my own find location button below the actionbar (my map fragment is in a RelativeLayout so I just did alignParentRight and set appropriate margin top).
Then in my onClickHandler I did this:
public void onClickHandler(View target) {
switch (target.getId()) {
case R.id.my_fml_btn:
mMap.setMyLocationEnabled(true);
View fmlBtn = mMapWrapper.findViewById(2); //mMapWrapper is my RelativeLayout
if (fmlBtn != null) fmlBtn.setVisibility(View.INVISIBLE);
break;
}
}
I used hierarchyviewer to find the id of the button that was added by the maps api. It just happens to be the 2nd view added to the map (and set to invisible).
You can of course you can fiddle about with LayoutParams to offset this button rather than hide it but this button only appears after you setMyLocationEnabled to true! (in my use case I prefer to let the user decide before firing up the gps)
Make sure you use ?android:attr/actionBarSize (or ?attr/actionBarSize if you're using ActionBarSherlock) to correctly offset the content of the fragment.
Depending of the effect you're trying to accomplish, either apply this value as margin or padding. I'm guessing that because of the semi-transparant ActionBar, you'll want to try padding, in order to still have the map appear behind it (and keep the see-through effect). I'm just not 100% sure whether padding will actually move the 'Locate me' button down... If not, then probably applying a margin is your only other option.
See here for an example and more details on this attribute.