diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..94fc867
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
+# OSX
+#
+.DS_Store
+
+# Xcode
+#
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+project.xcworkspace
+
+# Android/IJ
+#
+.idea
+.gradle
+local.properties
+
+# node.js
+#
+node_modules/
+npm-debug.log
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..94fc867
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,34 @@
+# OSX
+#
+.DS_Store
+
+# Xcode
+#
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+project.xcworkspace
+
+# Android/IJ
+#
+.idea
+.gradle
+local.properties
+
+# node.js
+#
+node_modules/
+npm-debug.log
diff --git a/README.md b/README.md
index 1740ede..ac4cdc5 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,13 @@
# react-native-inputscrollview
-输入框位置随键盘自动调整的scrollview
+防止键盘弹出时候,输入框被遮挡
+
+## 如何安装
+
+```bash
+npm install react-native-inputscrollview --save
+rnpm link react-native-inputscrollview
+
+```
+
+## 如何使用
+用InputScrollView替换InputView外层的ScrollView组件
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..d300fcc
--- /dev/null
+++ b/index.js
@@ -0,0 +1,141 @@
+/**
+ * Created by lvbingru on 12/16/15.
+ */
+
+import React, {Component, PropTypes, } from 'react';
+import ReactNative, {InteractionManager, View, Text, ScrollView, Platform, Animated, UIManager, NativeModules, Dimensions} from 'react-native';
+import TextInputState from 'react-native/Libraries/Components/TextInput/TextInputState';
+import dismissKeyboard from 'react-native/Libraries/Utilities/dismissKeyboard';
+import packageData from 'react-native/package.json';
+import semver from 'semver';
+const ViewPlugins = NativeModules.InputScrollViewPlugin;
+
+const propTypes = {
+ distance : PropTypes.number,
+ tapToDismiss : PropTypes.bool,
+ onKeyboardWillShow : PropTypes.func,
+}
+
+const defaultProps = {
+ distance : 160,
+ tapToDismiss : true,
+}
+
+export default class InputScrollView extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ keyboardHeightAnim: new Animated.Value(0)
+ };
+
+ this.offsetY = 0;
+ this.moved = false;
+ }
+
+ render() {
+ const {distance, tapToDismiss, onKeyboardWillShow, keyboardShouldPersistTaps, children, ...others} = this.props
+ return (
+ {
+ if (tapToDismiss === true) {
+ const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
+ if (e.target != currentlyFocusedTextInput) {
+ if (ViewPlugins && ViewPlugins.isTextInput) {
+ ViewPlugins.isTextInput(
+ e.target,
+ r => {
+ if (r===false) {
+ dismissKeyboard();
+ }
+ }
+ );
+ }
+ else {
+ dismissKeyboard();
+ }
+ }
+ }
+ return false;
+ }}
+ >
+ {
+ this.scrollViewRef = srcollView;
+ }}
+ onKeyboardWillShow = {e => {
+ if (!this.scrollViewRef) {
+ return;
+ }
+ const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
+ if (currentlyFocusedTextInput != null) {
+ ViewPlugins && ViewPlugins.isSubview(
+ currentlyFocusedTextInput,
+ this.scrollViewRef.getInnerViewNode(),
+ r => {
+ if(r===true) {this.move(currentlyFocusedTextInput, e)}
+ });
+ }
+ onKeyboardWillShow && onKeyboardWillShow(e);
+ }}
+ onKeyboardWillHide = {e=> {
+ if (!this.scrollViewRef) {
+ return;
+ }
+ if (this.moved) {
+ this.moved = false;
+ this.scrollToY(this.offsetY);
+ }
+ }}
+ onMomentumScrollEnd = {e=>{
+ if (!this.moved) {
+ this.offsetY = Math.max(0, e.nativeEvent.contentOffset.y)
+ }
+ }}
+ {...others}
+ >
+ {children}
+
+
+
+ );
+ }
+
+ move(currentlyFocusedTextInput, e) {
+ UIManager.measureLayout(
+ currentlyFocusedTextInput,
+ ReactNative.findNodeHandle(this.scrollViewRef.getInnerViewNode()),
+ e=>{console.warning(e)},
+ (left, top, width, height)=>{
+ let keyboardScreenY = Dimensions.get('window').height;
+ if (e) {
+ keyboardScreenY = e.endCoordinates.screenY;
+ }
+ let scrollOffsetY = top - keyboardScreenY + height + this.props.distance;
+ scrollOffsetY = Math.max(this.offsetY, scrollOffsetY);
+ this.scrollToY(scrollOffsetY);
+ }
+ );
+ this.moved = true;
+ }
+
+ getInnerScrollView() {
+ return this.scrollViewRef;
+ }
+
+ scrollToY(offsetY) {
+ if (semver.gte(packageData.version, '0.20.0')) {
+ this.scrollViewRef.scrollTo({x:0, y:offsetY});
+ }
+ else {
+ this.scrollViewRef.scrollTo(offsetY, 0);
+ }
+ }
+}
+
+InputScrollView.propTypes = propTypes;
+InputScrollView.defaultProps = defaultProps;
diff --git a/ios/InputScrollViewPlugin.xcodeproj/project.pbxproj b/ios/InputScrollViewPlugin.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..83260d6
--- /dev/null
+++ b/ios/InputScrollViewPlugin.xcodeproj/project.pbxproj
@@ -0,0 +1,261 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 9182DCCD1CBB66AC002206C2 /* InputScrollViewPlugin.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9182DCCC1CBB66AC002206C2 /* InputScrollViewPlugin.h */; };
+ 9182DCCF1CBB66AC002206C2 /* InputScrollViewPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 9182DCCE1CBB66AC002206C2 /* InputScrollViewPlugin.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9182DCC71CBB66AC002206C2 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "include/$(PRODUCT_NAME)";
+ dstSubfolderSpec = 16;
+ files = (
+ 9182DCCD1CBB66AC002206C2 /* InputScrollViewPlugin.h in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 9182DCC91CBB66AC002206C2 /* libInputScrollViewPlugin.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInputScrollViewPlugin.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 9182DCCC1CBB66AC002206C2 /* InputScrollViewPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InputScrollViewPlugin.h; sourceTree = ""; };
+ 9182DCCE1CBB66AC002206C2 /* InputScrollViewPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InputScrollViewPlugin.m; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 9182DCC61CBB66AC002206C2 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 9182DCC01CBB66AC002206C2 = {
+ isa = PBXGroup;
+ children = (
+ 9182DCCB1CBB66AC002206C2 /* InputScrollViewPlugin */,
+ 9182DCCA1CBB66AC002206C2 /* Products */,
+ );
+ sourceTree = "";
+ };
+ 9182DCCA1CBB66AC002206C2 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 9182DCC91CBB66AC002206C2 /* libInputScrollViewPlugin.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 9182DCCB1CBB66AC002206C2 /* InputScrollViewPlugin */ = {
+ isa = PBXGroup;
+ children = (
+ 9182DCCC1CBB66AC002206C2 /* InputScrollViewPlugin.h */,
+ 9182DCCE1CBB66AC002206C2 /* InputScrollViewPlugin.m */,
+ );
+ path = InputScrollViewPlugin;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 9182DCC81CBB66AC002206C2 /* InputScrollViewPlugin */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 9182DCD21CBB66AC002206C2 /* Build configuration list for PBXNativeTarget "InputScrollViewPlugin" */;
+ buildPhases = (
+ 9182DCC51CBB66AC002206C2 /* Sources */,
+ 9182DCC61CBB66AC002206C2 /* Frameworks */,
+ 9182DCC71CBB66AC002206C2 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = InputScrollViewPlugin;
+ productName = InputScrollViewPlugin;
+ productReference = 9182DCC91CBB66AC002206C2 /* libInputScrollViewPlugin.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 9182DCC11CBB66AC002206C2 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0720;
+ ORGANIZATIONNAME = erica;
+ TargetAttributes = {
+ 9182DCC81CBB66AC002206C2 = {
+ CreatedOnToolsVersion = 7.2;
+ };
+ };
+ };
+ buildConfigurationList = 9182DCC41CBB66AC002206C2 /* Build configuration list for PBXProject "InputScrollViewPlugin" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 9182DCC01CBB66AC002206C2;
+ productRefGroup = 9182DCCA1CBB66AC002206C2 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 9182DCC81CBB66AC002206C2 /* InputScrollViewPlugin */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 9182DCC51CBB66AC002206C2 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 9182DCCF1CBB66AC002206C2 /* InputScrollViewPlugin.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 9182DCD01CBB66AC002206C2 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.2;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 9182DCD11CBB66AC002206C2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.2;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 9182DCD31CBB66AC002206C2 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../../react-native/React/**",
+ "$(SRCROOT)/../../react-native/Libraries/**",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Debug;
+ };
+ 9182DCD41CBB66AC002206C2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../../react-native/React/**",
+ "$(SRCROOT)/../../react-native/Libraries/**",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 9182DCC41CBB66AC002206C2 /* Build configuration list for PBXProject "InputScrollViewPlugin" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 9182DCD01CBB66AC002206C2 /* Debug */,
+ 9182DCD11CBB66AC002206C2 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 9182DCD21CBB66AC002206C2 /* Build configuration list for PBXNativeTarget "InputScrollViewPlugin" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 9182DCD31CBB66AC002206C2 /* Debug */,
+ 9182DCD41CBB66AC002206C2 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 9182DCC11CBB66AC002206C2 /* Project object */;
+}
diff --git a/ios/InputScrollViewPlugin/InputScrollViewPlugin.h b/ios/InputScrollViewPlugin/InputScrollViewPlugin.h
new file mode 100644
index 0000000..11b2000
--- /dev/null
+++ b/ios/InputScrollViewPlugin/InputScrollViewPlugin.h
@@ -0,0 +1,13 @@
+//
+// InputScrollViewPlugin.h
+// InputScrollViewPlugin
+//
+// Created by LvBingru on 4/11/16.
+// Copyright © 2016 erica. All rights reserved.
+//
+
+#import "RCTBridgeModule.h"
+
+@interface InputScrollViewPlugin : NSObject
+
+@end
diff --git a/ios/InputScrollViewPlugin/InputScrollViewPlugin.m b/ios/InputScrollViewPlugin/InputScrollViewPlugin.m
new file mode 100644
index 0000000..a3727ca
--- /dev/null
+++ b/ios/InputScrollViewPlugin/InputScrollViewPlugin.m
@@ -0,0 +1,64 @@
+//
+// InputScrollViewPlugin.m
+// InputScrollViewPlugin
+//
+// Created by LvBingru on 4/11/16.
+// Copyright © 2016 erica. All rights reserved.
+//
+
+#import "InputScrollViewPlugin.h"
+#import "RCTShadowView.h"
+#import "RCTUIManager.h"
+#import "RCTTextField.h"
+#import "RCTTextView.h"
+
+@implementation InputScrollViewPlugin
+
+RCT_EXPORT_MODULE();
+
+@synthesize bridge = _bridge;
+
+RCT_EXPORT_METHOD(isSubview:(nonnull NSNumber *)reactTag
+ relativeTo:(nonnull NSNumber *)ancestorReactTag
+ callback:(RCTResponseSenderBlock)callback)
+{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ UIView *view = [_bridge.uiManager viewForReactTag:reactTag];
+ UIView *ancestorView = [_bridge.uiManager viewForReactTag:ancestorReactTag];
+
+ while (view) {
+ view = view.superview;
+ if (view == ancestorView) {
+ if (callback) {
+ callback(@[@(YES)]);
+ }
+ return;
+ }
+ }
+
+ if (callback) {
+ callback(@[@(NO)]);
+ }
+ });
+}
+
+RCT_EXPORT_METHOD(isTextInput:(nonnull NSNumber *)reactTag
+ callback:(RCTResponseSenderBlock)callback)
+{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ UIView *view = [_bridge.uiManager viewForReactTag:reactTag];
+ if ([view isKindOfClass:[RCTTextField class]] || [view isKindOfClass:[RCTTextView class]]) {
+ if (callback) {
+ callback(@[@(YES)]);
+ }
+ }
+ else {
+ if (callback) {
+ callback(@[@(NO)]);
+ }
+ }
+ });
+}
+
+
+@end
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..96f5c15
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "react-native-inputscrollview",
+ "version": "1.0.2",
+ "description": "输入框位置动态调整",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/reactnativecn/react-native-inputscrollview.git%22.git"
+ },
+ "keywords": [
+ "react-native",
+ "ios",
+ "android",
+ "键盘遮挡输入框"
+ ],
+ "author": "lvbingru",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/reactnativecn/react-native-inputscrollview.git%22/issues"
+ },
+ "homepage": "https://github.com/reactnativecn/react-native-inputscrollview.git%22#readme",
+ "dependencies": {
+ "semver": "^5.1.0"
+ }
+}