I'm using mapbox-sdk android for location tracking. I want to add few custom markers to the map in specified location. But the below code doesn't works for me.
MarkerOptions options = new MarkerOptions();
options.title("pos");
IconFactory iconFactory = IconFactory.getInstance(MainActivity.this);
Icon icon = iconFactory.fromResource(R.drawable.home);
options.icon(icon);
options.position(new LatLng(80.27, 13.09));
mapboxMap.addMarker(options);
I use mapox-sdk:6.0.1
use this:
private fun addMarkerIconsToMap(loadedMapStyle: Style) {
BitmapUtils.getBitmapFromDrawable(getDrawable(R.drawable.red_marker))?.let {
loadedMapStyle.addImage("icon-id", it)
}
if(!locationList.isNullOrEmpty()){
val feature: ArrayList<Feature> = ArrayList()
for (x in 0 until locationList.size){
feature.add(Feature.fromGeometry(Point.fromLngLat(locationList[x].long, locationList[x].lat)))
}
loadedMapStyle.addSource(GeoJsonSource("source-id",
FeatureCollection.fromFeatures(feature)
)
)
loadedMapStyle.addLayer(SymbolLayer("layer-id", "source-id").withProperties(
iconImage("icon-id"),
iconOffset(arrayOf(0f, -8f))
)
)
}
}
inside locationList is Array of long: Double and lat: Double
YourActivity :
class YourActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mapboxMap: MapboxMap
...
}
and then override :
override fun onMapReady(mapboxMap: MapboxMap) {
mapboxMap.setStyle(Style.MAPBOX_STREETS){
addMarkerIconsToMap(it)
}
this.mapboxMap = mapboxMap
}
This is how I would add a custom marker (from a Compose perspective).
(You can either do it from the viewModel depending on your program structure)
AndroidView(
factory = { mapView }, modifier = Modifier.fillMaxWidth()
) { mView ->
val bitmap = bitmapFromDrawableRes(context, R.drawable.chicken_marker)!!
val annotation = mView.annotations
val pointManager = annotation.createPointAnnotationManager()
list.forEach { point ->
val pointOptions = PointAnnotationOptions()
.withPoint(point)
.withIconImage(bitmap)
pointManager.create(pointOptions.apply { iconSize = 0.8 })
}
Here's the functions used to get the drawable(".svg",".png",".jpeg")
private fun bitmapFromDrawableRes(context: Context, #DrawableRes resourceId: Int): Bitmap? =
convertDrawableToBitmap(AppCompatResources.getDrawable(context, resourceId))
private fun convertDrawableToBitmap(sourceDrawable: Drawable?): Bitmap? {
if (sourceDrawable == null) {
return null
}
return if (sourceDrawable is BitmapDrawable) {
sourceDrawable.bitmap
} else {
// copying drawable object to not manipulate on the same reference
val constantState = sourceDrawable.constantState ?: return null
val drawable = constantState.newDrawable().mutate()
val bitmap: Bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth, drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
bitmap
}
}
Related
In the code below I get an error Val cannot be reassigned, I dont know how can I recreate the object ? i am new to kotlin and I am just trying to update a code that i found somewhere... trying to understand how to modify it.
I understand it is final and it is being called from another class like this
another class
val polyLine = RoadManager.buildRoadOverlay(road)
PanRoad = newRoad(
polyLine = polyLine,
colorRoad = colorRoad,
roadWidth = roadWidth,
showPoiMarker = showPoiMarker,
listInterestPoints = listInterestPoints,
)
I tried changin it to val to var like this var polyLine = RoadManager.buildRoadOverlay(road) still nothing.
Below is the class that is giving errors
private fun newRoad(
polyLine: Polyline,
colorRoad: Int?,
showPoiMarker: Boolean,
listInterestPoints: List<GeoPoint>,
roadWidth: Float,
bitmapIcon: Bitmap? = null,
): PanRoad {
print(message = "pannam createRoad called")
polyLine.setOnClickListener { _, _, eventPos ->
methodChannel.invokeMethod("receiveSinglePress", eventPos?.toHashMap())
true
}
/// set polyline color
val polygonPaint = Paint().apply {
color = Color.BLUE
style = Paint.Style.FILL
}
val outlinerPaint = Paint().apply {
color = Color.DKGRAY
style = Paint.Style.STROKE
strokeWidth = 2f
}
polyLine.outlinePaint = Paint().apply {
color = colorRoad ?: Color.GREEN
style = Paint.Style.STROKE
strokeWidth = 2f
strokeCap = Cap.ROUND
strokeJoin = Paint.Join.ROUND
}
val iconsRoads = customRoadMarkerIcon
when {
(iconsRoads.isEmpty() && bitmapIcon != null) -> {
iconsRoads[Constants.STARTPOSITIONROAD] = bitmapIcon
iconsRoads[Constants.MIDDLEPOSITIONROAD] = bitmapIcon
iconsRoads[Constants.ENDPOSITIONROAD] = bitmapIcon
}
iconsRoads.isNotEmpty() && bitmapIcon != null -> {
iconsRoads[Constants.MIDDLEPOSITIONROAD] = bitmapIcon
if (!iconsRoads.containsKey(Constants.STARTPOSITIONROAD)) {
iconsRoads[Constants.STARTPOSITIONROAD] = bitmapIcon
}
if (!iconsRoads.containsKey(Constants.ENDPOSITIONROAD)) {
iconsRoads[Constants.ENDPOSITIONROAD] = bitmapIcon
}
}
}
val PanRoad = PanRoad(
context,
map!!,
interestPoint = if (showPoiMarker) listInterestPoints else emptyList(),
showInterestPoints = showPoiMarker
)
PanRoad.let { roadF ->
if (showPoiMarker) {
roadF.markersIcons = iconsRoads
}
polyLine.outlinePaint.strokeWidth = roadWidth
roadF.road = polyLine
folderRoad.items.add(roadF)
}
return PanRoad
}
The error occurs at polyLine.outlinePaint
I assume the Polyline class you're working with is from org.osmdroid.views.overlay, which only provides a getOutlinePaint as can be seen in its JavaDoc. However, there is no setOutlinePaint. From Kotlins point of view outlinePaint is therefore a val which cannot be reassigned.
It think instead of reassigning the outlinePaint field you instead want to retrieve a reference to the Paint object stored in the field and modify it directly. Something like the following might work, however I'm unable to verify this at the moment.
val outlinePaint = polyLine.outlinePaint
outlinePaint.color = Color.GREEM
outlinePaint.style = Paint.Style.STROKE
or if using apply is preferred
polyLine.outlinePaint.apply {
color = Color.GREEM
style = Paint.Style.STROKE
}
I am working On Google map in android and Image not displayed when i set in My customView Below in function createCustomMarker().Please recommend me if doing some wrong. But I set the drawable from drawable folder then displayed But not from String url.
override fun onMapReady(googleMap: GoogleMap?) {
mMap = googleMap
mMap?.animateCamera(CameraUpdateFactory.zoomTo(16.0f))
mMap?.mapType = GoogleMap.MAP_TYPE_NORMAL
mMap?.setMinZoomPreference(6.0f)
mMap?.setMaxZoomPreference(21.0f)
mMap?.isIndoorEnabled = false
mMap?.isMyLocationEnabled = true
val coordinate =
LatLng(prefs?.current_lati?.toDouble()!!, prefs?.current_longi?.toDouble()!!) //Store these lat lng values somewhere. These should be constant.
val location = CameraUpdateFactory.newLatLngZoom(
coordinate, 15f
)
for(i in 0..arraylist?.size){
var lat=arraylist?.get(i)?.latitude
var longi=arraylist?.get(i)?.longitude
mMap!!.addMarker(MarkerOptions().position(LatLng(lat!!,longi!!)).icon(BitmapDescriptorFactory.fromBitmap(createCustomMarker( requireContext(),arraylist?.get(i)!!.image))))}
mMap!!.moveCamera(CameraUpdateFactory.newLatLng(locationArrayList!![i]))
mMap!!.animateCamera(location)
}
private fun createCustomMarker(context: Context, userImage: String): Bitmap {
val marker: View =
(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater).inflate(
R.layout.lay_cutom_marker,
null
)
val markerImage: ImageView = marker.findViewById(R.id.img_res)
var bmp: Bitmap? = null
// val url = URL(userImage)
Glide.with(context).load(userImage)
.placeholder(R.drawable.ic_user).error(R.drawable.ic_user).into(markerImage)
val displayMetrics = DisplayMetrics()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
context.display?.getRealMetrics(displayMetrics)
} else {
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
}
marker.layoutParams = ViewGroup.LayoutParams(52, ViewGroup.LayoutParams.WRAP_CONTENT)
marker.measure(displayMetrics.widthPixels, displayMetrics.heightPixels)
marker.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)
marker.buildDrawingCache()
bmp = Bitmap.createBitmap(
marker.measuredWidth, marker.measuredHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bmp)
marker.draw(canvas)
return bmp
}
Maybe it is because of you make icon after that image is loading in drawable as you load an image. you need to increase wait time until image has been loaded after that do all stuff regarding iconGenerator.
I created a ViewRenderable to go underneath my GLB model, but it doesn't seem to result in any shadow being cast on the viewRenderable.
What am I doing wrong?
class ShadowSelectionVisualizer : SelectionVisualizer {
private val footprintNode: Node = Node()
fun setFootprintRenderable(viewRenderable: ViewRenderable) {
val copyRenderable = viewRenderable.makeCopy()
copyRenderable.verticalAlignment = ViewRenderable.VerticalAlignment.CENTER
val rotation1: Quaternion = Quaternion.axisAngle(Vector3(1.0f, 0.0f, 0.0f), 90f)
footprintNode.renderable = copyRenderable
footprintNode.localRotation = rotation1
}
override fun applySelectionVisual(node: BaseTransformableNode) {
if (node.collisionShape is Box) {
val box: Box = node.collisionShape as Box
val vector3: Vector3 = box.size
(footprintNode.renderable as ViewRenderable).sizer = ViewSizer {
val bound = if (vector3.x > vector3.z) vector3.x else vector3.z
Vector3(bound, bound, 0.0f)
}
footprintNode.setParent(node)
}
}
override fun removeSelectionVisual(node: BaseTransformableNode?) {
footprintNode.setParent(null)
}
}
myModelRenderable.isShadowCaster = true
val selectionVisualizer = ShadowSelectionVisualizer()
val transformationSystem = TransformationSystem(resources.displayMetrics, selectionVisualizer)
ViewRenderable.builder()
.setView(
context, R.layout.shadow_receiver
)
.setRegistryId("someId.glb")
.build()
.thenAccept { viewRenderable: ViewRenderable ->
viewRenderable.isShadowCaster = false
viewRenderable.isShadowReceiver = true
selectionVisualizer.setFootprintRenderable(viewRenderable)
}
viewRenderable.isShadowCaster = false
Set this to true. More information here: https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/Renderable#isShadowCaster()
The problem
If I use the following helper / extension I will get an exception IBitmapDescriptorFactory is not initialized.
I checked Stackoverflow, some of them recommend to create a local property of the factory and than assign it but this does also not work.
Android Studio shows me the icon on the right side, because of this I think the asset has been added correctly.
Source
fun Webcam.toMarkerOptions(): MarkerOptions {
return MarkerOptions()
.title(name)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_map_webcam))
.position(coordinate.toLngLat())
}
Source 2 which also crashes
fun MarkerOptions.icon(context: Context, #DrawableRes vectorDrawable: Int): MarkerOptions {
this.icon(ContextCompat.getDrawable(context, vectorDrawable)?.run {
setBounds(0, 0, intrinsicWidth, intrinsicHeight)
val bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
draw(Canvas(bitmap))
BitmapDescriptorFactory.fromBitmap(bitmap)
})
return this
}
I have created the MapMarker composable method for this which takes resourceId:
#Composable
fun MapMarker(
context: Context,
position: LatLng,
title: String,
snippet: String,
#DrawableRes iconResourceId: Int
) {
val icon = bitmapDescriptor(
context, iconResourceId
)
Marker(
position = position,
title = title,
snippet = snippet,
icon = icon,
)
}
where bitmapDescriptor:
fun bitmapDescriptor(
context: Context,
vectorResId: Int
): BitmapDescriptor? {
// retrieve the actual drawable
val drawable = ContextCompat.getDrawable(context, vectorResId) ?: return null
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
val bm = Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
// draw it onto the bitmap
val canvas = android.graphics.Canvas(bm)
drawable.draw(canvas)
return BitmapDescriptorFactory.fromBitmap(bm)
}
For more details: https://erselankhan.medium.com/jetpack-compose-custom-google-map-marker-erselan-khan-e6e04178a30b
I used MapGestureListener to compare each time the coords of the clicked area and the coords of the marker and if they're at the same coords then I'm good to go but it just won't work because of the relative altitude change that doesn't assure the accuracy of getting the clicked position.
mpView.addMapGestureListener(object : MapGestureAdapter() {
override fun onMapClicked(e: MotionEvent?, isTwoFingers: Boolean): Boolean {
val clickedArea=mpView.geoCoordinatesFromPoint(Math.round(e!!.getX()), Math.round(e.getY()))
for (marker : MapMarker in markerList )
{
val dist=clickedArea!!.distanceTo(marker.position)
if (dist< 2)
{
val positionMarker = markerList.indexOf(marker)
val positionLastMarker = markerList.indexOf(mSelectedMarker!!)
val markerNumber = positionMarker +1
val lastMarkerNumber = positionLastMarker + 1
travelStep = travelStepList.get(markerNumber -1)
configTeaser(travelStep)
}
}
return false
}
})
I've managed to do it , i just had to call the "requestObjectsAtPoint" inside the MapGesture listener and do some workaround ,here's the code :
mpView.addMapGestureListener(object : MapGestureAdapter() {
override fun onMapClicked(e: MotionEvent?, isTwoFingers: Boolean): Boolean {
mpView.requestObjectsAtPoint(e!!.getX(),e.getY(), RequestObjectCallback { objects, x, y ->
for (marker : ViewObject in objects )
{
if (marker.objectType==1)
{
if ((marker as MapObject).mapObjectType==1)
{
val positionMarker = markerList.indexOf(marker)
val positionLastMarker = markerList.indexOf(mSelectedMarker!!)
val markerNumber = positionMarker +1
val lastMarkerNumber = positionLastMarker + 1
mSelectedMarker = marker as MapMarker
travelStep = travelStepList.get(markerNumber -1)
configTeaser(travelStep)
}
}
}
})
return true
}
})