diff --git a/.gitignore b/.gitignore
index a8a773e..6f1b287 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,9 @@ AwesomeProject.xcodeproj
AwesomeProjectTests
index.ios.js
iOS
+*.iml
+**/.DS_Store
+.gradle
+.idea
+build
+*.tgz
diff --git a/README.md b/README.md
index cb78c31..27bcb4e 100644
--- a/README.md
+++ b/README.md
@@ -8,14 +8,65 @@ You can install this component through ``npm``:
npm i react-native-keyboard-aware-scroll-view --save
```
+### To add it to your Android project:
+- Add to android/settings.gradle
+
+```groovy
+include ':ReactNativeKeyboardAwareScrollView'
+project(':ReactNativeKeyboardAwareScrollView').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keyboard-aware-scroll-view')
+```
+- Add to android/app/build.gradle
+
+```groovy
+compile project(':ReactNativeKeyboardAwareScrollView')
+```
+
+- Add to android/app/src/main/AndroidManifest.xml
+
+```xml
+
+
+ ...
+
+ ...
+
+```
+
+- Register module in MainActivity.java
+
+```java
+import com.jblack.keyboardaware.views.scrollview.AndroidKeyboardAwareScrollViewPackage; // <--- import
+
+public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
+ ......
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ ...
+
+ mReactInstanceManager = ReactInstanceManager.builder()
+ ...
+ .addPackage(new AndroidKeyboardAwareScrollViewPackage()) // <--- add here
+ ...
+ .build();
+
+ ...
+ }
+
+ ......
+}
+```
+
## Usage
You can use the ``KeyboardAwareScrollView`` or the ``KeyboardAwareListView``
components. Both accept ``ScrollView`` and ``ListView`` default props and
implements a custom ``KeyboardAwareMixin`` to handle keyboard appearance.
The mixin is also available if you want to use it in any other component.
-Import ``react-native-keyboard-aware-scroll-view`` and wrap your content inside
-it:
+Note: The KeyboardAwareListView is not currently supported in Android.
+
+Import ``react-native-keyboard-aware-scroll-view`` and wrap your content inside it:
```js
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..dcef810
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,38 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:1.5.0"
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+apply plugin: "com.android.library"
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.2"
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0.0"
+ }
+
+ lintOptions {
+ disable "GradleDynamicVersion", "InvalidPackage"
+ }
+}
+
+dependencies {
+ compile "com.facebook.react:react-native:0.19.+"
+}
+
+task wrapper(type: Wrapper) {
+ gradleVersion = "2.2.1"
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..c97a8bd
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..a083698
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Feb 07 13:49:59 EST 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lib/KeyboardAwareMixin.js b/lib/KeyboardAwareMixin.js
index 2a7e7de..c7e410d 100644
--- a/lib/KeyboardAwareMixin.js
+++ b/lib/KeyboardAwareMixin.js
@@ -1,4 +1,4 @@
-import { DeviceEventEmitter } from 'react-native'
+import { DeviceEventEmitter, NativeAppEventEmitter, Platform } from 'react-native'
import TimerMixin from 'react-timer-mixin'
const _KAM_DEFAULT_TAB_BAR_HEIGHT = 49
@@ -19,8 +19,8 @@ const KeyboardAwareMixin = {
},
// Keyboard actions
- updateKeyboardSpace: function (frames) {
- const keyboardSpace = (this.props.viewIsInsideTabBar) ? frames.endCoordinates.height - _KAM_DEFAULT_TAB_BAR_HEIGHT : frames.endCoordinates.height
+ updateKeyboardSpace: function (height) {
+ const keyboardSpace = (this.props.viewIsInsideTabBar) ? height - _KAM_DEFAULT_TAB_BAR_HEIGHT : height
this.setState({
keyboardSpace: keyboardSpace,
})
@@ -34,14 +34,24 @@ const KeyboardAwareMixin = {
componentDidMount: function () {
// Keyboard events
- DeviceEventEmitter.addListener('keyboardWillShow', this.updateKeyboardSpace)
- DeviceEventEmitter.addListener('keyboardWillHide', this.resetKeyboardSpace)
+ if (Platform.OS === 'ios') {
+ DeviceEventEmitter.addListener('keyboardWillShow', (frames) => this.updateKeyboardSpace(frames.endCoordinates.height))
+ DeviceEventEmitter.addListener('keyboardWillHide', this.resetKeyboardSpace)
+ } else {
+ this.androidKeyboardVisibleListener = NativeAppEventEmitter.addListener('androidKeyboardVisible', this.updateKeyboardSpace)
+ this.androidKeyboardHiddenListener = NativeAppEventEmitter.addListener('androidKeyboardHidden', this.resetKeyboardSpace)
+ }
},
componentWillUnmount: function () {
- // TODO: figure out if removeAllListeners is the right thing to do
- DeviceEventEmitter.removeAllListeners('keyboardWillShow')
- DeviceEventEmitter.removeAllListeners('keyboardWillHide')
+ if (Platform.OS === 'ios') {
+ // TODO: figure out if removeAllListeners is the right thing to do
+ DeviceEventEmitter.removeAllListeners('keyboardWillShow')
+ DeviceEventEmitter.removeAllListeners('keyboardWillHide')
+ } else {
+ this.androidKeyboardVisibleListener.remove();
+ this.androidKeyboardHiddenListener.remove();
+ }
},
/**
diff --git a/lib/KeyboardAwareScrollView.js b/lib/KeyboardAwareScrollView.js
index 443515f..f7b11d8 100644
--- a/lib/KeyboardAwareScrollView.js
+++ b/lib/KeyboardAwareScrollView.js
@@ -1,4 +1,9 @@
-import React, { ScrollView } from 'react-native'
+import React, {
+ Platform,
+ requireNativeComponent,
+ ScrollView,
+ View
+} from 'react-native'
import KeyboardAwareMixin from './KeyboardAwareMixin'
const KeyboardAwareScrollView = React.createClass({
@@ -6,6 +11,7 @@ const KeyboardAwareScrollView = React.createClass({
...ScrollView.propTypes,
viewIsInsideTabBar: React.PropTypes.bool,
},
+
mixins: [KeyboardAwareMixin],
componentWillMount: function() {
@@ -14,18 +20,35 @@ const KeyboardAwareScrollView = React.createClass({
}
},
- render: function () {
- return (
-
- {this.props.children}
-
- )
+ render: function() {
+ if (Platform.OS === 'ios') {
+ return (
+
+ {this.props.children}
+
+ )
+ } else {
+ return (
+
+
+ {this.props.children}
+
+
+ )
+ }
},
})
+var AndroidKeyboardAwareScrollView = requireNativeComponent('AndroidKeyboardAwareScrollView', KeyboardAwareScrollView)
+
export default KeyboardAwareScrollView
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..61623d6
--- /dev/null
+++ b/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
\ No newline at end of file
diff --git a/src/main/java/com/jblack/keyboardaware/events/AndroidKeyboardHiddenEvent.java b/src/main/java/com/jblack/keyboardaware/events/AndroidKeyboardHiddenEvent.java
new file mode 100644
index 0000000..1332e71
--- /dev/null
+++ b/src/main/java/com/jblack/keyboardaware/events/AndroidKeyboardHiddenEvent.java
@@ -0,0 +1,27 @@
+package com.jblack.keyboardaware.events;
+
+
+import android.util.Log;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+
+public class AndroidKeyboardHiddenEvent extends Event {
+
+ private static final String EVENT_NAME = "androidKeyboardHidden";
+
+ public AndroidKeyboardHiddenEvent(int viewTag, long timestampMs) {
+ super(viewTag, timestampMs);
+ Log.v("AKAScrollView", String.format("AndroidKeyboardHiddenEvent created with viewTag [%d], timestamp [%d]", viewTag, timestampMs));
+ }
+
+ @Override
+ public String getEventName() {
+ return EVENT_NAME;
+ }
+
+ @Override
+ public void dispatch(RCTEventEmitter rctEventEmitter) {
+ rctEventEmitter.receiveEvent(getViewTag(), getEventName(), null);
+ }
+}
diff --git a/src/main/java/com/jblack/keyboardaware/events/AndroidKeyboardVisibleEvent.java b/src/main/java/com/jblack/keyboardaware/events/AndroidKeyboardVisibleEvent.java
new file mode 100644
index 0000000..adec3ab
--- /dev/null
+++ b/src/main/java/com/jblack/keyboardaware/events/AndroidKeyboardVisibleEvent.java
@@ -0,0 +1,34 @@
+package com.jblack.keyboardaware.events;
+
+
+import android.util.Log;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+
+public class AndroidKeyboardVisibleEvent extends Event {
+
+ private static final String EVENT_NAME = "androidKeyboardVisible";
+ private final int height;
+
+ public AndroidKeyboardVisibleEvent(int viewTag, long timestampMs, int height) {
+ super(viewTag, timestampMs);
+ this.height = height;
+ Log.v("AKAScrollView", String.format("AndroidKeyboardVisibleEvent created with viewTag [%d], timestamp [%d], height [%d]",
+ viewTag, timestampMs, height));
+ }
+
+ @Override
+ public String getEventName() {
+ return EVENT_NAME;
+ }
+
+ @Override
+ public void dispatch(RCTEventEmitter rctEventEmitter) {
+ WritableMap map = Arguments.createMap();
+ map.putInt("height", height);
+ rctEventEmitter.receiveEvent(getViewTag(), getEventName(), map);
+ }
+}
diff --git a/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollView.java b/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollView.java
new file mode 100644
index 0000000..b1a920f
--- /dev/null
+++ b/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollView.java
@@ -0,0 +1,53 @@
+package com.jblack.keyboardaware.views.scrollview;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.events.EventDispatcher;
+import com.facebook.react.views.scroll.ReactScrollView;
+import com.jblack.keyboardaware.events.AndroidKeyboardHiddenEvent;
+import com.jblack.keyboardaware.events.AndroidKeyboardVisibleEvent;
+
+
+public class AndroidKeyboardAwareScrollView extends ReactScrollView {
+
+ public AndroidKeyboardAwareScrollView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int proposedWidth = MeasureSpec.getSize(widthMeasureSpec);
+ final int proposedHeight = MeasureSpec.getSize(heightMeasureSpec);
+ final int currentWidth = getWidth();
+ final int currentHeight = getHeight();
+
+ Log.v("AKAScrollView", String.format("onMeasure - currentHeight [%d] proposedHeight [%d] currentWidth [%d] proposedWidth [%d]",
+ currentHeight, proposedHeight, currentWidth, proposedWidth));
+
+ // Check if the view height is changing, it isn't the initial onMeasure call, and we aren't changing device orientation
+ if ((currentHeight != proposedHeight) && (currentHeight != 0) && (currentWidth == proposedWidth)) {
+ // Check if it is a change greater than 25% of the current height, to allow for things like extra
+ // keyboard rows being shown/hidden
+ final double percentDifferenceThreshold = 0.25;
+ final double difference = Math.abs(currentHeight - proposedHeight);
+
+ if (difference / currentHeight > percentDifferenceThreshold) {
+ final EventDispatcher eventDispatcher = ((ThemedReactContext) getContext())
+ .getNativeModule(UIManagerModule.class)
+ .getEventDispatcher();
+
+ if (currentHeight > proposedHeight) {
+ eventDispatcher.dispatchEvent(new AndroidKeyboardVisibleEvent(getId(), SystemClock.uptimeMillis(), proposedHeight));
+ } else if (currentHeight < proposedHeight) {
+ eventDispatcher.dispatchEvent(new AndroidKeyboardHiddenEvent(getId(), SystemClock.uptimeMillis()));
+ }
+ }
+ }
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+}
diff --git a/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollViewManager.java b/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollViewManager.java
new file mode 100644
index 0000000..53c24a5
--- /dev/null
+++ b/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollViewManager.java
@@ -0,0 +1,20 @@
+package com.jblack.keyboardaware.views.scrollview;
+
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.views.scroll.ReactScrollViewManager;
+
+
+public class AndroidKeyboardAwareScrollViewManager extends ReactScrollViewManager {
+
+ private static final String REACT_CLASS = "AndroidKeyboardAwareScrollView";
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ @Override
+ public AndroidKeyboardAwareScrollView createViewInstance(ThemedReactContext reactContext) {
+ return new AndroidKeyboardAwareScrollView(reactContext);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollViewPackage.java b/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollViewPackage.java
new file mode 100644
index 0000000..0efa72a
--- /dev/null
+++ b/src/main/java/com/jblack/keyboardaware/views/scrollview/AndroidKeyboardAwareScrollViewPackage.java
@@ -0,0 +1,30 @@
+package com.jblack.keyboardaware.views.scrollview;
+
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class AndroidKeyboardAwareScrollViewPackage implements ReactPackage {
+
+ @Override
+ public List createNativeModules(ReactApplicationContext reactApplicationContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactApplicationContext) {
+ return Arrays.asList(new AndroidKeyboardAwareScrollViewManager());
+ }
+}