From b73c35f73d50c3999a9259cb140dcb0823aec55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Wed, 2 Oct 2024 22:44:50 +0200 Subject: [PATCH] feat: implement custom image handling on Android --- .../main/java/com/rcttabview/RCTTabView.kt | 67 ++++++++++++++++--- .../com/rcttabview/RCTTabViewViewManager.kt | 7 +- example/src/Examples/MaterialBottomTabs.tsx | 10 +-- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/com/rcttabview/RCTTabView.kt b/android/src/main/java/com/rcttabview/RCTTabView.kt index 152037a..85e4f1d 100644 --- a/android/src/main/java/com/rcttabview/RCTTabView.kt +++ b/android/src/main/java/com/rcttabview/RCTTabView.kt @@ -1,15 +1,28 @@ package com.rcttabview +import android.annotation.SuppressLint import android.content.Context +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.net.Uri import android.view.Choreographer import android.view.MenuItem -import androidx.appcompat.content.res.AppCompatResources +import com.facebook.common.references.CloseableReference +import com.facebook.datasource.DataSources +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.imagepipeline.image.CloseableBitmap +import com.facebook.imagepipeline.request.ImageRequestBuilder import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.WritableMap +import com.facebook.react.views.imagehelper.ImageSource +import com.facebook.react.views.imagehelper.ImageSource.Companion.getTransparentBitmapImageSource import com.google.android.material.bottomnavigation.BottomNavigationView + class ReactBottomNavigationView(context: Context) : BottomNavigationView(context) { private val ANIMATION_DURATION: Long = 300 + private val icons: MutableList = mutableListOf() var items: MutableList? = null var onTabSelectedListener: ((WritableMap) -> Unit)? = null @@ -66,14 +79,8 @@ class ReactBottomNavigationView(context: Context) : BottomNavigationView(context menu.clear() items.forEachIndexed {index, item -> val menuItem = menu.add(0, index, 0, item.title) - val iconResourceId = resources.getIdentifier( - item.icon, "drawable", context.packageName - ) - if (iconResourceId != 0) { - menuItem.icon = AppCompatResources.getDrawable(context, iconResourceId) - } else { - menuItem.setIcon(android.R.drawable.btn_star) // fallback icon - } + val drawable = this.getDrawable(icons[index]) + menuItem.setIcon(drawable) if (item.badge.isNotEmpty()) { val badge = this.getOrCreateBadge(index) badge.isVisible = true @@ -84,6 +91,48 @@ class ReactBottomNavigationView(context: Context) : BottomNavigationView(context } } + fun setIcons(icons: ReadableArray?) { + if (icons == null || icons.size() == 0) { + return + } + val tmpSources = mutableListOf() + + for (idx in 0 until icons.size()) { + val source = icons.getMap(idx) + var imageSource = + ImageSource( + context, + source.getString("uri"), + source.getDouble("width"), + source.getDouble("height")) + if (Uri.EMPTY == imageSource.uri) { + imageSource = getTransparentBitmapImageSource(context) + } + tmpSources.add(imageSource) + + } + + if (this.icons == tmpSources) { + return + } + + this.icons.clear() + this.icons.addAll(tmpSources) + } + + @SuppressLint("UseCompatLoadingForDrawables") + private fun getDrawable(imageSource: ImageSource): Drawable { + val imageRequest = ImageRequestBuilder.newBuilderWithSource(imageSource.uri).build() + val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context) + val result = DataSources.waitForFinalResult(dataSource) as CloseableReference + val bitmap = result.get().underlyingBitmap + + CloseableReference.closeSafely(result) + dataSource.close() + + return BitmapDrawable(resources, bitmap) + } + // Fixes issues with BottomNavigationView children layouting. private fun measureAndLayout() { measure( diff --git a/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt b/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt index ffa98af..bb451df 100644 --- a/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt +++ b/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt @@ -18,7 +18,6 @@ import com.facebook.yoga.YogaNode data class TabInfo( val key: String, - val icon: String, val title: String, val badge: String ) @@ -40,7 +39,6 @@ class RCTTabViewViewManager : itemsArray.add( TabInfo( key = item.getString("key") ?: "", - icon = item.getString("icon") ?: "", title = item.getString("title") ?: "", badge = item.getString("badge") ?: "" ) @@ -57,6 +55,11 @@ class RCTTabViewViewManager : } } + @ReactProp(name = "icons") + fun setIcons(view: ReactBottomNavigationView, icons: ReadableArray?) { + view.setIcons(icons) + } + public override fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { eventDispatcher = context.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher val view = ReactBottomNavigationView(context) diff --git a/example/src/Examples/MaterialBottomTabs.tsx b/example/src/Examples/MaterialBottomTabs.tsx index 986ffd1..1313506 100644 --- a/example/src/Examples/MaterialBottomTabs.tsx +++ b/example/src/Examples/MaterialBottomTabs.tsx @@ -30,9 +30,7 @@ function MaterialBottomTabs() { component={Albums} options={{ tabBarIcon: () => ( - + ), }} /> @@ -42,7 +40,7 @@ function MaterialBottomTabs() { options={{ tabBarIcon: () => ( ), }} @@ -52,9 +50,7 @@ function MaterialBottomTabs() { component={Chat} options={{ tabBarIcon: () => ( - + ), }} />