Android Google 地图自定义信息窗口
Android Google Maps Custom InfoWindow
我想自己设计一个不同的信息window,但找不到合适的方法。
如图所示:
当我点击标记时,我想在底部显示一个栏。我将在那里提供有关标记的详细信息。 (它将包括名称、地址、图标)并且这些名称、地址必须是可点击的。
有哪些可能的方法(ways)可以做到?
用于设置自定义标记
googleMap.addMarker(iconGenerator.createMarker(latitude, longitude, your_string to display))
您可以使用 com.google.maps.android.ui.IconGenerator
class 生成 Google 地图实用程序的自定义标记。
Gradle 要包含的行是
compile 'com.google.maps.android:android-maps-utils:0.3+
在我的例子中,我不想再添加一个库,所以需要 class 和来自 here..
的数据
public class IconGenerator {
private static final int STYLE_DEFAULT = 1;
private static final int STYLE_WHITE = 2;
private static final int STYLE_RED = 3;
private static final int STYLE_BLUE = 4;
private static final int STYLE_GREEN = 5;
private static final int STYLE_PURPLE = 6;
private static final int STYLE_ORANGE = 7;
private final Context mContext;
private BubbleDrawable mBackground;
private ViewGroup mContainer;
private TextView mTextView;
public IconGenerator(Context context) {
mContext = context;
mBackground = new BubbleDrawable(mContext.getResources());
mContainer = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.amu_text_bubble, null);
RotationLayout mRotationLayout = (RotationLayout) mContainer.getChildAt(0);
mTextView = mRotationLayout.findViewById(R.id.amu_text);
setStyle();
}
private static int getStyleColor(int style) {
switch (style) {
case STYLE_RED:
return 0xffcc0000;
case STYLE_BLUE:
return 0xff0099cc;
case STYLE_GREEN:
return 0xff669900;
case STYLE_PURPLE:
return 0xff9933cc;
case STYLE_ORANGE:
return 0xffff8800;
case STYLE_DEFAULT:
case STYLE_WHITE:
default:
return 0xffffffff;
}
}
private static int getTextStyle(int style) {
switch (style) {
case STYLE_RED:
case STYLE_BLUE:
case STYLE_GREEN:
case STYLE_PURPLE:
case STYLE_ORANGE:
return R.style.amu_Bubble_TextAppearance_Light;
case STYLE_DEFAULT:
case STYLE_WHITE:
default:
return R.style.amu_Bubble_TextAppearance_Dark;
}
}
public MarkerOptions createMarker(double latitude, double longitude, String text) {
LatLng latLng = new LatLng(latitude, longitude);
float mAnchorV = 1F;
float mAnchorU = 0.5F;
return new MarkerOptions().
icon(BitmapDescriptorFactory.fromBitmap(makeIcon(text))).
position(latLng).
anchor(mAnchorU, mAnchorV);
}
private Bitmap makeIcon(CharSequence text) {
if (mTextView != null) {
mTextView.setText(text);
}
return makeIcon();
}
private Bitmap makeIcon() {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mContainer.measure(measureSpec, measureSpec);
int measuredWidth = mContainer.getMeasuredWidth();
int measuredHeight = mContainer.getMeasuredHeight();
mContainer.layout(0, 0, measuredWidth, measuredHeight);
Bitmap r = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
r.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(r);
mContainer.draw(canvas);
return r;
}
private void setStyle() {
setColor(getStyleColor(IconGenerator.STYLE_RED));
setTextAppearance(mContext, getTextStyle(IconGenerator.STYLE_RED));
}
private void setColor(int color) {
mBackground.setColor(color);
setBackground(mBackground);
}
@SuppressWarnings("deprecation")
// View#setBackgroundDrawable is compatible with pre-API level 16 (Jelly Bean).
private void setBackground(Drawable background) {
mContainer.setBackgroundDrawable(background);
// Force setting of padding.
// setBackgroundDrawable does not call setPadding if the background has 0 padding.
if (background != null) {
Rect rect = new Rect();
background.getPadding(rect);
mContainer.setPadding(rect.left, rect.top, rect.right, rect.bottom);
} else {
mContainer.setPadding(0, 0, 0, 0);
}
}
private void setTextAppearance(Context context, int resid) {
if (mTextView != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mTextView.setTextAppearance(resid);
} else
mTextView.setTextAppearance(context, resid);
}
}
}
自定义Window
在为标记创建标记集详细信息并通过 googleMap.setInfoWindowAdapter
的 getInfoContents
方法访问这些详细信息时,还可以使用详细信息设置您的自定义视图。
googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
YourModelClassName detailDto = (YourModelClassName ) marker.getTag();
View v = View.inflate(MapViewActivity.this, R.layout.custom_info_window, null);
// set widget of your custom_layout like below
CustomFTextView txtResourceName = v.findViewById(R.id.txt_resource_name);
CustomFTextView txtResourceAddress = v.findViewById(R.id.txt_resource_address);
ImageView imageViewPic = v.findViewById(R.id.img_event);
if (detailDto != null) {
txtResourceName.setText(detailDto.getResourceName());
txtResourceAddress.setText(detailDto.getAddress());
String mUrl = base_Url + detailDto.getImageUrl();
Picasso.with(MapViewActivity.this).load(mUrl).resize(TARGET_WIDTH, TARGET_HEIGHT).centerInside().into(imageViewPic);
}
return v;
}
});
像这样将数据设置为标记。
this.googleMap.addMarker(new MarkerOptions().position(sydney)).setTag(detailDto);
GoogleMap.InfoWindowAdapter
将显示带有标记的自定义 window 如果您想在屏幕底部显示标记详细信息隐藏自定义 window 并在屏幕上显示自定义视图地图视图
main.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.iphonealsham.speedli.activitys.MapsActivity" />
<LinearLayout
android:id="@+id/linearLayoutCustomView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/textViewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/textViewOtherDetails"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
在 onMarkerClick
中 return true
隐藏 InfoWidow 并显示 customView
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
Log.d("GoogleMap", " click");
//focus the market
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(marker.getPosition()));
if (linearLayoutCustomView.getVisibility() == View.VISIBLE)
linearLayoutCustomView.setVisibility(View.GONE);
else
displayCustomeInfoWindow(marker);
return true;
}
});
}
在视图中设置详细信息
private void displayCustomeInfoWindow(Marker marker) {
linearLayoutCustomView.setVisibility(View.VISIBLE);
TextView textViewTitle = linearLayoutCustomView.findViewById(R.id.textViewTitle);
TextView textViewOtherDetails = linearLayoutCustomView.findViewById(R.id.textViewOtherDetails);
textViewTitle.setText(marker.getTitle());
textViewOtherDetails.setText("LatLong :: " + marker.getPosition().latitude + "," + marker.getPosition().longitude);
}
我想自己设计一个不同的信息window,但找不到合适的方法。
如图所示:
当我点击标记时,我想在底部显示一个栏。我将在那里提供有关标记的详细信息。 (它将包括名称、地址、图标)并且这些名称、地址必须是可点击的。
有哪些可能的方法(ways)可以做到?
用于设置自定义标记
googleMap.addMarker(iconGenerator.createMarker(latitude, longitude, your_string to display))
您可以使用 com.google.maps.android.ui.IconGenerator
class 生成 Google 地图实用程序的自定义标记。
Gradle 要包含的行是
compile 'com.google.maps.android:android-maps-utils:0.3+
在我的例子中,我不想再添加一个库,所以需要 class 和来自 here..
的数据public class IconGenerator {
private static final int STYLE_DEFAULT = 1;
private static final int STYLE_WHITE = 2;
private static final int STYLE_RED = 3;
private static final int STYLE_BLUE = 4;
private static final int STYLE_GREEN = 5;
private static final int STYLE_PURPLE = 6;
private static final int STYLE_ORANGE = 7;
private final Context mContext;
private BubbleDrawable mBackground;
private ViewGroup mContainer;
private TextView mTextView;
public IconGenerator(Context context) {
mContext = context;
mBackground = new BubbleDrawable(mContext.getResources());
mContainer = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.amu_text_bubble, null);
RotationLayout mRotationLayout = (RotationLayout) mContainer.getChildAt(0);
mTextView = mRotationLayout.findViewById(R.id.amu_text);
setStyle();
}
private static int getStyleColor(int style) {
switch (style) {
case STYLE_RED:
return 0xffcc0000;
case STYLE_BLUE:
return 0xff0099cc;
case STYLE_GREEN:
return 0xff669900;
case STYLE_PURPLE:
return 0xff9933cc;
case STYLE_ORANGE:
return 0xffff8800;
case STYLE_DEFAULT:
case STYLE_WHITE:
default:
return 0xffffffff;
}
}
private static int getTextStyle(int style) {
switch (style) {
case STYLE_RED:
case STYLE_BLUE:
case STYLE_GREEN:
case STYLE_PURPLE:
case STYLE_ORANGE:
return R.style.amu_Bubble_TextAppearance_Light;
case STYLE_DEFAULT:
case STYLE_WHITE:
default:
return R.style.amu_Bubble_TextAppearance_Dark;
}
}
public MarkerOptions createMarker(double latitude, double longitude, String text) {
LatLng latLng = new LatLng(latitude, longitude);
float mAnchorV = 1F;
float mAnchorU = 0.5F;
return new MarkerOptions().
icon(BitmapDescriptorFactory.fromBitmap(makeIcon(text))).
position(latLng).
anchor(mAnchorU, mAnchorV);
}
private Bitmap makeIcon(CharSequence text) {
if (mTextView != null) {
mTextView.setText(text);
}
return makeIcon();
}
private Bitmap makeIcon() {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mContainer.measure(measureSpec, measureSpec);
int measuredWidth = mContainer.getMeasuredWidth();
int measuredHeight = mContainer.getMeasuredHeight();
mContainer.layout(0, 0, measuredWidth, measuredHeight);
Bitmap r = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
r.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(r);
mContainer.draw(canvas);
return r;
}
private void setStyle() {
setColor(getStyleColor(IconGenerator.STYLE_RED));
setTextAppearance(mContext, getTextStyle(IconGenerator.STYLE_RED));
}
private void setColor(int color) {
mBackground.setColor(color);
setBackground(mBackground);
}
@SuppressWarnings("deprecation")
// View#setBackgroundDrawable is compatible with pre-API level 16 (Jelly Bean).
private void setBackground(Drawable background) {
mContainer.setBackgroundDrawable(background);
// Force setting of padding.
// setBackgroundDrawable does not call setPadding if the background has 0 padding.
if (background != null) {
Rect rect = new Rect();
background.getPadding(rect);
mContainer.setPadding(rect.left, rect.top, rect.right, rect.bottom);
} else {
mContainer.setPadding(0, 0, 0, 0);
}
}
private void setTextAppearance(Context context, int resid) {
if (mTextView != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mTextView.setTextAppearance(resid);
} else
mTextView.setTextAppearance(context, resid);
}
}
}
自定义Window
在为标记创建标记集详细信息并通过 googleMap.setInfoWindowAdapter
的 getInfoContents
方法访问这些详细信息时,还可以使用详细信息设置您的自定义视图。
googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
YourModelClassName detailDto = (YourModelClassName ) marker.getTag();
View v = View.inflate(MapViewActivity.this, R.layout.custom_info_window, null);
// set widget of your custom_layout like below
CustomFTextView txtResourceName = v.findViewById(R.id.txt_resource_name);
CustomFTextView txtResourceAddress = v.findViewById(R.id.txt_resource_address);
ImageView imageViewPic = v.findViewById(R.id.img_event);
if (detailDto != null) {
txtResourceName.setText(detailDto.getResourceName());
txtResourceAddress.setText(detailDto.getAddress());
String mUrl = base_Url + detailDto.getImageUrl();
Picasso.with(MapViewActivity.this).load(mUrl).resize(TARGET_WIDTH, TARGET_HEIGHT).centerInside().into(imageViewPic);
}
return v;
}
});
像这样将数据设置为标记。
this.googleMap.addMarker(new MarkerOptions().position(sydney)).setTag(detailDto);
GoogleMap.InfoWindowAdapter
将显示带有标记的自定义 window 如果您想在屏幕底部显示标记详细信息隐藏自定义 window 并在屏幕上显示自定义视图地图视图
main.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.iphonealsham.speedli.activitys.MapsActivity" />
<LinearLayout
android:id="@+id/linearLayoutCustomView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/textViewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/textViewOtherDetails"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
在 onMarkerClick
中 return true
隐藏 InfoWidow 并显示 customView
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
Log.d("GoogleMap", " click");
//focus the market
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(marker.getPosition()));
if (linearLayoutCustomView.getVisibility() == View.VISIBLE)
linearLayoutCustomView.setVisibility(View.GONE);
else
displayCustomeInfoWindow(marker);
return true;
}
});
}
在视图中设置详细信息
private void displayCustomeInfoWindow(Marker marker) {
linearLayoutCustomView.setVisibility(View.VISIBLE);
TextView textViewTitle = linearLayoutCustomView.findViewById(R.id.textViewTitle);
TextView textViewOtherDetails = linearLayoutCustomView.findViewById(R.id.textViewOtherDetails);
textViewTitle.setText(marker.getTitle());
textViewOtherDetails.setText("LatLong :: " + marker.getPosition().latitude + "," + marker.getPosition().longitude);
}