Skip to content

Commit f4dcbfd

Browse files
committed
fix(Tabs): 新增value/onChange/activeColor api
1 parent 5777d67 commit f4dcbfd

File tree

4 files changed

+69
-149
lines changed

4 files changed

+69
-149
lines changed

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

Lines changed: 20 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,62 @@
11
import React, {Component} from 'react';
22
import {StyleSheet, View} from 'react-native';
33
import Layout, {Container} from '../../Layout';
4-
import {Tabs, Icon, IconsName} from '@uiw/react-native';
4+
import {Tabs, IconsName} from '@uiw/react-native';
55
import {ComProps} from '../../routes';
66

7-
const {Header, Body, Card, Footer} = Layout;
7+
const {Header, Body, Footer} = Layout;
88

99
export interface listItem {
1010
title: string | React.ReactElement | React.ReactNode;
1111
icon: IconsName | React.ReactElement | React.ReactNode;
1212
}
1313
export interface IndexProps extends ComProps {}
1414
export interface IndexState {
15-
flag1: string;
16-
flag: string;
15+
flag1: number;
16+
flag: number;
1717
color1: string;
1818
}
1919

2020
export default class Index extends Component<IndexProps, IndexState> {
2121
constructor(props: IndexProps) {
2222
super(props);
2323
this.state = {
24-
flag: '喜欢',
25-
flag1: '喜欢',
24+
flag: 2,
25+
flag1: 1,
2626
color1: '#f18700',
2727
};
2828
}
29-
onPress1 = (val: string) => {
29+
onPress1 = (val: number) => {
3030
this.setState({flag: val});
3131
};
32-
onPress = (val: string) => {
32+
onPress = (val: number) => {
3333
this.setState({flag1: val});
3434
};
3535
render() {
3636
const {route} = this.props;
3737
const description = route.params.description;
3838
const title = route.params.title;
39-
const {Item} = Tabs;
39+
4040
return (
4141
<Container>
4242
<Layout>
4343
<Header title={title} description={description} />
4444
<Body>
45-
<Tabs>
46-
<Item
47-
title={'喜欢'}
48-
icon="heart-on"
49-
style={{
50-
iconColor:
51-
this.state.flag === '喜欢' ? this.state.color1 : undefined,
52-
titleColor:
53-
this.state.flag === '喜欢' ? this.state.color1 : undefined,
54-
}}
55-
border={this.state.flag === '喜欢'}
56-
onPress={this.onPress1}
57-
/>
58-
<Tabs.Item
59-
title={'关注'}
60-
style={{
61-
titleColor:
62-
this.state.flag === '关注' ? this.state.color1 : undefined,
63-
}}
64-
icon={
65-
<Icon
66-
name="star-on"
67-
color={
68-
this.state.flag === '关注' ? this.state.color1 : '#fff'
69-
}
70-
size={24}
71-
/>
72-
}
73-
border={this.state.flag === '关注'}
74-
onPress={this.onPress1}
75-
/>
76-
<Tabs.Item
77-
title={'信息'}
78-
icon="mail"
79-
style={{
80-
iconColor:
81-
this.state.flag === '信息' ? this.state.color1 : undefined,
82-
titleColor:
83-
this.state.flag === '信息' ? this.state.color1 : undefined,
84-
}}
85-
border={this.state.flag === '信息'}
86-
onPress={this.onPress1}
87-
/>
45+
<Tabs value={this.state.flag} onChange={value => this.setState({flag: value})}>
46+
<Tabs.Item title="喜欢" />
47+
<Tabs.Item title="关注" />
48+
<Tabs.Item title="兴趣" />
49+
<Tabs.Item title="爱好" />
50+
<Tabs.Item title="gitlabl" />
51+
<Tabs.Item title="github" />
8852
</Tabs>
8953

9054
<View style={styles.divider} />
9155

92-
<Tabs>
93-
<Tabs.Item
94-
title={'喜欢'}
95-
border={this.state.flag1 === '喜欢'}
96-
onPress={this.onPress}
97-
style={{
98-
titleColor:
99-
this.state.flag1 === '喜欢' ? this.state.color1 : undefined,
100-
borderColor:
101-
this.state.flag1 === '喜欢' ? this.state.color1 : undefined,
102-
}}
103-
/>
104-
<Tabs.Item
105-
title={'关注'}
106-
border={this.state.flag1 === '关注'}
107-
onPress={this.onPress}
108-
style={{
109-
titleColor:
110-
this.state.flag1 === '关注' ? this.state.color1 : undefined,
111-
borderColor:
112-
this.state.flag1 === '关注' ? this.state.color1 : undefined,
113-
}}
114-
/>
115-
<Tabs.Item
116-
title={'信息'}
117-
border={this.state.flag1 === '信息'}
118-
onPress={this.onPress}
119-
style={{
120-
titleColor:
121-
this.state.flag1 === '信息' ? this.state.color1 : undefined,
122-
borderColor:
123-
this.state.flag1 === '信息' ? this.state.color1 : undefined,
124-
}}
125-
/>
126-
<Tabs.Item
127-
title={'我的'}
128-
border={this.state.flag1 === '我的'}
129-
onPress={this.onPress}
130-
style={{
131-
titleColor:
132-
this.state.flag1 === '我的' ? this.state.color1 : undefined,
133-
borderColor:
134-
this.state.flag1 === '我的' ? this.state.color1 : undefined,
135-
}}
136-
/>
137-
<Tabs.Item
138-
title={'偏好'}
139-
border={this.state.flag1 === '偏好'}
140-
onPress={this.onPress}
141-
style={{
142-
titleColor:
143-
this.state.flag1 === '偏好' ? this.state.color1 : undefined,
144-
borderColor:
145-
this.state.flag1 === '偏好' ? this.state.color1 : undefined,
146-
}}
147-
/>
56+
<Tabs value={this.state.flag1} onChange={value => this.setState({flag1: value})} activeColor={this.state.color1}>
57+
<Tabs.Item title={'喜欢'} icon="heart-on" />
58+
<Tabs.Item title={'关注'} icon="heart-on" />
59+
<Tabs.Item title={'信息'} icon="mail" />
14860
</Tabs>
14961
</Body>
15062
<Footer />

packages/core/src/Tabs/README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,28 +113,27 @@ export default Demo
113113
|------|------|-----|------|
114114
| `children` | 子元素 | JSX.Element | - |
115115
| `style` | 容器样式 | `ViewStyle` | - |
116+
| `value` || `number` | - |
117+
| `onChange` | 点击tab栏变化 | `(value: number) => void` | - |
118+
| `activeColor` | 选中后颜色 | `string` | `#035bb6` |
116119

117120
### Tabs.Item Props
118121

119122
| 参数 | 说明 | 类型 | 默认值 |
120123
|------|------|-----|------|
121124
| `title` | 显示的文字 | string | - |
122125
| `style` | 样式集合,具体项见下表 | TabsItemStyle | - |
123-
| `onPress` | 点击时触发 | (title: string) => void | - |
124126
| `icon` | 图标 | JSX.Element, React.ReactNode, React.ReactElement, IconsName | - |
125-
| `border` | 是否显示下边框 | boolean | - |
127+
126128

127129
### TabsItemStyle
128130
| 参数 | 说明 | 类型 | 默认值 |
129131
|------|------|-----|------|
130132
| `width` | 宽度 | number | - |
131-
| `titleColor` | 文字颜色 | string | - |
132133
| `titleFontWeight` | 文字粗细 |`'100' \| '200' \| '300' \| '400' \| '500' \| '600' \| '700' \| '800' \| '900' \| 'bold' \| 'normal'`| - |
133134
| `titleSize` | 文字大小 | number | - |
134-
| `iconColor` | icon 颜色 | string | - |
135135
| `iconSize` | icon 大小 | number | - |
136136
| `borderWidth` | border 宽度 | number | - |
137-
| `borderColor` | border 颜色 | string | - |
138137
| `borderBottom` | border 底部距离 | number | - |
139138
| `borderHeight` | border 粗细 | number | - |
140139

packages/core/src/Tabs/TabsItem.tsx

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,14 @@ export type TabsItemIconTypes = IconsName | React.ReactElement | React.ReactNode
99
export interface TabsItemStyle {
1010
/** 宽度 */
1111
width?: number;
12-
/** 文字颜色 */
13-
titleColor?: string;
1412
/** 文字粗细 */
1513
titleFontWeight?: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | 'bold' | 'normal';
1614
/** 文字大小 */
1715
titleSize?: number;
18-
/** icon 颜色 */
19-
iconColor?: string;
2016
/** icon 大小 */
2117
iconSize?: number;
2218
/** border 宽度 */
2319
borderWidth?: number;
24-
/** border 颜色 */
25-
borderColor?: string;
2620
/** border 距离底部距离一般与 Tabs paddingBottom 相等 */
2721
borderBottom?: number;
2822
/** border 粗细 */
@@ -41,33 +35,37 @@ export interface TabsItemProps {
4135
onPress?: (title: string) => void;
4236
/** 图标 */
4337
icon?: TabsItemIconTypes;
44-
/** 是否显示下边框 */
45-
border?: boolean;
38+
activeColor?: string;
39+
value?: number;
40+
onChange?: (value: number) => void;
41+
index?: number;
4642
}
4743

4844
function TabsItem(props: TabsItemProps) {
45+
const { activeColor, icon, index, value, onChange } = props;
46+
console.log('value', value, 'index', index);
4947
const style = useCallback(() => {
5048
const { style = {} } = props;
5149
const titleBoxStyle = {
5250
width: style.width ?? 100,
5351
};
5452
const titleStyle = {
5553
fontSize: style.titleSize ?? 20,
56-
color: style.titleColor ?? '#fff',
54+
color: index === value && activeColor ? activeColor : '#035bb6',
5755
fontWeight: style.titleFontWeight ?? '600',
5856
};
5957
const iconBoxStyle = {
6058
width: style.width ?? 100,
6159
};
6260
const iconStyle = {
63-
color: style.iconColor ?? '#fff',
61+
color: index === value && activeColor ? activeColor : '#035bb6',
6462
size: style.iconSize ?? 24,
6563
};
6664
const borderColor = {
6765
width: style.borderWidth ?? 40,
6866
borderBottomWidth: style.borderHeight ?? 4,
69-
borderBottomColor: style.borderColor ?? '#fff',
70-
bottom: -(style.borderBottom ?? 20),
67+
borderBottomColor: index === value && activeColor ? activeColor : '#035bb6',
68+
bottom: 0,
7169
};
7270
return {
7371
titleBoxStyle,
@@ -76,38 +74,36 @@ function TabsItem(props: TabsItemProps) {
7674
iconStyle,
7775
borderColor,
7876
};
79-
}, [props.style]);
77+
}, [value, activeColor]);
8078

8179
const IconDom = useMemo(() => {
8280
const isIconDom = () => {
83-
if (typeof props.icon === 'string') {
84-
return <Icon name={props.icon as IconsName} color={style().iconStyle.color} size={style().iconStyle.size} />;
81+
if (typeof icon === 'string') {
82+
return <Icon name={icon as IconsName} color={style().iconStyle.color} size={style().iconStyle.size} />;
8583
} else {
86-
return <React.Fragment>{props.icon}</React.Fragment>;
84+
return <React.Fragment>{icon}</React.Fragment>;
8785
}
8886
};
89-
if (props.icon) {
87+
if (icon) {
9088
return <View style={[styles.iconBox, { ...style().iconBoxStyle }]}>{isIconDom()}</View>;
91-
} else return null;
92-
}, [props.icon, props.style]);
89+
}
90+
return null;
91+
}, [icon, props.style, value, activeColor]);
9392

9493
const BorderDom = useMemo(() => {
95-
if (props.border) {
94+
if (value === index) {
9695
return (
9796
<View style={styles.bottomView}>
9897
<View style={[styles.bottom, { ...style().borderColor }]} />
9998
</View>
10099
);
101-
} else return null;
102-
}, [props.border]);
100+
}
101+
return null;
102+
}, [value]);
103103

104104
return (
105105
<View style={styles.TabsItemContainer}>
106-
<TouchableOpacity
107-
onPress={() => {
108-
props.onPress && props.onPress(props.title);
109-
}}
110-
>
106+
<TouchableOpacity onPress={() => (index === 0 || index) && onChange?.(index)}>
111107
{IconDom}
112108
<View style={[styles.titleBox, { ...style().titleBoxStyle }]}>
113109
<Text style={[styles.title, { ...style().titleStyle }]}>{props.title}</Text>
@@ -131,6 +127,7 @@ const styles = StyleSheet.create({
131127
},
132128
titleBox: {
133129
paddingTop: 10,
130+
paddingBottom: 10,
134131
},
135132
title: {
136133
textAlign: 'center',

packages/core/src/Tabs/index.tsx

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ export interface TabsProps extends ViewProps {
1010
children?: JSX.Element | Array<JSX.Element>;
1111
/** 容器样式 */
1212
style?: ViewStyle;
13+
value?: number;
14+
onChange?: (value: number) => void;
15+
activeColor?: string;
1316
}
1417

1518
function Tabs(props: TabsProps) {
16-
const { style, children, ...other } = props;
19+
const { style, children, onChange, activeColor, value } = props;
1720
if (!children) {
1821
return null;
1922
}
@@ -34,11 +37,20 @@ function Tabs(props: TabsProps) {
3437

3538
return (
3639
<SafeAreaView style={styles.container}>
37-
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
38-
<View style={[styles.TabsContainer, style]} {...other}>
39-
{props.children}
40-
</View>
41-
</ScrollView>
40+
<View style={[styles.TabsContainer, style]}>
41+
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
42+
{children &&
43+
React.Children.toArray(children).map((child, index) => {
44+
if (!React.isValidElement(child)) {
45+
return;
46+
}
47+
return React.cloneElement(child, {
48+
...child.props,
49+
...{ value: value, onChange: onChange, index: index, activeColor: activeColor },
50+
});
51+
})}
52+
</ScrollView>
53+
</View>
4254
</SafeAreaView>
4355
);
4456
}
@@ -49,10 +61,10 @@ const styles = StyleSheet.create({
4961
marginTop: StatusBar.currentHeight || 0,
5062
},
5163
TabsContainer: {
52-
backgroundColor: '#3e8ad5',
64+
backgroundColor: '#fff',
5365
minWidth: 1 * MainWidth,
54-
flexDirection: 'row',
55-
justifyContent: 'space-evenly',
66+
display: 'flex',
67+
justifyContent: 'space-between',
5668
alignItems: 'center',
5769
paddingTop: 15,
5870
paddingBottom: 20,

0 commit comments

Comments
 (0)