How to move a map under a marker?

2019-01-16 10:15发布

问题:

Suppose that we have a centered marker on the map, when we move the map with our fingers we can see that marker would no longer displayed when you got out of bounds of the area. So how can we make a marker that would remain always on the center of the map although we move the map anywhere? There is an app named UBER and they provide this feature, you don't drag and drop the marker you just move the map and the marker remained it's position.

Here is a screenshot:

As you can see green marker is on the center of screen when we move the map it remained its place but shows the new position when the user stop moving the map. How can we do like this?

I have a code that shows the address when you drag&drop the marker, how about displaying the address again but this time not by dragging, moving the map? Hope you can understand any ideas would be great.

public class MainActivity extends AbstractMapActivity implements
    OnNavigationListener, OnInfoWindowClickListener,
    OnMarkerDragListener {
  private static final String STATE_NAV="nav";
  private static final int[] MAP_TYPE_NAMES= { R.string.normal,
    R.string.hybrid, R.string.satellite, R.string.terrain };
  private static final int[] MAP_TYPES= { GoogleMap.MAP_TYPE_NORMAL,
    GoogleMap.MAP_TYPE_HYBRID, GoogleMap.MAP_TYPE_SATELLITE,
    GoogleMap.MAP_TYPE_TERRAIN };
private GoogleMap map=null;
String filterAddress = "";
Marker marker;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (readyToGo()) {
        setContentView(R.layout.activity_main);

        SupportMapFragment mapFrag=
            (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);

        mapFrag.setRetainInstance(true);
        initListNav();

        map=mapFrag.getMap();

        if (savedInstanceState == null) {
            CameraUpdate center=
                CameraUpdateFactory.newLatLng(new LatLng(
                        41.003739,
                        28.999572));
            CameraUpdate zoom=CameraUpdateFactory.zoomTo(10);

            map.moveCamera(center);
            map.animateCamera(zoom);

            addMarker(map, 41.003739, 28.999572, R.string.un, R.string.united_nations);

              map.setInfoWindowAdapter(new PopupAdapter(getLayoutInflater()));
              map.setOnInfoWindowClickListener(this);
              map.setOnMarkerDragListener(this);
        }
    }
}

@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
    map.setMapType(MAP_TYPES[itemPosition]);

    return(true);
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);

    savedInstanceState.putInt(STATE_NAV,
            getSupportActionBar().getSelectedNavigationIndex());
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
getSupportActionBar().setSelectedNavigationItem(savedInstanceState.getInt(STATE_NAV));
}

@Override
public void onInfoWindowClick(Marker marker) {
    Toast.makeText(this, marker.getTitle(), Toast.LENGTH_LONG).show();
}

@Override
public void onMarkerDragStart(Marker marker) {
    LatLng position=marker.getPosition();

    Log.d(getClass().getSimpleName(), String.format("Drag from %f:%f",
            position.latitude,
            position.longitude));
}

@Override
public void onMarkerDrag(Marker marker) {
    LatLng position=marker.getPosition();

    Log.d(getClass().getSimpleName(),
            String.format("Dragging to %f:%f", position.latitude,
                    position.longitude));
}

@Override
public void onMarkerDragEnd(Marker marker) {
    LatLng position=marker.getPosition();

    String filterAddress = "";
    Geocoder geoCoder = new Geocoder(
            getBaseContext(), Locale.getDefault());
    try {
        List<Address> addresses = geoCoder.getFromLocation(
                position.latitude, 
                position.longitude, 1);

        if (addresses.size() > 0) {
            for (int index = 0; 
            index < addresses.get(0).getMaxAddressLineIndex(); index++)
                filterAddress += addresses.get(0).getAddressLine(index) + " ";
        }
    }catch (IOException ex) {        
        ex.printStackTrace();
    }catch (Exception e2) {
        // TODO: handle exception
        e2.printStackTrace();
    } 
    Log.d(getClass().getSimpleName(),
            String.format("Dragging to %f:%f", position.latitude,
                    position.longitude));
    TextView myTextView = (TextView) findViewById(R.id.test);

    myTextView.setText("Address is: " + filterAddress);

}

private void initListNav() {
    ArrayList<String> items=new ArrayList<String>();
    ArrayAdapter<String> nav=null;
    ActionBar bar=getSupportActionBar();

    for (int type : MAP_TYPE_NAMES) {
        items.add(getString(type));
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        nav=
            new ArrayAdapter<String>(
                    bar.getThemedContext(),
                    android.R.layout.simple_spinner_item,
                    items);
    }
    else {
        nav=
            new ArrayAdapter<String>(
                    this,
                    android.R.layout.simple_spinner_item,
                    items);
    }

    nav.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    bar.setListNavigationCallbacks(nav, this);
}

private void addMarker(GoogleMap map, double lat, double lon,
        int title, int snippet)

{
    map.addMarker(new MarkerOptions().position(new LatLng(lat, lon))
            .icon(BitmapDescriptorFactory.fromResource(R.drawable.pin))

            .draggable(true));
}
    }

Here is the xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/img_header" >

<fragment
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.SupportMapFragment" />

<TextView
    android:id="@+id/test"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:layout_alignParentRight="true"
    android:text="Address : "
    android:textColor="#FF0000"
    android:textSize="22sp" />
</RelativeLayout>

回答1:

Two easy steps:

Step 1

I used a RelativeLayout as parent of fragment with map and center in it an ImageView (which will do as the centered map marker just like in uber or easy taxi apps):

<!-- Map and ImageView in center for simulating the map marker -->
<RelativeLayout
    android:id="@+id/confirm_address_map_wrapper"
    android:layout_width="match_parent"
    android:layout_height="220dp">

    <fragment
        android:id="@+id/confirm_address_map_fragment"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        />
    <!-- Image View that acts as map marker notice centerInParent-->

     <View
        android:id="@+id/view"
        android:layout_width="1dp"
        android:layout_height="1dp"
        android:layout_centerInParent="true"/>


    <ImageView
        android:id="@+id/confirm_address_map_custom_marker"
        android:layout_width="@dimen/ICON_DEFAULT_SIZE"
        android:layout_height="@dimen/ICON_DEFAULT_SIZE"
        android:layout_above="@+id/view"
        android:layout_centerHorizontal="true"
        android:src="@mipmap/my_map_marker"/>
</RelativeLayout>

Step 2

onMapReady() method at my activity I use googleMap instance method setOnCameraChangeListener() that lets me listen when the map is used and get latitude and longitude based on the center of camera position:

    @Override
    public void onMapReady(GoogleMap googleMap) {

        googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition cameraPosition) {

           Log.i("centerLat",cameraPosition.target.latitude);

           Log.i("centerLong",cameraPosition.target.longitude);
        }
    });

}

UPDATE:
OnCameraChangeListener is deprecated . Please use OnCameraIdleListener:
[Source: https://stackoverflow.com/a/38732283/421467]



回答2:

I was not able to get the Uber app effect, however I was able to do something similar, perhaps it will do just fine for your solution making use of the GoogleMap.OnCameraChangeListener.

Activity:

public class MyActivity extends Activity implements OnCameraChangeListener {

    ...

    @Override
    public void onCameraChange(CameraPosition position) {
        mMap.clear();
        mMap.addMarker( new MarkerOptions()
            .position( position.target )
            .title( position.toString() )
        );
    }

    ...

}

The problem is, the marker is not drawn while the camera is being moved. However, it seems as though you have already created an overlay of a marker. So with an overlay it should work like the Uber application.

I hope this helps, even the question is a few months old, perhaps it will benefit future developers.

Kind regards Miki



回答3:

If you are using Fragment to display your google map, put the ImageView inside the Fragment to overlay your customized marker such that your marker remains fixed when you are moving your map. Follow the code for xml file:

<fragment
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.MapFragment" >

    <ImageView
        android:id="@+id/pin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:contentDescription="@null"
        android:src="@drawable/pin" />
</fragment>

In the activity.java file use this:

ImageView pinButton = (ImageView) findViewById(R.id.pin);

use setOnCameraChangeListener() to get latitude and longitude based on the center of camera position or follow the answer provided by @androidPlusPlus



回答4:

Check this answer

first : add an imageview to the same layout and position equal to center. second: to get the coordinate of the center of the map use the following approach

1_ get viewgroup ( FrameLayout ) in my case where the map fragment is located.

 - FrameLayout myContainer = (FrameLayout) findViewById(R.id.content_frame);
    int mapHeight = myContainer.getHeight();
    int mapWidth = myContainer.getWidth();
2_ use setOnCameraChangeListener and on camera change get the coordinates:

LatLng center = mMap.getCameraPosition().target;

And also here is my complete solution