Skip to content

Commit 1a128a7

Browse files
authored
Merge pull request #588 from hy916/dev
fix(Accordion)添加Accordion手风琴组件
2 parents e4923c7 + c6bb251 commit 1a128a7

File tree

11 files changed

+288
-13
lines changed

11 files changed

+288
-13
lines changed
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import React from 'react';
2-
import {View, Text, StyleSheet} from 'react-native';
2+
import { View, Text, StyleSheet } from 'react-native';
33
const ImagePicker = () => {
4-
return (
5-
<View style={styles.tree}>
4+
return <View style={styles.tree}>
65
<Text>ImagePicker</Text>
7-
</View>
8-
);
6+
</View>;
97
};
108
const styles = StyleSheet.create({
119
tree: {
1210
paddingHorizontal: 10,
1311
paddingVertical: 5,
14-
backgroundColor: '#fff',
15-
},
12+
backgroundColor: '#fff'
13+
}
1614
});
17-
export default ImagePicker;
15+
export default ImagePicker;

example/examples/lib2/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export {default as ImagePicker} from './ImagePicker';
1+
export { default as ImagePicker } from './ImagePicker';
22
export * from './ImagePicker';

example/examples/lib2/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export {default as ImagePicker} from './ImagePicker';
2-
export * from './ImagePicker';
1+
export { default as ImagePicker } from './ImagePicker';
2+
export * from './ImagePicker';

example/examples/src/routes.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {StackNavigationProp, StackNavigationOptions} from '@react-navigation/stack';
1+
import { StackNavigationProp, StackNavigationOptions } from '@react-navigation/stack';
22

33
type ModalStackNavigation = StackNavigationProp<{}>;
44

@@ -498,4 +498,12 @@ export const stackPageData: Routes[] = [
498498
description: '图片上传',
499499
},
500500
},
501+
{
502+
name: 'Accordion',
503+
component: require('./routes/Accordion').default,
504+
params: {
505+
title: 'Accordion 手风琴',
506+
description: '可以折叠/展开的内容区域。',
507+
},
508+
},
501509
];
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React, { Component } from 'react';
2+
import { View, Image } from 'react-native';
3+
import { Accordion, Text } from '@uiw/react-native';
4+
import Layout, { Container } from '../../Layout';
5+
import { ComProps } from '../../routes';
6+
const { Header, Body, Card, Footer } = Layout;
7+
8+
export interface Accordion extends ComProps { }
9+
10+
const contents = [
11+
{
12+
title: <Text>Section 1</Text>,
13+
content: (
14+
<View>
15+
<Text>Content of section 1</Text>
16+
<Image source={{ uri: 'https://wx3.sinaimg.cn/mw690/4718260ely1gt2cg7t5udj23dw1wkhdu.jpg' }} style={{ height: 180 }} />
17+
</View>
18+
),
19+
},
20+
{
21+
title: <Text>Section 2</Text>,
22+
content: (
23+
<View>
24+
<Text>Content of section 2</Text>
25+
<Image source={{ uri: 'https://wx1.sinaimg.cn/mw690/4718260ely1gt2cg5r9zij22yo1o0x6p.jpg' }} style={{ height: 180 }} />
26+
</View>
27+
),
28+
},
29+
{
30+
title: <Text>Section 3</Text>,
31+
content: (
32+
<View>
33+
<Text>Content of section 3</Text>
34+
<Image source={{ uri: 'https://iknow-pic.cdn.bcebos.com/810a19d8bc3eb135828572d2ab1ea8d3fd1f441d' }} style={{ height: 180 }} />
35+
</View>
36+
),
37+
},
38+
];
39+
export default class MenuDropdownView extends Component<Accordion> {
40+
state = {
41+
expanded: false,
42+
top: false,
43+
};
44+
render() {
45+
const { route } = this.props;
46+
const description = route.params.description;
47+
const title = route.params.title;
48+
return (
49+
<Container>
50+
<Layout>
51+
<Header title={title} description={description} />
52+
<Body>
53+
<Card title="基础实例">
54+
<Accordion sections={contents} />
55+
</Card>
56+
<Card title="是否可以展开多个.默认为是,当前为否">
57+
<Accordion sections={contents} isMultiple={false} />
58+
</Card>
59+
<Card title="是否展示右侧图标,默认为是,当前为否">
60+
<Accordion sections={contents} iconShow={false} />
61+
</Card>
62+
<Card title="设置右侧图标尺寸大小">
63+
<Accordion sections={contents} iconSize={30} />
64+
</Card>
65+
<Card title="每行列表手风琴样式">
66+
<Accordion sections={contents} accordionStyle={{ backgroundColor: '#3578e5' }} />
67+
</Card>
68+
<Card title="展开手风琴内容样式">
69+
<Accordion sections={contents} contentStyle={{ backgroundColor: '#FFD21D' }} />
70+
</Card>
71+
</Body>
72+
<Footer />
73+
</Layout>
74+
</Container>
75+
);
76+
}
77+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Accordion 手风琴组件
2+
---
3+
可以折叠/展开的内容区域。
4+
5+
### 基础示例
6+
7+
```jsx mdx:preview&background=#bebebe29
8+
import React,{ Component } from "react"
9+
import { View, Text,Image,Card } from 'react-native';
10+
import { Accordion } from '@uiw/react-native';
11+
12+
const contents = [
13+
{
14+
title: <Text>Section 1</Text>,
15+
content: (
16+
<View>
17+
<Text>Content of section 1</Text>
18+
<Image source={{ uri: 'https://wx3.sinaimg.cn/mw690/4718260ely1gt2cg7t5udj23dw1wkhdu.jpg' }} style={{ height: 180 }} />
19+
</View>
20+
),
21+
},
22+
{
23+
title: <Text>Section 2</Text>,
24+
content: (
25+
<View>
26+
<Text>Content of section 2</Text>
27+
<Image source={{ uri: 'https://wx1.sinaimg.cn/mw690/4718260ely1gt2cg5r9zij22yo1o0x6p.jpg' }} style={{ height: 180 }} />
28+
</View>
29+
),
30+
},
31+
{
32+
title: <Text>Section 3</Text>,
33+
content: (
34+
<View>
35+
<Text>Content of section 3</Text>
36+
<Image source={{ uri: 'https://iknow-pic.cdn.bcebos.com/810a19d8bc3eb135828572d2ab1ea8d3fd1f441d' }} style={{ height: 180 }} />
37+
</View>
38+
),
39+
},
40+
];
41+
42+
function Demo() {
43+
return (
44+
<View style={{ marginTop: 50 }}>
45+
<Accordion sections={contents} />
46+
</View>
47+
);
48+
}
49+
```
50+
51+
### Props
52+
53+
| 参数 | 说明 | 类型 | 默认值 |
54+
|------|------|-----|------|
55+
| `sections` | 自定义手风琴列表,通过`title`参数设置标题,通过`content`参数设置展示内容,通过`isOnPress`参数设置是否禁用 | JSX.Element | - |
56+
| `isMultiple` | 是否同时展示多个内容| boolean | true |
57+
| `accordionStyle` | 手风琴每行列表样式 | ViewStyle | - |
58+
| `contentStyle` | 点击展开内容样式 | ViewStyle | - |
59+
| `iconShow` | 是否展示图标 | boolean | true |
60+
| `iconSize` | 设置图标尺寸 | number | - |
61+
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import React, { FC, useState, useRef } from 'react';
2+
import { StyleSheet, View, TouchableOpacity, StyleProp, ViewStyle, LayoutAnimation, Animated } from 'react-native';
3+
import { Theme } from '../theme';
4+
import { useTheme } from '@shopify/restyle';
5+
import Icon from '../Icon';
6+
7+
interface AccordionProps {
8+
/** 自定义手风琴列表*/
9+
sections: {
10+
/** 列表标题内容*/
11+
title: JSX.Element;
12+
/** 展开内容*/
13+
content: JSX.Element;
14+
/** 是否可以点击,默认可以点击*/
15+
isOnPress?: boolean;
16+
}[];
17+
/** 是否展示多个,默认展示多个*/
18+
isMultiple?: boolean;
19+
/** 手风琴每行列表样式 */
20+
accordionStyle?: StyleProp<ViewStyle>;
21+
/** 点击展开内容样式 */
22+
contentStyle?: StyleProp<ViewStyle>;
23+
/** 是否展示图标 */
24+
iconShow?: boolean;
25+
/** 图标源 */
26+
customIcon?: string | JSX.Element;
27+
/** 图标尺寸 */
28+
iconSize?: number;
29+
}
30+
31+
const Accordion: FC<AccordionProps> = (props) => {
32+
const { sections, isMultiple = true, iconShow = true, iconSize = 18, accordionStyle, contentStyle } = props;
33+
const [activeIndex, setActiveIndex] = useState<number[] | number>(isMultiple ? [] : -1);
34+
const theme = useTheme<Theme>();
35+
const styles = createStyles({
36+
bgColor: theme.colors.mask,
37+
headerColor: theme.colors.background,
38+
borderColor: theme.colors.border,
39+
});
40+
const animatedController = useRef(new Animated.Value(0)).current;
41+
42+
const onPress = (index: number | never) => {
43+
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
44+
if (isMultiple) {
45+
const currentIndex = Array.isArray(activeIndex) ? activeIndex.indexOf(index) : -1;
46+
if (currentIndex > -1) {
47+
const newActiveIndex = Array.isArray(activeIndex) ? [...activeIndex] : [];
48+
if (currentIndex > -1) {
49+
newActiveIndex.splice(currentIndex, 1);
50+
}
51+
setActiveIndex(newActiveIndex);
52+
} else {
53+
setActiveIndex(Array.isArray(activeIndex) ? [...activeIndex, index] : [index]);
54+
}
55+
} else {
56+
setActiveIndex(activeIndex === index ? -1 : index);
57+
}
58+
Animated.timing(animatedController, {
59+
toValue: activeIndex === index ? 0 : 1,
60+
duration: 500,
61+
useNativeDriver: true,
62+
}).start();
63+
};
64+
65+
const rotateZ = animatedController.interpolate({
66+
inputRange: [0, 1],
67+
outputRange: ['0deg', '90deg'],
68+
});
69+
70+
return (
71+
<View>
72+
{sections.map((item, index) => (
73+
<View key={index}>
74+
<TouchableOpacity disabled={item?.isOnPress || false} activeOpacity={0.8} onPress={() => onPress(index)} style={[styles.header, accordionStyle]}>
75+
<View style={styles.titleBy} key={index}>
76+
{item.title}
77+
{iconShow &&
78+
<Animated.View style={{ transform: [{ rotateZ: activeIndex === index || (Array.isArray(activeIndex) && activeIndex.indexOf(index) > -1) ? rotateZ : '0deg' }] }}>
79+
<Icon name="right" size={iconSize} color={theme.colors.border} />
80+
</Animated.View>}
81+
</View>
82+
</TouchableOpacity>
83+
{(isMultiple && Array.isArray(activeIndex) && activeIndex.indexOf(index) > -1 || !isMultiple && activeIndex === index) && <View
84+
style={[styles.content, contentStyle]}>
85+
{item.content}
86+
</View>}
87+
</View>
88+
))}
89+
</View>
90+
)
91+
}
92+
93+
type CreStyle = {
94+
bgColor: string;
95+
headerColor: string;
96+
borderColor: string;
97+
};
98+
99+
function createStyles({ bgColor, borderColor, headerColor }: CreStyle) {
100+
return StyleSheet.create({
101+
titleBy: {
102+
flexDirection: 'row',
103+
justifyContent: 'space-between',
104+
},
105+
header: {
106+
borderBottomWidth: 1,
107+
borderBottomColor: borderColor,
108+
padding: 15,
109+
backgroundColor: headerColor,
110+
},
111+
content: {
112+
padding: 15,
113+
backgroundColor: bgColor,
114+
},
115+
});
116+
}
117+
118+
export default Accordion;
119+

packages/core/src/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ export { default as ImageViewer } from './ImageViewer';
125125
export * from './ImageViewer';
126126
export { default as Form } from './Form';
127127
export * from './Form';
128-
128+
export { default as Accordion } from './Accordion';
129+
export * from './Accordion';
129130
/**
130131
* Typography
131132
*/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Preview from 'src/component/Preview';
2+
import md from '@uiw/react-native/README.md';
3+
4+
const Demo = () => <Preview {...md} path="/packages/core/src/Accordion/README.md" />;
5+
6+
export default Demo;

website/src/routes/menus.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const componentMenus: MenuData[] = [
2424
{ path: '/components/swipeaction', name: 'SwipeAction 滑动操作组件' },
2525
{ path: '/components/expandablesection', name: 'ExpandableSection 展开缩放组件' },
2626
{ path: '/components/cardcollapse', name: 'CardCollapse 可折叠卡片列表' },
27+
{ path: '/components/accordion', name: 'Accordion 可折叠/展开的内容区域' },
2728
{ divider: true, name: 'Data Entry' },
2829
{ path: '/components/form', name: 'Form 表单 🚧' },
2930
{ path: '/components/checkbox', name: 'CheckBox 复选框' },

0 commit comments

Comments
 (0)