How can I change google map my location default button?
I set my location enable and map draw standard image to find location, is it possible to change default image?
See below xml file to custom button:
<?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"
android:orientation="vertical" >
<fragment
android:id="#+id/maps"
android:name="pl.mg6.android.maps.extensions.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="5dp" >
<ImageView
android:id="#+id/imgMyLocation"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="fitXY"
android:src="#drawable/track_my_location" />
</LinearLayout>
</RelativeLayout>
Then in java class, declare your location button:
private ImageView imgMyLocation;
imgMyLocation = (ImageView) findViewById(R.id.imgMyLocation);
Click Event:
imgMyLocation.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
getMyLocation();
}
Get Location Method, in that just pass your current latitude and longitude.
private void getMyLocation() {
LatLng latLng = new LatLng(Double.parseDouble(getLatitude()), Double.parseDouble(getLongitude()));
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 18);
googleMap.animateCamera(cameraUpdate);
}
});
With a simple trick, you can replace the my location button with a custom one.
Customize the Layout of your new button.
Set my location enabled in maps api.
Hide default button of my location.
call click method of my location on your custom button click.
1. Customize the layout of your new button
add a new button to your desired location in layout file of map activity.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MapsActivity" />
<ImageView
android:id="#+id/ic_location"
android:layout_width="18dp"
android:layout_height="18dp"
android:src="#drawable/ic_location"
android:layout_marginRight="8dp"
android:layout_marginBottom="18dp"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
2. Set my location enabled in maps api
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Enable My Location
mMap.setMyLocationEnabled(true);
/* and DON'T disable the default location button*/
}
3. Hide default button of my location.
//Create field for map button.
private View locationButton;
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMyLocationEnabled(true);
// get your maps fragment
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
// Extract My Location View from maps fragment
locationButton = mapFragment.getView().findViewById(0x2);
// Change the visibility of my location button
if(locationButton != null)
locationButton.setVisibility(View.GONE);
}
4. call click method of my location on your custom button click.
findViewById(R.id.ic_location).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mMap != null)
{
if(locationButton != null)
locationButton.callOnClick();
}
}
});
If you want to retain the smoothness of the default My Location button but not the look, call the following lines:
//Make sure you have explicit permission/catch SecurityException
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(false);
Now you can start & stop location updates while keeping the default behavior
This might be useful to someone who is looking for changing the location icon directly, instead of using any trick or workaround:
locationButton = (mapView.findViewById<View>(Integer.parseInt("1")).parent as View)
.findViewById<ImageView>(Integer.parseInt("2"))
locationButton.setImageResource(R.drawable.ic_location_current)`
Here findViewById<ImageView> is the right thing to be done.
I get the default ImageView of my location using tag instead of idfor preventingExpected resource of type id` lint warning -
ImageView imageView = ((ImageView)mapFragment.getView().findViewWithTag("GoogleMapMyLocationButton"));
Then you can manipulate the imageView then.
imageView.setImageResource(R.drawable.icon_custom_location);
Related
Question
Why does my custom infowindow not 'inflate' after a configuration change?
Summary
I have an app that places a marker on a map using MarkerManager, and sets a custom info-window using setInfoWindowAdapter.
After loading the app and clicking on the marker, the info-window correctly displays my custom layout.
However, after rotating the app so that the configuration changes, selecting the marker no longer displays the custom info-window, and instead only displays the generic 'title'.
What have I missed in all the hours of reading and tutorials that means I'm not correctly implementing this?
Code
Here is a stripped-down version of my app to replicate the issue
MapsActivity
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
MarkerManager.Collection mMarkerManagerCollection;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
if(savedInstanceState == null){
mapFragment.setRetainInstance(true); // maintains the map fragment on orientation changes
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
MarkerManager mMarkerManager = new MarkerManager(mMap);
mMap.setInfoWindowAdapter(mMarkerManager);
mMarkerManagerCollection = mMarkerManager.newCollection("myMarker");
mMarkerManagerCollection.setOnInfoWindowAdapter(new GoogleMap.InfoWindowAdapter(){
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
View v = getLayoutInflater().inflate(R.layout.info_window, null);
TextView tv = (TextView) v.findViewById(R.id.myTv);
tv.setText("hello world, this is my marker");
return v;
}
});
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
MarkerOptions options = new MarkerOptions()
.position(sydney)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
.flat(true)
.title("Marker in Sydney");
Marker marker = mMarkerManagerCollection.addMarker(options);
marker.setTag("test marker");
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
}
info_window.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="93dp"
android:layout_height="96dp"
android:id="#+id/rect_load"
android:padding="2dp"
android:src="#mipmap/ic_launcher"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/myTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="myText"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
Gradle
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.google.android.gms:play-services:9.8.0'
compile 'com.google.maps.android:android-maps-utils:0.4'
compile 'com.google.android.gms:play-services:9.8.0'
The problem is that you are creating and populating a new MarkerManager on each onMapReady call. As onMapReady gets called when the orientation changes but you are not removing old markers, the map has two markers on the same position.
When you click the marker after the orientation changes, the old marker is triggered and you see the default behaviour (show title). If you click the marker again you will see your info window.
One possible solution can be calling mMap.clear(); on the onMapReady before adding markers.
Background
Suppose I have a view that works as the background (MapFragment in my case), and some other views that are the content of the activity.
The problem
Focusing an EditText, it shows the soft keyboard, causing all views to change their sizes, including the background view.
This means that showing the soft keyboard causes the background to "jump" and re-layout itself.
This is especially problematic in my case, as I use MapFragment as the background. That's because I can think of a workaround to detect the keyboard size, and show only the upper area of the background view, but there is little control of the MapFragment in how it looks and work.
Here's a demo of the problem:
Here's a sample xml, used inside the sample of the mapFragment:
basic_demo.xml
<FrameLayout
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">
<fragment
android:id="#+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<EditText
android:id="#android:id/edit"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="20dp"
android:background="#66ffffff"
android:digits="0123456789()-+*"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center_vertical|left"
android:imeOptions="actionSearch|flagNoExtractUi"
android:inputType="phone"
android:singleLine="true"
android:textColorHint="#aaa"
android:textSize="18dp"
tools:hint="Search Phones ..."/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="30dp"
android:background="#66ffffff"
android:text="This should always be shown, at the bottom"/>
</FrameLayout>
What I've found
I know that we can set the "windowSoftInputMode" flag in the manifest, but this is an all-or-nothing solution. It affects all of the views, and not a single one.
The question
How can I let the soft keyboard change the layout of all views except specific ones?
Is it even possible?
EDIT: looking at "gio"'s solution, it works. Here's a more optimized way to do it:
View view=...
mContainerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
final Rect outGlobalRect = new Rect(), outWindowRect = new Rect();
#Override
public void onGlobalLayout() {
mContainerView.getGlobalVisibleRect(outGlobalRect);
mContainerView.getWindowVisibleDisplayFrame(outWindowRect);
int marginBottom = outGlobalRect.bottom - outWindowRect.bottom;
final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
if (layoutParams.bottomMargin == marginBottom)
return;
layoutParams.setMargins(0, 0, 0, marginBottom);
view.requestLayout();
}
});
It's possible according your initial requirements. Idea is to change bottom margin of needed view. Value will be calculated as difference between shown and real height of root view. I wrapped TextView into FrameLayout for case if you need to control more views there.
xml layout
<FrameLayout
android:id="#+id/ac_mp_container"
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">
<fragment
android:id="#+id/ac_mp_map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.tivogi.so.MapsActivity" />
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content" />
<FrameLayout
android:id="#+id/ac_mp_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This should always be shown, at the bottom" />
</FrameLayout>
activity class
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private View mContainerView;
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.ac_mp_map);
mapFragment.getMapAsync(this);
mContainerView = findViewById(R.id.ac_mp_container);
mContainerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
View view = findViewById(R.id.ac_mp_view);
int marginBottom;
Rect outGlobalRect = new Rect();
Rect outWindowRect = new Rect();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
mContainerView.getGlobalVisibleRect(outGlobalRect);
mContainerView.getWindowVisibleDisplayFrame(outWindowRect);
marginBottom = outGlobalRect.bottom - outWindowRect.bottom;
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM);
layoutParams.setMargins(0, 0, 0, marginBottom);
view.setLayoutParams(layoutParams);
}
});
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// 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));
}
}
Result:
This is a little bit off topic from what you guys have been discussing, but I had the same issue with the Google Map layout being re adjusted when user clicks on an EditText on that fragment layout. My problem was that the GoogleMap was a fragment of another view (ViewPager). In order to fix it, I had to programmatically add getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) to the ViewPager Class.
Layout Hierarchy: Activity --> ViewPager --> GoogleMap Fragment. Code added to ViewPager on the onCreate method.
I'm working on a mapping app. And I want to show some views under the MapView.
I'm using the method:
mapView.setAlpha(0.5f);
Nothing happens to the mapView. When I try to apply this method to my buttons it works fine, even applying it to the parent view of the mapView makes every child view transparent except for the mapView.
How can we make the mapView transparent? I have looked into other questions here and I cant seem to find a solution.
Is there some special method in the mapView.getMap() that we can use to make it transparent?
You can set the transparence for the map using View.setAlpha() (documentation). Here is a working example:
activity_maps.xml:
<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">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="THIS TEXT IS VISIBLE"
android:textSize="24sp"
android:gravity="center"/>
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/map"
tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.SupportMapFragment" />
</RelativeLayout>
MapsActivity.java
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
Marker m = googleMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
m.showInfoWindow();
View v = getSupportFragmentManager().findFragmentById(R.id.map).getView();
v.setAlpha(0.5f); // Change this value to set the desired alpha
}
}
The result looks like this (as you see the text is visible because of the map's transparency):
You can do this through the setAlpha(float) method of your MapView reference, like this:
mMapView = (MapView) findViewById(R.id.map);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this);
mMapView.setAlpha(0.5f);
If you are using MapFragment, then just use setAlpha(float) for your MapFragment.
Use a Framelayout where you put your 2 Views (CameraView and MapView) over themselfes.
And use the xml attribute alpha to make the MapView transparent.
I want to set fixed marker in the center point of mapview while dragging map.It has been done at android Map V1 google mapview. But now it's deprecated.Now my question is, is it possible in android Map V2 google mapview ?(I have tried.but map doesn't show)
So you want something like a cross-hairs on the center of map, right?
I have not used MapView. But I have used Map Fragment, and the way i implement a fix marker on the map is use a ImageView, So you will end up with something like below:
<?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/fragment1"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/cross_hairs" />
</RelativeLayout>
You could swap the MapFragment with MapView.
Placing the marker on the map will be inefficient, since you will need to keep updating the marker when the user pans the map.
Hope it helps!
I'm betting you used getMapCenter() which, as per Google Maps for Android v2, no longer available to use. But no worries, just use this:
GoogleMap.getCameraPosition().target
It will return a LatLng object which basically represents the center of the map. You can then use it to reposition the marker to the center every time there's a drag event by assigning an OnCameraChangedListener to your GoogleMap.
yourGMapInstance.setOnCameraChangeListener(new OnCameraChangedListener() {
#Override
public void onCameraChange (CameraPosition position) {
// Get the center of the Map.
LatLng centerOfMap = yourGMapInstance.getCameraPosition().target;
// Update your Marker's position to the center of the Map.
yourMarkerInstance.setPosition(centerOfMap);
}
});
There. I hope this helped!
Notice that setOnCameraChangeListener() has been deprecated, so you can use the new camera listeners (OnCameraIdleListener, OnCameraMoveListener, OnCameraMoveStartedListener, OnCameraMoveCanceledListener), for example:
map.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
#Override
public void onCameraMove() {
// Get the center of the map
LatLng center = map.getCameraPosition().target;
......
}
});
for more information, read this: https://developers.google.com/maps/documentation/android-api/events
Simply goto the XML File: Add Image View in map fragment and set the gravity to center. Then goto the Java File and add the following java code into your onMayReady Function:
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="#+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/linearLayout2" />
<ImageView
android:id="#+id/imageView_map_marker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="17dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:layout_gravity="center"
android:tooltipText="Select Location"
app:srcCompat="#drawable/ic_baseline_location_red" />
mMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
#Override
public void onCameraMove() {
mMap.clear();
binding.imageViewMapMarker.setVisibility(View.VISIBLE);
}
});
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
binding.imageViewMapMarker.setVisibility(View.GONE);
selectedLatitude=mMap.getCameraPosition().target.latitude;
selectedLongitude=mMap.getCameraPosition().target.longitude;
MarkerOptions marker = new MarkerOptions().position(mMap.getCameraPosition().target).title("")
.icon(bitmapDescriptorFromVector(getApplicationContext(), R.drawable.ic_baseline_location_red));
mMap.addMarker(marker);
}
});
I wish to add a marker to a googleMap with an editable title and snippet. The marker should appear when the user does a long click on the map and then the marker should appear showing a title of something like "click to edit".
The code is all up and running except that I can not figure out how to get the title to appear the moment the marker is created. I can only make it appear with a subsequent click on the marker. I can not see anything within MarkerOptions that allows me to do this. Did I miss something?
The option your looking for is not in MarkerOptions it is a function of the Marker itself. Here's a link to the related docs
marker.showInfoWindow();
To call this method you need to have the marker, or a reference to it. If you're doing this on creation it should be easy. Otherwise just store your makers in some collection - like a HashMap so they are easy to find - and you can display the info window whenever you want.
In case you want to display your marker's title and snippet in your own custom way - you may set it in the onMapReadyCallback.
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
View view = getLayoutInflater().inflate(R.layout.marker_info, null);
TextView textViewTitle = (TextView) view.findViewById(R.id.marker_title);
textViewTitle.setText(marker.getTitle());
TextView textViewSnippet = (TextView) view.findViewById(R.id.marker_snippet);
textViewSnippet.setText(marker.getSnippet());
return view;
}
});
And here is my layout file for the same.
marker_info.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/marker_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:gravity="center"/>
<TextView
android:id="#+id/marker_snippet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"/>
</LinearLayout>