Skip to content

Commit

Permalink
feat(android): marker image
Browse files Browse the repository at this point in the history
  • Loading branch information
mym0404 committed Apr 7, 2024
1 parent 3c37458 commit 69f4b05
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 68 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ allprojects {
| isForceShowIcon ||| |
| tintColor ||| |
| image(default symbols) ||| |
| image(local image) | 📦 | 📦 | |
| image(network image) | 📦 | 📦 | |
| image(local image) | 📦 | | |
| image(network image) | 📦 | | |
| image(custom view) ||| |
| caption | 📦 | 📦 | |
| subcaption | 📦 | 📦 | |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.mjstudio.reactnativenavermap.overlay.marker

import com.naver.maps.map.overlay.OverlayImage
import java.util.concurrent.ConcurrentHashMap


object OverlayImages {
private val store: MutableMap<String, OverlayImage> = ConcurrentHashMap()
fun put(uri: String, image: OverlayImage) {
store[uri] = image
}

operator fun get(uri: String): OverlayImage? {
return store[uri]
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,54 @@
package com.mjstudio.reactnativenavermap.overlay.marker

import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.drawable.Animatable
import android.net.Uri
import android.view.View
import androidx.core.view.children
import com.airbnb.android.react.maps.TrackableView
import com.airbnb.android.react.maps.ViewChangesTracker
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.interfaces.DraweeController
import com.facebook.drawee.view.DraweeHolder
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.image.CloseableStaticBitmap
import com.facebook.imagepipeline.image.ImageInfo
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.facebook.react.uimanager.ThemedReactContext
import com.mjstudio.reactnativenavermap.event.NaverMapOverlayTapEvent
import com.mjstudio.reactnativenavermap.overlay.RNCNaverMapOverlay
import com.mjstudio.reactnativenavermap.util.emitEvent
import com.naver.maps.map.NaverMap
import com.naver.maps.map.overlay.Marker
import com.naver.maps.map.overlay.OverlayImage
import com.naver.maps.map.util.MarkerIcons
import debugE
import kotlin.math.max


@SuppressLint("ViewConstructor")
class RNCNaverMapMarker(val reactContext: ThemedReactContext) :
RNCNaverMapOverlay<Marker>(reactContext) {
RNCNaverMapOverlay<Marker>(reactContext), TrackableView {
private var imageHolder: DraweeHolder<GenericDraweeHierarchy>? = null
private var customView: View? = null
private var customViewBitmap: Bitmap? = null
private var lastUri: String? = null

init {
imageHolder = DraweeHolder.create(createDraweeHierarchy(), context)?.apply {
onAttach()
}
}

override val overlay: Marker by lazy {
Marker().apply {
setOnClickListener {
Expand All @@ -36,5 +74,166 @@ class RNCNaverMapMarker(val reactContext: ThemedReactContext) :
override fun onDropViewInstance() {
overlay.map = null
overlay.onClickListener = null
imageHolder?.onDetach()
}

fun setCustomView(view: View, index: Int) {
super.addView(view, index)
if (view.layoutParams == null) {
view.setLayoutParams(
LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
)
)
}
ViewChangesTracker.getInstance().addMarker(this)
customView = view
updateCustomView()
}

fun removeCustomView(index: Int) {
customView = null
ViewChangesTracker.getInstance().removeMarker(this)
if (customViewBitmap != null && !customViewBitmap!!.isRecycled) customViewBitmap!!.recycle()
setImage(lastUri)
super.removeView(children.elementAt(index))
}

override fun requestLayout() {
super.requestLayout()
if (childCount == 0 && customView != null) {
customView = null
updateCustomView()
}
}

private fun updateCustomView() {
if (customViewBitmap == null || customViewBitmap!!.isRecycled ||
customViewBitmap?.getWidth() != overlay.width ||
customViewBitmap?.getHeight() != overlay.height
) {
customViewBitmap = Bitmap.createBitmap(
max(1, overlay.width),
max(1, overlay.height),
Bitmap.Config.ARGB_4444
)
}
if (customView != null) {
customViewBitmap?.also { bitmap ->
bitmap.eraseColor(Color.TRANSPARENT)
val canvas = Canvas(bitmap)
draw(canvas)
setOverlayImage(OverlayImage.fromBitmap(bitmap))
}
}
}

override fun updateCustomForTracking(): Boolean {
return true
}

override fun update(width: Int, height: Int) {
updateCustomView();
}

fun setImage(uri: String?) {
lastUri = uri
debugE(uri)
uri?.let { uri ->
val defaultIcons = when (uri) {
"blue" -> MarkerIcons.BLUE
"gray" -> MarkerIcons.GRAY
"green" -> MarkerIcons.GREEN
"lightblue" -> MarkerIcons.LIGHTBLUE
"pink" -> MarkerIcons.PINK
"red" -> MarkerIcons.RED
"yellow" -> MarkerIcons.YELLOW
"black" -> MarkerIcons.BLACK
"lowDensityCluster" -> MarkerIcons.CLUSTER_LOW_DENSITY
"mediumDensityCluster" -> MarkerIcons.CLUSTER_MEDIUM_DENSITY
"highDensityCluster" -> MarkerIcons.CLUSTER_HIGH_DENSITY
else -> null
}
if (defaultIcons != null) {
setOverlayImage(defaultIcons)
return
}
val overlayImage = OverlayImages[uri]
if (overlayImage != null) {
setOverlayImage(overlayImage)
return;
}


if (uri.startsWith("http://") ||
uri.startsWith("https://") ||
uri.startsWith("file://") ||
uri.startsWith("asset://")
) {
val imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse(uri))
.build()
val dataSource: DataSource<CloseableReference<CloseableImage>> =
Fresco.getImagePipeline()
.fetchDecodedImage(imageRequest, this)
val controller: DraweeController = Fresco.newDraweeControllerBuilder()
.setImageRequest(imageRequest)
.setControllerListener(object : BaseControllerListener<ImageInfo?>() {
override fun onFinalImageSet(
id: String,
imageInfo: ImageInfo?,
animatable: Animatable?
) {
var imageReference: CloseableReference<CloseableImage>? = null
var overlayImage: OverlayImage? = null
try {
imageReference = dataSource.result
if (imageReference != null) {
val image = imageReference.get()
if (image is CloseableStaticBitmap) {
var bitmap: Bitmap? = image.underlyingBitmap
if (bitmap != null) {
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
overlayImage = OverlayImage.fromBitmap(bitmap)
OverlayImages.put(uri, overlayImage)
}
}
}
} finally {
dataSource.close()
if (imageReference != null) {
CloseableReference.closeSafely(imageReference)
}
}
overlayImage?.let { setOverlayImage(it) }
}
})
.setOldController(imageHolder!!.controller)
.build()
imageHolder!!.setController(controller)
} else {
OverlayImage.fromResource(getRidFromName(uri)).run {
OverlayImages.put(uri, this)
setOverlayImage(this)
}
}
}
}

private fun setOverlayImage(image: OverlayImage?) {
overlay.icon = image ?: MarkerIcons.GREEN
}

private fun createDraweeHierarchy(): GenericDraweeHierarchy {
return GenericDraweeHierarchyBuilder(resources)
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
.setFadeDuration(0)
.build()
}

@SuppressLint("DiscouragedApi")
private fun getRidFromName(name: String): Int {
return context.resources.getIdentifier(name, "drawable", context.packageName)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mjstudio.reactnativenavermap.overlay.marker

import android.graphics.Color
import android.view.View
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.ThemedReactContext
Expand All @@ -13,7 +14,6 @@ import com.mjstudio.reactnativenavermap.util.isValidNumber
import com.mjstudio.reactnativenavermap.util.registerDirectEvent
import com.naver.maps.map.overlay.Marker
import com.naver.maps.map.overlay.Marker.SIZE_AUTO
import com.naver.maps.map.util.MarkerIcons


class RNCNaverMapMarkerManager : RNCNaverMapMarkerManagerSpec<RNCNaverMapMarker>() {
Expand All @@ -39,6 +39,17 @@ class RNCNaverMapMarkerManager : RNCNaverMapMarkerManagerSpec<RNCNaverMapMarker>
this?.overlay?.run(fn)
}

override fun addView(parent: RNCNaverMapMarker?, child: View, index: Int) {
parent?.setCustomView(child, index)
}

override fun removeView(parent: RNCNaverMapMarker?, view: View) {
}

override fun removeViewAt(parent: RNCNaverMapMarker?, index: Int) {
parent?.removeCustomView(index)
}

@ReactProp(name = "position")
override fun setPosition(view: RNCNaverMapMarker, value: ReadableMap?) = view.withOverlay {
value.getLatLng()?.run {
Expand Down Expand Up @@ -148,56 +159,8 @@ class RNCNaverMapMarkerManager : RNCNaverMapMarkerManagerSpec<RNCNaverMapMarker>
}

@ReactProp(name = "image")
override fun setImage(view: RNCNaverMapMarker?, value: String?) = view.withOverlay {
when (value) {
"blue" -> {
it.icon = MarkerIcons.BLUE
}

"gray" -> {
it.icon = MarkerIcons.GRAY
}

"green" -> {
it.icon = MarkerIcons.GREEN
}

"lightblue" -> {
it.icon = MarkerIcons.LIGHTBLUE
}

"pink" -> {
it.icon = MarkerIcons.PINK
}

"red" -> {
it.icon = MarkerIcons.RED
}

"yellow" -> {
it.icon = MarkerIcons.YELLOW
}

"black" -> {
it.icon = MarkerIcons.BLACK
}

"lowDensityCluster" -> {
it.icon = MarkerIcons.CLUSTER_LOW_DENSITY
}

"mediumDensityCluster" -> {
it.icon = MarkerIcons.CLUSTER_MEDIUM_DENSITY
}

"highDensityCluster" -> {
it.icon = MarkerIcons.CLUSTER_HIGH_DENSITY
}

else -> {
it.icon = MarkerIcons.GREEN
}
}
override fun setImage(view: RNCNaverMapMarker?, value: String?) {
view?.setImage(value)
}


Expand Down
4 changes: 2 additions & 2 deletions android/src/newarch/RNCNaverMapMarkerManagerSpec.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.mjstudio.reactnativenavermap

import android.view.ViewGroup
import com.facebook.react.uimanager.SimpleViewManager
import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.viewmanagers.RNCNaverMapMarkerManagerDelegate
import com.facebook.react.viewmanagers.RNCNaverMapMarkerManagerInterface

abstract class RNCNaverMapMarkerManagerSpec<T : ViewGroup> : SimpleViewManager<T>(),
abstract class RNCNaverMapMarkerManagerSpec<T : ViewGroup> : ViewGroupManager<T>(),
RNCNaverMapMarkerManagerInterface<T> {
private val mDelegate: ViewManagerDelegate<T>

Expand Down
17 changes: 11 additions & 6 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
type NaverMapViewRef,
type Region,
NaverMapCircleOverlay,
NaverMapMarkerOverlay,
} from '@mj-studio/react-native-naver-map';
import Slider from '@react-native-community/slider';
import { request, PERMISSIONS } from 'react-native-permissions';
Expand Down Expand Up @@ -81,12 +82,16 @@ export default function App() {
// }
onTapMap={(args) => console.log(`Map Tapped: ${formatJson(args)}`)}
>
{/*<NaverMapMarkerOverlay*/}
{/* latitude={33.1165607356}*/}
{/* longitude={126.26599018}*/}
{/* onTap={() => console.log(1)}*/}
{/* image={'black'}*/}
{/*/>*/}
<NaverMapMarkerOverlay
latitude={33.1165607356}
longitude={126.26599018}
onTap={() => console.log(1)}
image={require('./logo180.png')}
width={32}
height={32}
>
<View style={{ backgroundColor: 'red', width: 50, height: 50 }} />
</NaverMapMarkerOverlay>
<NaverMapCircleOverlay
latitude={33.17827398}
longitude={126.349895729}
Expand Down
Binary file added example/src/logo180.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 69f4b05

Please sign in to comment.