Skip to content

Commit c750ff8

Browse files
committed
fix(SearchInputBar): SearchInputBar 聚焦问题(#284),SearchInputBar 安卓真机点击第二个搜索栏输入框报错(285)
1 parent 3828ece commit c750ff8

File tree

2 files changed

+71
-173
lines changed
  • example/examples/src/routes/SearchInputBar
  • packages/core/src/SearchInputBar

2 files changed

+71
-173
lines changed

example/examples/src/routes/SearchInputBar/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ export default class Index extends Component<IndexProps, IndexState> {
4242
ref={this.ref}
4343
onChangeText={val => this.onChangeText(val, 'value')}
4444
onClear={() => this.onClear('value')}
45+
placeholder="请输入搜索关键字"
4546
value={this.state.value}
4647
button={{
48+
type: 'success',
4749
onPress: () => {
4850
console.log('object', this.ref);
4951
Toast.info('你点击了搜索', 2, 'info');

packages/core/src/SearchInputBar/index.tsx

Lines changed: 69 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import React from 'react';
22
import {
33
View,
44
StyleSheet,
5+
StyleProp,
6+
ViewStyle,
57
Text,
68
TouchableOpacity,
79
Animated,
@@ -10,21 +12,27 @@ import {
1012
TextInputFocusEventData,
1113
TextInputProps,
1214
} from 'react-native';
13-
import Icon from '../Icon';
14-
import { ButtonProps } from '../Button';
15+
import Icon, { IconsProps } from '../Icon';
16+
import Button, { ButtonProps } from '../Button';
1517
import RightButton from './RightButton';
1618

1719
export interface SearchInputBarProps extends TextInputProps {
18-
/** 点击清除按钮时触发事件 */
19-
onClear?: Function;
20+
/** 容器样式 */
21+
containerStyle?: StyleProp<ViewStyle>;
2022
/** 右侧按钮 */
2123
button?: ButtonProps;
2224
/** 右侧按钮文案 */
2325
actionName?: string;
24-
/** 右侧按钮宽度默认70 */
25-
buttonWidth?: number;
26-
/** 是否一直显示右侧按钮 */
27-
showActionButton?: boolean;
26+
/** 是否一直显示右侧按钮 null = 永不显示 */
27+
showActionButton?: boolean | null;
28+
/** 搜索图标 */
29+
searchIcon?: IconsProps;
30+
/** 点击搜索图标时触发事件 */
31+
onSearch?: Function;
32+
/** 清除图标 */
33+
closeIcon?: IconsProps;
34+
/** 点击清除图标时触发事件 */
35+
onClear?: Function;
2836
}
2937

3038
interface SearchInputBarState {
@@ -35,12 +43,7 @@ interface SearchInputBarState {
3543
}
3644

3745
export default class SearchInputBar extends React.Component<SearchInputBarProps, SearchInputBarState> {
38-
private inputRef = React.createRef<TextInput>();
39-
private moveLeft: Animated.Value = new Animated.Value(0);
40-
private placeholderIcon = React.createRef<View>();
41-
private placeholderAnimated: Animated.Value = new Animated.Value(1);
42-
private buttonAnimated: Animated.Value = new Animated.Value(this.props.buttonWidth ?? 70);
43-
private buttonAnimatedWidth: Animated.Value = new Animated.Value(0);
46+
public inputRef = React.createRef<TextInput>();
4447
constructor(props: SearchInputBarProps) {
4548
super(props);
4649
this.state = {
@@ -49,198 +52,91 @@ export default class SearchInputBar extends React.Component<SearchInputBarProps,
4952
};
5053
}
5154

52-
changeIconBoxStyle = (flag: boolean) => {
53-
if ('_value' in this.buttonAnimatedWidth) {
54-
const _value = (this.buttonAnimatedWidth as any)._value;
55-
if (_value && !flag) {
56-
return;
57-
}
58-
}
59-
const { buttonWidth = 70, showActionButton } = this.props;
60-
Animated.timing(this.placeholderAnimated, {
61-
toValue: flag ? 1 : 0,
62-
duration: 50,
63-
useNativeDriver: true,
64-
}).start();
65-
66-
Animated.timing(this.buttonAnimated, {
67-
toValue: flag ? buttonWidth : 0,
68-
duration: 150,
69-
useNativeDriver: true,
70-
}).start(() => {});
71-
this.buttonAnimatedWidth.setValue(flag ? 0 : buttonWidth);
72-
73-
this.placeholderIcon.current &&
74-
this.placeholderIcon.current.measure(
75-
(_frameOffsetX, _frameOffsetY, _width, _height, pageOffsetX, pageOffsetY) => {
76-
const num = showActionButton ? 0 : buttonWidth;
77-
Animated.timing(this.moveLeft, {
78-
toValue: flag ? 0 : -pageOffsetX + 20 + num / 2 + 10,
79-
duration: 300,
80-
useNativeDriver: true,
81-
}).start(({ finished }) => {
82-
flag || (this.inputRef.current && this.inputRef.current.focus());
83-
});
84-
},
85-
);
86-
};
87-
onChangeText = (value: string) => {
88-
const { onChangeText = Function } = this.props;
89-
onChangeText(value);
90-
if (!value && this.state.showIcon) {
91-
this.setState({ showIcon: false });
92-
return;
55+
needFocus = (type: 'search' | 'close' | 'actived') => {
56+
if (type === 'close') {
57+
this.props.onClear?.();
58+
} else if (type === 'search') {
59+
this.props.onSearch?.();
9360
}
94-
if (value && !this.state.showIcon) {
95-
this.inputRef.current &&
96-
this.inputRef.current.measure((_frameOffsetX, _frameOffsetY, _width) => {
97-
this.setState({ showIconLeft: _width - 40, showIcon: true });
98-
});
99-
}
100-
};
101-
componentDidMount() {
102-
const { value, buttonWidth = 70, showActionButton } = this.props;
103-
if (value) {
104-
Animated.timing(this.placeholderAnimated, {
105-
toValue: 1,
106-
duration: 100,
107-
useNativeDriver: true,
108-
}).start(() => {
109-
this.changeIconBoxStyle(false);
110-
this.inputRef.current &&
111-
this.inputRef.current.measure((_frameOffsetX, _frameOffsetY, _width) => {
112-
let num = showActionButton ? 0 : buttonWidth;
113-
this.setState({ showIconLeft: _width - 40 - num!, showIcon: true });
114-
});
115-
});
61+
if (type === 'actived') {
62+
this.setState({ showIcon: true });
11663
}
117-
}
118-
119-
onClose = () => {
120-
const { onClear } = this.props;
121-
onClear?.();
122-
this.setState({ showIcon: false });
64+
console.log('object', type);
12365
this.inputRef.current && this.inputRef.current.focus();
12466
};
12567
render() {
126-
const { showIcon, showIconLeft } = this.state;
12768
const {
12869
value,
129-
onBlur,
130-
placeholder = '请输入',
131-
buttonWidth = 70,
132-
showActionButton = false,
70+
onChangeText,
71+
showActionButton,
72+
actionName = '搜索',
13373
button,
134-
actionName,
74+
style,
75+
containerStyle,
76+
searchIcon,
77+
closeIcon,
13578
...other
13679
} = this.props;
13780
return (
138-
<View style={styles.searchContainer}>
139-
<View style={[styles.centerBox, { justifyContent: 'space-between', overflow: 'hidden' }]}>
81+
<View style={[styles.centerFlex]}>
82+
<View style={StyleSheet.flatten([styles.searchContainer, styles.centerFlex, containerStyle])}>
83+
<View>
84+
<TouchableOpacity style={{}} onPress={() => this.needFocus('search')}>
85+
<Icon name="search" size={18} color="#999" height={'100%'} {...searchIcon} />
86+
</TouchableOpacity>
87+
</View>
14088
<TextInput
14189
{...other}
142-
ref={this.inputRef}
143-
style={[styles.searchInput, { flex: 1 }]}
144-
onChangeText={this.onChangeText}
14590
value={value}
146-
onBlur={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
147-
if (!value) {
148-
this.changeIconBoxStyle(true);
91+
onChangeText={onChangeText}
92+
ref={this.inputRef}
93+
style={[styles.textInput, style]}
94+
onFocus={(e: NativeSyntheticEvent<TextInputFocusEventData>) => {
95+
if (showActionButton !== null) {
96+
this.setState({ showIcon: true });
14997
}
150-
onBlur?.(event);
98+
other?.onFocus?.(e);
15199
}}
152-
/>
153-
<Animated.View style={showActionButton ? {} : { transform: [{ translateX: this.buttonAnimated }] }}>
154-
<Animated.View style={showActionButton ? {} : { width: this.buttonAnimatedWidth }}>
155-
<RightButton width={buttonWidth} isShow actionName={actionName} {...button} />
156-
</Animated.View>
157-
</Animated.View>
158-
</View>
159-
160-
<View style={[styles.iconBox, { justifyContent: 'space-between', overflow: 'hidden' }]}>
161-
<TouchableOpacity
162-
activeOpacity={1}
163-
style={[styles.centerBox, { flex: 1 }]}
164-
onPress={() => {
165-
this.changeIconBoxStyle(false);
100+
onBlur={(e: NativeSyntheticEvent<TextInputFocusEventData>) => {
101+
this.setState({ showIcon: false });
102+
other?.onBlur?.(e);
166103
}}
167-
>
168-
<Animated.View style={[{ transform: [{ translateX: this.moveLeft }] }]}>
169-
<View style={[styles.centerBox]} ref={this.placeholderIcon}>
170-
<Icon name="search" size={18} color="#999" />
171-
</View>
172-
</Animated.View>
173-
<Animated.View style={[{ transform: [{ translateX: this.moveLeft }] }]}>
174-
<Animated.View style={[styles.centerBox, { opacity: this.placeholderAnimated }]}>
175-
<Text style={styles.placeholderStyle}>{placeholder}</Text>
176-
</Animated.View>
177-
</Animated.View>
178-
</TouchableOpacity>
179-
180-
<Animated.View style={showActionButton ? {} : { transform: [{ translateX: this.buttonAnimated }] }}>
181-
<Animated.View style={showActionButton ? {} : { width: this.buttonAnimatedWidth }}>
182-
<RightButton width={buttonWidth} isShow actionName={actionName} {...button} />
183-
</Animated.View>
184-
</Animated.View>
104+
/>
105+
{Boolean(value) && (
106+
<TouchableOpacity style={{}} onPress={() => this.needFocus('close')}>
107+
<Icon name="close" size={18} color="#999" height={'100%'} {...closeIcon} />
108+
</TouchableOpacity>
109+
)}
185110
</View>
186-
187-
{showIcon && (
188-
<TouchableOpacity
189-
activeOpacity={1}
190-
style={[styles.closeStyle, styles.centerBox, { left: showIconLeft }]}
191-
onPress={this.onClose}
192-
>
193-
<Icon name="close" size={18} color="#999" />
194-
</TouchableOpacity>
111+
{(showActionButton || this.state.showIcon) && (
112+
<Button type="primary" {...button}>
113+
{actionName}
114+
</Button>
195115
)}
196116
</View>
197117
);
198118
}
199119
}
200120

201121
const styles = StyleSheet.create({
202-
searchContainer: {
203-
paddingHorizontal: 20,
204-
borderRadius: 5,
205-
height: 40,
206-
overflow: 'hidden',
207-
},
208-
iconBox: {
209-
height: 40,
210-
display: 'flex',
122+
centerFlex: {
211123
flexDirection: 'row',
212-
alignItems: 'center',
213124
justifyContent: 'center',
214-
backgroundColor: 'transparent',
215-
position: 'relative',
216-
top: -40,
217-
zIndex: 1,
125+
alignContent: 'center',
218126
},
219-
centerBox: {
220-
display: 'flex',
221-
flexDirection: 'row',
222-
alignItems: 'center',
223-
justifyContent: 'center',
224-
},
225-
placeholderStyle: {
226-
paddingLeft: 10,
227-
fontSize: 18,
228-
color: '#999',
229-
},
230-
searchInput: {
127+
searchContainer: {
231128
height: 40,
232129
borderColor: 'gray',
233130
borderWidth: 1,
234131
borderRadius: 20,
235-
backgroundColor: '#f7f7f7',
236-
fontSize: 18,
237-
paddingHorizontal: 40,
132+
flex: 1,
133+
paddingHorizontal: 10,
134+
marginRight: 10,
238135
},
239-
closeStyle: {
240-
position: 'relative',
136+
textInput: {
241137
height: 40,
242-
width: 40,
243-
top: -80,
244-
zIndex: 2,
138+
flex: 1,
139+
fontSize: 18,
140+
paddingHorizontal: 8,
245141
},
246142
});

0 commit comments

Comments
 (0)