Skip to content

Commit 87eb1e4

Browse files
committed
fix(Picker): 增加弹开 & 联动
1 parent 66e2cf3 commit 87eb1e4

File tree

10 files changed

+517
-364
lines changed

10 files changed

+517
-364
lines changed
Lines changed: 53 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,58 @@
11
import React from 'react';
2-
import {Text, View} from 'react-native';
3-
import {Picker, Button} from '@uiw/react-native';
2+
import {SafeAreaView} from 'react-native';
3+
import {Picker, Button, Spacing} from '@uiw/react-native';
44
import {ComProps} from '../../routes';
5-
import Layout, {Container} from '../../Layout';
6-
const {Header, Body, Footer} = Layout;
75

8-
export interface BadgeViewProps extends ComProps {}
6+
export interface PickerViewProps extends ComProps {}
97

10-
export default class BadgeView extends React.Component<BadgeViewProps> {
11-
state = {
12-
value: 1,
13-
};
14-
render() {
15-
const {route, navigation} = this.props;
16-
const description = route.params.description;
17-
const title = route.params.title;
18-
const arr = [];
19-
for (let i = 0; i < 100; i++) {
20-
arr.push({label: i});
21-
}
22-
return (
23-
<Container scrollEnabled={false}>
24-
<Layout>
25-
<Header title={title} description={description} />
26-
<Body scrollEnabled={false}>
27-
<View
28-
style={{
29-
flex: 1,
30-
flexDirection: 'row',
31-
backgroundColor: '#fff',
32-
marginTop: 20,
33-
paddingVertical: 20,
34-
}}>
35-
<View style={{width: '50%'}}>
36-
<Picker data={arr as any} value={17} />
37-
</View>
38-
<View style={{width: '50%'}}>
39-
<Picker
40-
onChange={val => {
41-
console.log('val: ', val);
42-
}}
43-
data={arr as any}
44-
value={this.state.value}
45-
/>
46-
</View>
47-
</View>
48-
<Button
49-
onPress={() => {
50-
this.setState({value: this.state.value + 1});
51-
}}>
52-
控制第二列value
53-
</Button>
54-
</Body>
55-
<Footer />
56-
</Layout>
57-
</Container>
58-
);
59-
}
8+
export default function (props: PickerViewProps) {
9+
const [value, setValue] = React.useState(['2', '22', '221']);
10+
const [value2, setValue2] = React.useState(['5']);
11+
const [visible, setVisible] = React.useState(false);
12+
const arr = [
13+
{
14+
label: '江苏省',
15+
value: '1',
16+
children: [
17+
{
18+
label: '南京市',
19+
value: '11',
20+
children: [
21+
{label: '宣武区', value: '111'},
22+
{label: '雨花台区', value: '112'},
23+
],
24+
},
25+
{
26+
label: '苏州市',
27+
value: '12',
28+
children: [{label: '苏州区', value: '121'}],
29+
},
30+
],
31+
},
32+
{label: '北京市', value: '2', children: [{label: '北京市', value: '22', children: [{label: '朝阳区', value: '221'}]}]},
33+
];
34+
35+
const arr2 = [
36+
{label: '3', value: '3'},
37+
{label: '4', value: '4'},
38+
{label: '5', value: '5'},
39+
];
40+
41+
return (
42+
<SafeAreaView style={{flex: 1}}>
43+
<Button onPress={() => setVisible(true)}>打开</Button>
44+
<Picker
45+
title="标题"
46+
displayType="modal"
47+
value={value}
48+
onChange={(val: any) => setValue(val)}
49+
visible={visible}
50+
cols={3}
51+
onClosed={() => setVisible(false)}
52+
data={arr as any}
53+
/>
54+
<Spacing />
55+
<Picker cols={1} displayType="view" data={arr2 as any} value={value2} onChange={(val2: any) => setValue2(val2)} />
56+
</SafeAreaView>
57+
);
6058
}

packages/core/src/DatePicker/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, { useState, useEffect, useRef } from 'react';
22
import { View, StyleSheet, SafeAreaView, StyleProp, TextStyle } from 'react-native';
33
import Modal, { ModalProps } from '../Modal';
4-
import { PickerProps } from '../Picker';
54
import PickerView, { DateKey } from './component/PickerView';
65
import Control from './component/Control';
76
import {
@@ -48,7 +47,7 @@ export interface DatePickerProps {
4847
/** modal 属性 */
4948
modalProps?: ModalProps;
5049
/** picker 属性 */
51-
pickerProps?: PickerProps;
50+
pickerProps?: any;
5251
}
5352
interface DateIndex {
5453
year?: number;

packages/core/src/Modal/index.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -89,24 +89,27 @@ const Modal = (props: ModalProps = {}) => {
8989
if (isHorizontal) {
9090
translateStyle.translateX = translateValue;
9191
}
92-
const child = (
93-
<Animated.View
94-
style={[styles.content, placement && styles[placement], { opacity: AnimatedOpacity }, containerStyle]}
95-
>
92+
const child = React.useMemo(
93+
() => (
9694
<Animated.View
97-
onLayout={measureContainer}
98-
style={[
99-
styles.content,
100-
placement && styles[placement],
101-
// !layoutHeight && isVertical ? { display: display } : {},
102-
// !layoutWidth && isHorizontal ? { display: display } : {},
103-
// // getTransformStyle(),
104-
{ transform: [translateStyle], backgroundColor: '#fff', position: 'relative', zIndex: 10000 },
105-
]}
95+
style={[styles.content, placement && styles[placement], { opacity: AnimatedOpacity }, containerStyle]}
10696
>
107-
{children}
97+
<Animated.View
98+
onLayout={measureContainer}
99+
style={[
100+
styles.content,
101+
placement && styles[placement],
102+
// !layoutHeight && isVertical ? { display: display } : {},
103+
// !layoutWidth && isHorizontal ? { display: display } : {},
104+
// // getTransformStyle(),
105+
{ transform: [translateStyle], backgroundColor: '#fff', position: 'relative', zIndex: 10000 },
106+
]}
107+
>
108+
{children}
109+
</Animated.View>
108110
</Animated.View>
109-
</Animated.View>
111+
),
112+
[children],
110113
);
111114
return (
112115
<MaskLayer {...otherProps} visible={visible} onDismiss={onDismiss}>

packages/core/src/Picker/README.md

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ Picker 选择器
33

44
解决 ios 与 android 和用户交互方式不同问题.
55
> 🚧测试版本
6-
> 避免出现样式错乱问题, 请尽量使用统一整数数字高度。
7-
> 激活状态尽量不要改变高度, 只是修改颜色作为标记。
86
<!--rehype:style=border-left: 8px solid #ffe564;background-color: #ffe56440;padding: 12px 16px;-->
97
108
<!-- ![](https://user-images.githubusercontent.com/66067296/139409471-846bdddb-99cc-4b2d-b2da-278da81b0c22.gif) -->
@@ -14,48 +12,78 @@ Picker 选择器
1412

1513
```jsx mdx:preview&background=#bebebe29
1614
import React from 'react';
17-
import { View } from 'react-native';
15+
import { SafeAreaView } from 'react-native';
1816
import { Picker } from '@uiw/react-native';
1917

2018
function Demo() {
19+
const [value, setValue] = React.useState(['5'])
20+
const arr1 = [
21+
{ label: '3', value: '3' },
22+
{ label: '4', value: '4' },
23+
{ label: '5', value: '5' },
24+
]
2125
return (
22-
<View style={{ flex: 1 }}>
26+
<SafeAreaView style={{ flex: 1 }}>
2327
<Picker
24-
data={[
25-
{label: '1'},
26-
{label: '2'},
27-
{label: '3'},
28-
{label: '4'},
29-
{label: '5'},
30-
]}
28+
cols={1}
29+
value={value}
30+
displayType="view"
31+
data={arr2}
32+
onChange={val => setValue(val)}
3133
/>
32-
</View>
34+
</SafeAreaView>
3335
)
3436
}
3537
export default Demo
3638
```
3739

38-
### 使用自定义元素
40+
### modal弹框 & 联动
3941

4042
```jsx mdx:preview&background=#bebebe29
4143
import React from 'react';
42-
import { View, Text } from 'react-native';
43-
import { Picker } from '@uiw/react-native';
44+
import { SafeAreaView } from 'react-native';
45+
import { Picker,Button } from '@uiw/react-native';
4446

4547
function Demo() {
48+
const [value, setValue] = React.useState(['2', '22', '221'])
49+
const [visible, setVisible] = React.useState(false)
50+
const arr = [
51+
{
52+
label: '江苏省',
53+
value: '1',
54+
children: [
55+
{
56+
label: '南京市', value: '11',
57+
children: [
58+
{ label: '宣武区', value: '111' },
59+
{ label: '雨花台区', value: '112' }
60+
]
61+
},
62+
{
63+
label: '苏州市',
64+
value: '12',
65+
children: [
66+
{ label: '苏州区', value: '121' }
67+
]
68+
}
69+
]
70+
},
71+
{ label: '北京市', value: '2', children: [{ label: '北京市', value: '22', children: [{ label: '朝阳区', value: '221' }] }] }
72+
];
4673
return (
47-
<View style={{ flex: 1 }}>
74+
<SafeAreaView style={{ flex: 1 }}>
75+
<Button onPress={() => setVisible(true)}>打开</Button>
4876
<Picker
49-
data={[
50-
{label: '1'},
51-
{label: '2'},
52-
{label: '3'},
53-
{label: '4'},
54-
{label: '5'},
55-
{label: '5',render: (label, record, index)=><Text>end</Text>},
56-
]}
77+
title="标题"
78+
displayType="modal"
79+
value={value}
80+
onChange={val => setValue(val)}
81+
visible={visible}
82+
cols={3}
83+
onClosed={() => setVisible(false)}
84+
data={arr}
5785
/>
58-
</View>
86+
</SafeAreaView>
5987
)
6088
}
6189
export default Demo
@@ -65,12 +93,14 @@ export default Demo
6593

6694
属性 | 说明 | 类型 | 默认值
6795
----|-----|------|------
68-
| lines | 显示行数 | number | 3 |
69-
| rowKey | 在开始位置设置图标 | string | - |
70-
| data | 需要渲染的数据 | Array | - |
71-
| containerStyle | item 容器样式 | obj | - |
72-
| textStyle | 容器的文本样式 | TextStyle | - |
73-
| value | 选中当前项的下标 | number | - |
74-
| onChange | value 改变时触发 | fn | - |
75-
| readonly | 是否只读 | fn | - |
96+
| data | 选择项列表 | `CascadePickerItemProps[]` | `Array<CascadePickerItemProps[]>` | [] |
97+
| cols | 展示几列 | `number` | 1 |
98+
| value | 当前值 | `ItemValue[]` | [] |
99+
| displayType | 选择器显示类型。view表示在页面显示;modal表示在弹窗中显示;默认为modal | `view | modal` | view |
100+
| onChange | 修改事件 | `(value?: ItemValue[]) => void` | - |
101+
| title | 选中当前项的下标 | number | - |
102+
| visible | 是否弹窗显示 | boolean | false |
103+
| onClosed | 弹窗关闭事件 | () => void | - |
104+
| cancelText | 取消按钮文本 | string | 取消 |
105+
| okText | 确认按钮文本 | string | 确认 |
76106

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React, { memo } from 'react';
2+
import { Animated, StyleSheet, Text } from 'react-native';
3+
4+
import { WhellPickerItemProps } from './type';
5+
6+
const opacityFunction = (val: number) => 1 / (1 + Math.abs(val));
7+
const scaleFunction = (val: number) => 1 - 0.1 * Math.abs(val);
8+
const rotationFunction = (val: number) => 20 * val;
9+
10+
function WheelPickerItem({ textStyle, style, visibleRest, height, option, index, currentIndex }: WhellPickerItemProps) {
11+
const relativeScrollIndex = Animated.subtract(index, currentIndex);
12+
13+
const inputRange = [0];
14+
for (let i = 1; i <= visibleRest + 1; i++) {
15+
inputRange.unshift(-i);
16+
inputRange.push(i);
17+
}
18+
19+
const opacityOutputRange = [1];
20+
for (let x = 1; x <= visibleRest + 1; x++) {
21+
const y = opacityFunction(x);
22+
opacityOutputRange.unshift(y);
23+
opacityOutputRange.push(y);
24+
}
25+
26+
const scaleOutputRange = [1.0];
27+
for (let x = 1; x <= visibleRest + 1; x++) {
28+
const y = scaleFunction(x);
29+
scaleOutputRange.unshift(y);
30+
scaleOutputRange.push(y);
31+
}
32+
33+
const rotateXOutputRange = ['0deg'];
34+
for (let x = 1; x <= visibleRest + 1; x++) {
35+
const y = rotationFunction(x);
36+
rotateXOutputRange.unshift(`${y}deg`);
37+
rotateXOutputRange.push(`${y}deg`);
38+
}
39+
40+
const opacity = relativeScrollIndex.interpolate({ inputRange, outputRange: opacityOutputRange });
41+
const scale = relativeScrollIndex.interpolate({ inputRange, outputRange: scaleOutputRange });
42+
const rotateX = relativeScrollIndex.interpolate({ inputRange, outputRange: rotateXOutputRange });
43+
44+
return (
45+
<Animated.View style={[styles.option, style, { height, opacity, transform: [{ rotateX }, { scale }] }]}>
46+
<Text style={textStyle}>{option?.label}</Text>
47+
</Animated.View>
48+
);
49+
}
50+
51+
export default WheelPickerItem;
52+
53+
const styles = StyleSheet.create({
54+
option: {
55+
alignItems: 'center',
56+
justifyContent: 'center',
57+
zIndex: 100,
58+
},
59+
});

0 commit comments

Comments
 (0)