Skip to content

Commit 9a41a18

Browse files
committed
Add support both vertical, horizontal layout. Shadow invisible by default
1 parent 32c9cc6 commit 9a41a18

File tree

3 files changed

+54
-19
lines changed

3 files changed

+54
-19
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
- A simple search box with animation, inspired from ios search bar.
33
- No library dependencies, lightweight, fast, flexible, customizable.
44
- Support both iOS/Android devices
5+
- Support vertical, horizontal layout
6+
- Shadow invisible by default
57

68
## Install
79
```
@@ -196,12 +198,11 @@ class MyScene extends Component {
196198

197199
## Prop Defaults
198200
```
199-
contentWidth: Dimensions.get('window').width,
200-
middleWidth: Dimensions.get('window').width / 2,
201201
searchIconCollapsedMargin: 25,
202202
searchIconExpandedMargin: 10,
203203
placeholderCollapsedMargin: 15,
204204
placeholderExpandedMargin: 20,
205+
shadowVisible: false
205206
```
206207

207208
## LICENSE

index.js

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,30 @@ import {
1010
View
1111
} from 'react-native';
1212

13-
const { width } = Dimensions.get('window');
1413
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
1514
const containerHeight = 40;
1615
const middleHeight = 20;
1716

1817
class Search extends Component {
1918
constructor(props) {
2019
super(props);
21-
this.state = { keyword: '' };
20+
21+
this.state = {
22+
keyword: '',
23+
expanded: false
24+
};
25+
const { width } = Dimensions.get('window');
26+
this.contentWidth = width;
27+
this.middleWidth = width / 2;
2228

2329
/**
2430
* Animated values
2531
*/
26-
this.iconSearchAnimated = new Animated.Value(this.props.middleWidth - this.props.searchIconCollapsedMargin);
32+
this.iconSearchAnimated = new Animated.Value(this.middleWidth - this.props.searchIconCollapsedMargin);
2733
this.iconDeleteAnimated = new Animated.Value(0);
28-
this.inputFocusWidthAnimated = new Animated.Value(this.props.contentWidth - 10);
29-
this.inputFocusPlaceholderAnimated = new Animated.Value(this.props.middleWidth - this.props.placeholderCollapsedMargin);
30-
this.btnCancelAnimated = new Animated.Value(this.props.contentWidth);
34+
this.inputFocusWidthAnimated = new Animated.Value(this.contentWidth - 10);
35+
this.inputFocusPlaceholderAnimated = new Animated.Value(this.middleWidth - this.props.placeholderCollapsedMargin);
36+
this.btnCancelAnimated = new Animated.Value(this.contentWidth);
3137

3238
/**
3339
* functions
@@ -40,6 +46,7 @@ class Search extends Component {
4046
this.focus = this.focus.bind(this);
4147
this.expandAnimation = this.expandAnimation.bind(this);
4248
this.collapseAnimation = this.collapseAnimation.bind(this);
49+
this.onLayout = this.onLayout.bind(this);
4350

4451
/**
4552
* local variables
@@ -54,6 +61,17 @@ class Search extends Component {
5461
this.shadowHeight = this.props.shadowOffsetHeightCollapsed;
5562
}
5663

64+
onLayout = (event) => {
65+
const contentWidth = event.nativeEvent.layout.width;
66+
this.contentWidth = contentWidth;
67+
this.middleWidth = contentWidth / 2;
68+
if (this.state.expanded) {
69+
this.expandAnimation();
70+
} else {
71+
this.collapseAnimation();
72+
}
73+
}
74+
5775
/**
5876
* onSearch
5977
* async await
@@ -90,6 +108,9 @@ class Search extends Component {
90108
onFocus = async () => {
91109
this.props.beforeFocus && await this.props.beforeFocus();
92110
this.refs.input_keyword._component.isFocused && await this.refs.input_keyword._component.focus();
111+
await this.setState(prevState => {
112+
return { expanded: !prevState.expanded };
113+
});
93114
await this.expandAnimation();
94115
this.props.onFocus && await this.props.onFocus(this.state.keyword);
95116
this.props.afterFocus && await this.props.afterFocus();
@@ -131,6 +152,9 @@ class Search extends Component {
131152
onCancel = async () => {
132153
this.props.beforeCancel && await this.props.beforeCancel();
133154
await this.setState({ keyword: '' });
155+
await this.setState(prevState => {
156+
return { expanded: !prevState.expanded };
157+
});
134158
await this.collapseAnimation();
135159
this.props.onCancel && await this.props.onCancel();
136160
this.props.afterCancel && await this.props.afterCancel();
@@ -142,7 +166,7 @@ class Search extends Component {
142166
Animated.timing(
143167
this.inputFocusWidthAnimated,
144168
{
145-
toValue: this.props.contentWidth - 70,
169+
toValue: this.contentWidth - 70,
146170
duration: 200
147171
}
148172
).start(),
@@ -194,28 +218,28 @@ class Search extends Component {
194218
Animated.timing(
195219
this.inputFocusWidthAnimated,
196220
{
197-
toValue: this.props.contentWidth - 10,
221+
toValue: this.contentWidth - 10,
198222
duration: 200
199223
}
200224
).start(),
201225
Animated.timing(
202226
this.btnCancelAnimated,
203227
{
204-
toValue: this.props.contentWidth,
228+
toValue: this.contentWidth,
205229
duration: 200
206230
}
207231
).start(),
208232
Animated.timing(
209233
this.inputFocusPlaceholderAnimated,
210234
{
211-
toValue: this.props.middleWidth - this.props.placeholderCollapsedMargin,
235+
toValue: this.middleWidth - this.props.placeholderCollapsedMargin,
212236
duration: 200
213237
}
214238
).start(),
215239
Animated.timing(
216240
this.iconSearchAnimated,
217241
{
218-
toValue: this.props.middleWidth - this.props.searchIconCollapsedMargin,
242+
toValue: this.middleWidth - this.props.searchIconCollapsedMargin,
219243
duration: 200
220244
}
221245
).start(),
@@ -248,25 +272,28 @@ class Search extends Component {
248272
styles.container,
249273
this.props.backgroundColor && { backgroundColor: this.props.backgroundColor }
250274
]}
275+
onLayout={this.onLayout}
251276
>
252277
<AnimatedTextInput
253278
ref="input_keyword"
254279
style={[
255280
styles.input,
256281
this.props.placeholderTextColor && { color: this.props.placeholderTextColor },
282+
this.props.inputStyle && this.props.inputStyle,
257283
this.props.inputHeight && { height: this.props.inputHeight },
258284
this.props.inputBorderRadius && { borderRadius: this.props.inputBorderRadius },
259285
{
260286
width: this.inputFocusWidthAnimated,
261287
paddingLeft: this.inputFocusPlaceholderAnimated
262288
},
263-
{
289+
this.props.shadowVisible && {
264290
shadowOffset: { width: this.props.shadowOffsetWidth, height: this.shadowHeight },
265291
shadowColor: this.props.shadowColor,
266292
shadowOpacity: this.shadowOpacityAnimated,
267293
shadowRadius: this.props.shadowRadius,
268294
}
269295
]}
296+
editable={this.props.editable}
270297
value={this.state.keyword}
271298
onChangeText={this.onChangeText}
272299
placeholder={this.placeholder}
@@ -277,7 +304,7 @@ class Search extends Component {
277304
returnKeyType={this.props.returnKeyType || 'search'}
278305
keyboardType={this.props.keyboardType || 'default'}
279306
onFocus={this.onFocus}
280-
underlineColorAndroid="transparent"
307+
underlineColorAndroid='transparent'
281308
/>
282309
<TouchableWithoutFeedback onPress={this.onFocus}>
283310
<Animated.Image
@@ -333,7 +360,7 @@ const styles = {
333360
paddingTop: 5,
334361
paddingBottom: 5,
335362
paddingRight: 20,
336-
borderColor: '#000',
363+
borderColor: '#444',
337364
backgroundColor: '#f7f7f7',
338365
borderRadius: 5,
339366
fontSize: 13,
@@ -419,6 +446,11 @@ Search.propTypes = {
419446
titleCancelColor: PropTypes.string,
420447
tintColorSearch: PropTypes.string,
421448
tintColorDelete: PropTypes.string,
449+
inputStyle: PropTypes.oneOfType([
450+
PropTypes.number,
451+
PropTypes.object
452+
]),
453+
onLayout: PropTypes.func,
422454

423455
/**
424456
* text input
@@ -431,6 +463,7 @@ Search.propTypes = {
431463
inputBorderRadius: PropTypes.number,
432464
contentWidth: PropTypes.number,
433465
middleWidth: PropTypes.number,
466+
editable: PropTypes.bool,
434467

435468
/**
436469
* Positioning
@@ -451,11 +484,11 @@ Search.propTypes = {
451484
shadowOpacityCollapsed: PropTypes.number,
452485
shadowOpacityExpanded: PropTypes.number,
453486
shadowRadius: PropTypes.number,
487+
shadowVisible: PropTypes.bool,
454488
};
455489

456490
Search.defaultProps = {
457-
contentWidth: width,
458-
middleWidth: width / 2,
491+
editable: true,
459492
searchIconCollapsedMargin: 25,
460493
searchIconExpandedMargin: 10,
461494
placeholderCollapsedMargin: 15,
@@ -467,6 +500,7 @@ Search.defaultProps = {
467500
shadowOpacityCollapsed: 0.12,
468501
shadowOpacityExpanded: 0.24,
469502
shadowRadius: 4,
503+
shadowVisible: false,
470504
};
471505

472506
export default Search;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-search-box",
3-
"version": "0.0.6",
3+
"version": "0.0.7",
44
"description": "A simple search box with animation, inspired from ios search bar. No library dependencies, lightweight, fast, flexible, customizable. Support both iOS/Android devices",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)