inputscrollview

This commit is contained in:
LvBingru 2016-07-16 11:00:41 +08:00
parent 3dfb5c53d4
commit 4e26a8c939
8 changed files with 587 additions and 1 deletions

34
.gitignore vendored Normal file
View File

@ -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

34
.npmignore Normal file
View File

@ -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

View File

@ -1,2 +1,13 @@
# react-native-inputscrollview
输入框位置随键盘自动调整的scrollview
防止键盘弹出时候,输入框被遮挡
## 如何安装
```bash
npm install react-native-inputscrollview --save
rnpm link react-native-inputscrollview
```
## 如何使用
用InputScrollView替换InputView外层的ScrollView组件

141
index.js Normal file
View File

@ -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 (
<View
style = {{flex:1}}
onStartShouldSetResponderCapture = {e=>{
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;
}}
>
<ScrollView
style = {{flex:1}}
contentContainerStyle = {[{alignItems : 'stretch',}]}
keyboardShouldPersistTaps = {tapToDismiss?true:keyboardShouldPersistTaps}
ref={(srcollView) => {
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}
</ScrollView>
</View>
);
}
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;

View File

@ -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 = "<group>"; };
9182DCCE1CBB66AC002206C2 /* InputScrollViewPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InputScrollViewPlugin.m; sourceTree = "<group>"; };
/* 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 = "<group>";
};
9182DCCA1CBB66AC002206C2 /* Products */ = {
isa = PBXGroup;
children = (
9182DCC91CBB66AC002206C2 /* libInputScrollViewPlugin.a */,
);
name = Products;
sourceTree = "<group>";
};
9182DCCB1CBB66AC002206C2 /* InputScrollViewPlugin */ = {
isa = PBXGroup;
children = (
9182DCCC1CBB66AC002206C2 /* InputScrollViewPlugin.h */,
9182DCCE1CBB66AC002206C2 /* InputScrollViewPlugin.m */,
);
path = InputScrollViewPlugin;
sourceTree = "<group>";
};
/* 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 */;
}

View File

@ -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<RCTBridgeModule>
@end

View File

@ -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

28
package.json Normal file
View File

@ -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"
}
}