Skip to content

Commit

Permalink
feat(android): add fabric support on Android (#608)
Browse files Browse the repository at this point in the history
* feat: android wip

* fix: add pager to build.gradle

* fix: add codeGen to srcDirs

* fix: codegen names

* feat: add fabric implementation

* fix: remove unused file

* fix: commands on old arch
  • Loading branch information
okwasniewski authored Sep 22, 2022
1 parent b9f0351 commit 58e50f0
Show file tree
Hide file tree
Showing 18 changed files with 891 additions and 234 deletions.
28 changes: 20 additions & 8 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
buildscript {
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['PagerView_kotlinVersion']

repositories {
google()
mavenCentral()
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:4.2.1'
// noinspection DifferentKotlinGradleVersion
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

Expand All @@ -14,6 +19,8 @@ def isNewArchitectureEnabled() {
}

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'


if (isNewArchitectureEnabled()) {
apply plugin: 'com.facebook.react'
Expand Down Expand Up @@ -52,7 +59,10 @@ android {
sourceSets {
main {
if (isNewArchitectureEnabled()) {
java.srcDirs += ['src/turbo']
java.srcDirs += [
"src/turbo",
"${project.buildDir}/generated/source/codegen/java"
]
} else {
java.srcDirs += ['src/legacy']
}
Expand Down Expand Up @@ -130,17 +140,19 @@ repositories {
}
}

def kotlin_version = getExtOrDefault('kotlinVersion')

dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
// From node_modules
api "com.facebook.react:react-native:+"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.viewpager2:viewpager2:1.0.0'
}

if (isNewArchitectureEnabled()) {
react {
jsRootDir = file("../src/")
libraryName = "PagerViewView"
jsRootDir = file("../src")
libraryName = "RNCViewPager"
codegenJavaPackageName = "com.reactnativepagerview"
}
}

This file was deleted.

173 changes: 173 additions & 0 deletions android/src/legacy/com/reactnativepagerview/PagerViewViewManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package com.reactnativepagerview

import android.view.View
import android.view.ViewGroup
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.facebook.infer.annotation.Assertions
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.common.MapBuilder
import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerModule
import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.uimanager.events.EventDispatcher
import com.reactnativepagerview.event.PageScrollEvent
import com.reactnativepagerview.event.PageScrollStateChangedEvent
import com.reactnativepagerview.event.PageSelectedEvent


class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>() {
private lateinit var eventDispatcher: EventDispatcher

override fun getName(): String {
return PagerViewViewManagerImpl.NAME
}

override fun createViewInstance(reactContext: ThemedReactContext): NestedScrollableHost {
val host = NestedScrollableHost(reactContext)
host.id = View.generateViewId()
host.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
host.isSaveEnabled = false
val vp = ViewPager2(reactContext)
vp.adapter = ViewPagerAdapter()
//https://github.com/callstack/react-native-viewpager/issues/183
vp.isSaveEnabled = false
eventDispatcher = reactContext.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher

vp.post {
vp.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
eventDispatcher.dispatchEvent(
PageScrollEvent(host.id, position, positionOffset))
}

override fun onPageSelected(position: Int) {
super.onPageSelected(position)
eventDispatcher.dispatchEvent(
PageSelectedEvent(host.id, position))
}

override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
val pageScrollState: String = when (state) {
ViewPager2.SCROLL_STATE_IDLE -> "idle"
ViewPager2.SCROLL_STATE_DRAGGING -> "dragging"
ViewPager2.SCROLL_STATE_SETTLING -> "settling"
else -> throw IllegalStateException("Unsupported pageScrollState")
}
eventDispatcher.dispatchEvent(
PageScrollStateChangedEvent(host.id, pageScrollState))
}
})

eventDispatcher.dispatchEvent(PageSelectedEvent(host.id, vp.currentItem))
}
host.addView(vp)
return host
}

override fun addView(host: NestedScrollableHost, child: View?, index: Int) {
PagerViewViewManagerImpl.addView(host, child, index)
}

override fun getChildCount(parent: NestedScrollableHost) = PagerViewViewManagerImpl.getChildCount(parent)

override fun getChildAt(parent: NestedScrollableHost, index: Int): View {
return PagerViewViewManagerImpl.getChildAt(parent, index)
}

override fun removeView(parent: NestedScrollableHost, view: View) {
PagerViewViewManagerImpl.removeView(parent, view)
}

override fun removeAllViews(parent: NestedScrollableHost) {
PagerViewViewManagerImpl.removeAllViews(parent)
}

override fun removeViewAt(parent: NestedScrollableHost, index: Int) {
PagerViewViewManagerImpl.removeViewAt(parent, index)
}

override fun needsCustomLayoutForChildren(): Boolean {
return PagerViewViewManagerImpl.needsCustomLayoutForChildren()
}

@ReactProp(name = "scrollEnabled", defaultBoolean = true)
fun setScrollEnabled(host: NestedScrollableHost, value: Boolean) {
PagerViewViewManagerImpl.setScrollEnabled(host, value)
}

@ReactProp(name = "initialPage", defaultInt = 0)
fun setInitialPage(host: NestedScrollableHost, value: Int) {
PagerViewViewManagerImpl.setInitialPage(host, value)
}

@ReactProp(name = "orientation")
fun setOrientation(host: NestedScrollableHost, value: String) {
PagerViewViewManagerImpl.setOrientation(host, value)
}

@ReactProp(name = "offscreenPageLimit", defaultInt = ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT)
operator fun set(host: NestedScrollableHost, value: Int) {
PagerViewViewManagerImpl.setOffscreenPageLimit(host, value)
}

@ReactProp(name = "overScrollMode")
fun setOverScrollMode(host: NestedScrollableHost, value: String) {
PagerViewViewManagerImpl.setOverScrollMode(host, value)
}

@ReactProp(name = "layoutDirection")
fun setLayoutDirection(host: NestedScrollableHost, value: String) {
PagerViewViewManagerImpl.setLayoutDirection(host, value)
}

override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Map<String, String>> {
return MapBuilder.of(
PageScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScroll"),
PageScrollStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScrollStateChanged"),
PageSelectedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageSelected"))
}

override fun receiveCommand(root: NestedScrollableHost, commandId: String?, args: ReadableArray?) {
super.receiveCommand(root, commandId, args)
val view = PagerViewViewManagerImpl.getViewPager(root)
Assertions.assertNotNull(view)
Assertions.assertNotNull(args)
val childCount = view.adapter?.itemCount

when (commandId) {
COMMAND_SET_PAGE, COMMAND_SET_PAGE_WITHOUT_ANIMATION -> {
val pageIndex = args!!.getInt(0)
val canScroll = childCount != null && childCount > 0 && pageIndex >= 0 && pageIndex < childCount
if (canScroll) {
val scrollWithAnimation = commandId == COMMAND_SET_PAGE
PagerViewViewManagerImpl.setCurrentItem(view, pageIndex, scrollWithAnimation)
eventDispatcher.dispatchEvent(PageSelectedEvent(root.id, pageIndex))
}
}
COMMAND_SET_SCROLL_ENABLED -> {
view.isUserInputEnabled = args!!.getBoolean(0)
}
else -> throw IllegalArgumentException(String.format(
"Unsupported command %d received by %s.",
commandId,
javaClass.simpleName))
}
}

@ReactProp(name = "pageMargin", defaultInt = 0)
fun setPageMargin(host: NestedScrollableHost, margin: Int) {
PagerViewViewManagerImpl.setPageMargin(host, margin)
}

companion object {
private const val COMMAND_SET_PAGE = "setPage"
private const val COMMAND_SET_PAGE_WITHOUT_ANIMATION = "setPageWithoutAnimation"
private const val COMMAND_SET_SCROLL_ENABLED = "setScrollEnabledImperatively"
}
}

21 changes: 21 additions & 0 deletions android/src/main/java/com/reactnativepagerview/Helper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.reactnativepagerview

import android.content.Context
import android.content.ContextWrapper
import android.view.View
import com.facebook.react.bridge.ReactContext


class Helper {
companion object {
// https://github.com/facebook/react-native/blob/v0.64.2/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java#L138
fun getReactContext(view: View): ReactContext? {
var context: Context = view.getContext()
if (context !is ReactContext && context is ContextWrapper) {
context = context.baseContext
}
return if (context is ReactContext) context else null;
}
}

}
Loading

0 comments on commit 58e50f0

Please sign in to comment.