Как создать пользовательский растровый маркер с Android map API v2
Я разрабатываю приложение для Android, где я использую API карт Google v2. Мне нужно показать местоположение пользователя на карте с помощью пользовательских маркеров.
Каждый маркер отобразит изображение пользователя по URL-адресу. Изображение должно быть загружено в асинхронном режиме с сервера. См. Прилагаемый скриншот для примера.
Как добавить изображение и пользовательскую информацию в маркер?
![enter image description here]()
Ответы
Ответ 1
В Google Maps API v2 Demo существует класс MarkerDemoActivity
, в котором вы можете увидеть, как настраиваемый образ установлен на GoogleMap.
// Uses a custom icon.
mSydney = mMap.addMarker(new MarkerOptions()
.position(SYDNEY)
.title("Sydney")
.snippet("Population: 4,627,300")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow)));
Поскольку это просто заменяет маркер изображением, вы можете использовать Canvas
для рисования более сложных и причудливых вещей:
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bmp = Bitmap.createBitmap(80, 80, conf);
Canvas canvas1 = new Canvas(bmp);
// paint defines the text color, stroke width and size
Paint color = new Paint();
color.setTextSize(35);
color.setColor(Color.BLACK);
// modify canvas
canvas1.drawBitmap(BitmapFactory.decodeResource(getResources(),
R.drawable.user_picture_image), 0,0, color);
canvas1.drawText("User Name!", 30, 40, color);
// add marker to Map
mMap.addMarker(new MarkerOptions()
.position(USER_POSITION)
.icon(BitmapDescriptorFactory.fromBitmap(bmp))
// Specifies the anchor to be at a particular point in the marker image.
.anchor(0.5f, 1));
Это рисует Canvas canvas1
на GoogleMap mMap
. Код должен (в основном) говорить сам за себя, есть много учебников, как рисовать Canvas
. Вы можете начать с просмотра Canvas и Drawables на странице разработчика Android.
Теперь вы также хотите загрузить изображение с URL-адреса.
URL url = new URL(user_image_url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is);
Вы должны загружать изображение из фонового потока (вы можете использовать AsyncTask или Volley для этого).
После этого вы можете заменить BitmapFactory.decodeResource(getResources(), R.drawable.user_picture_image)
на загруженное изображение bmImg
.
Ответ 2
Альтернативным и простым решением, которое я также использую, является создание настраиваемого макета маркера и преобразование его в растровое изображение.
view_custom_marker.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custom_marker_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/marker_mask">
<ImageView
android:id="@+id/profile_image"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:contentDescription="@null"
android:src="@drawable/avatar" />
</FrameLayout>
Преобразуйте это представление в растровое изображение с помощью кода ниже
private Bitmap getMarkerBitmapFromView(@DrawableRes int resId) {
View customMarkerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.view_custom_marker, null);
ImageView markerImageView = (ImageView) customMarkerView.findViewById(R.id.profile_image);
markerImageView.setImageResource(resId);
customMarkerView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
customMarkerView.layout(0, 0, customMarkerView.getMeasuredWidth(), customMarkerView.getMeasuredHeight());
customMarkerView.buildDrawingCache();
Bitmap returnedBitmap = Bitmap.createBitmap(customMarkerView.getMeasuredWidth(), customMarkerView.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN);
Drawable drawable = customMarkerView.getBackground();
if (drawable != null)
drawable.draw(canvas);
customMarkerView.draw(canvas);
return returnedBitmap;
}
Добавьте свой настраиваемый маркер в обратный вызов готовой карты.
@Override
public void onMapReady(GoogleMap googleMap) {
Log.d(TAG, "onMapReady() called with");
mGoogleMap = googleMap;
MapsInitializer.initialize(this);
addCustomMarker();
}
private void addCustomMarker() {
Log.d(TAG, "addCustomMarker()");
if (mGoogleMap == null) {
return;
}
// adding a marker on map with image from drawable
mGoogleMap.addMarker(new MarkerOptions()
.position(mDummyLatLng)
.icon(BitmapDescriptorFactory.fromBitmap(getMarkerBitmapFromView(R.drawable.avatar))));
}
Для получения более подробной информации, пожалуйста, перейдите по ссылке ниже
Как создать пользовательский маркер с использованием макета?
Ответ 3
Я надеюсь, что еще не поздно поделиться своим решением. До этого вы можете следить за учебником, как указано в документации разработчика Android. Для этого вам необходимо использовать Cluster Manager с defaultRenderer
.
-
Создайте объект, который реализует ClusterItem
public class SampleJob implements ClusterItem {
private double latitude;
private double longitude;
//Create constructor, getter and setter here
@Override
public LatLng getPosition() {
return new LatLng(latitude, longitude);
}
-
Создайте класс рендеринга по умолчанию. Это класс, который выполняет всю работу (раздувая пользовательский маркер/кластер своим стилем). Я использую Universal image loader для загрузки и кэширования изображения.
public class JobRenderer extends DefaultClusterRenderer<Job> {
private final IconGenerator iconGenerator;
private final IconGenerator clusterIconGenerator;
private final ImageView imageView;
private final ImageView clusterImageView;
private final int markerWidth;
private final int markerHeight;
private final String TAG = "ClusterRenderer";
private DisplayImageOptions options;
public JobRenderer(Context context, GoogleMap map, ClusterManager<Job> clusterManager) {
super(context, map, clusterManager);
// initialize cluster icon generator
clusterIconGenerator = new IconGenerator(context.getApplicationContext());
View clusterView = LayoutInflater.from(context).inflate(R.layout.multi_profile, null);
clusterIconGenerator.setContentView(clusterView);
clusterImageView = (ImageView) clusterView.findViewById(R.id.image);
// initialize cluster item icon generator
iconGenerator = new IconGenerator(context.getApplicationContext());
imageView = new ImageView(context.getApplicationContext());
markerWidth = (int) context.getResources().getDimension(R.dimen.custom_profile_image);
markerHeight = (int) context.getResources().getDimension(R.dimen.custom_profile_image);
imageView.setLayoutParams(new ViewGroup.LayoutParams(markerWidth, markerHeight));
int padding = (int) context.getResources().getDimension(R.dimen.custom_profile_padding);
imageView.setPadding(padding, padding, padding, padding);
iconGenerator.setContentView(imageView);
options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.circle_icon_logo)
.showImageForEmptyUri(R.drawable.circle_icon_logo)
.showImageOnFail(R.drawable.circle_icon_logo)
.cacheInMemory(false)
.cacheOnDisk(true)
.considerExifParams(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
}
@Override
protected void onBeforeClusterItemRendered(Job job, MarkerOptions markerOptions) {
ImageLoader.getInstance().displayImage(job.getJobImageURL(), imageView, options);
Bitmap icon = iconGenerator.makeIcon(job.getName());
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(job.getName());
}
@Override
protected void onBeforeClusterRendered(Cluster<Job> cluster, MarkerOptions markerOptions) {
Iterator<Job> iterator = cluster.getItems().iterator();
ImageLoader.getInstance().displayImage(iterator.next().getJobImageURL(), clusterImageView, options);
Bitmap icon = clusterIconGenerator.makeIcon(iterator.next().getName());
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
@Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
return cluster.getSize() > 1;
}
-
Применить диспетчер кластеров в свой класс активности/фрагмента.
public class SampleActivity extends AppCompatActivity implements OnMapReadyCallback {
private ClusterManager<Job> mClusterManager;
private GoogleMap mMap;
private ArrayList<SampleJob> jobs = new ArrayList<SampleJob>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_landing);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setMapToolbarEnabled(true);
mClusterManager = new ClusterManager<Job>(this, mMap);
mClusterManager.setRenderer(new JobRenderer(this, mMap, mClusterManager));
mMap.setOnCameraChangeListener(mClusterManager);
mMap.setOnMarkerClickListener(mClusterManager);
//Assume that we already have arraylist of jobs
for(final Job job: jobs){
mClusterManager.addItem(job);
}
mClusterManager.cluster();
}
-
Результат
![Результат]()
Ответ 4
Из лямбда-ответа я сделал что-то ближе к требованиям.
boolean imageCreated = false;
Bitmap bmp = null;
Marker currentLocationMarker;
private void doSomeCustomizationForMarker(LatLng currentLocation) {
if (!imageCreated) {
imageCreated = true;
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
bmp = Bitmap.createBitmap(400, 400, conf);
Canvas canvas1 = new Canvas(bmp);
Paint color = new Paint();
color.setTextSize(30);
color.setColor(Color.WHITE);
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap imageBitmap=BitmapFactory.decodeResource(getResources(),
R.drawable.messi,opt);
Bitmap resized = Bitmap.createScaledBitmap(imageBitmap, 320, 320, true);
canvas1.drawBitmap(resized, 40, 40, color);
canvas1.drawText("Le Messi", 30, 40, color);
currentLocationMarker = mMap.addMarker(new MarkerOptions().position(currentLocation)
.icon(BitmapDescriptorFactory.fromBitmap(bmp))
// Specifies the anchor to be at a particular point in the marker image.
.anchor(0.5f, 1));
} else {
currentLocationMarker.setPosition(currentLocation);
}
}