Skip to content

Commit fcd770d

Browse files
committed
feat(ScreenRoot):新增ScreenRoot组件
1 parent ed876de commit fcd770d

File tree

5 files changed

+329
-0
lines changed

5 files changed

+329
-0
lines changed

example/examples/src/routes.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,4 +443,12 @@ export const stackPageData: Routes[] = [
443443
description: 'DatePicker 年-月-日-时-分',
444444
},
445445
},
446+
{
447+
name: 'ScreenRoot',
448+
component: require('./routes/ScreenRoot').default,
449+
params: {
450+
title: 'ScreenRoot 屏幕头部导航',
451+
description: 'ScreenRoot',
452+
},
453+
},
446454
];
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
import {ScreenRoot} from '@uiw/react-native';
3+
import {Text, TouchableOpacity} from 'react-native';
4+
import {ComProps} from '../../routes';
5+
6+
export interface ScreenRootProps extends ComProps {}
7+
8+
export default class Demo extends React.Component<ScreenRootProps> {
9+
render() {
10+
const HeaderRight = () => (
11+
<TouchableOpacity onPress={() => {}}>
12+
<Text
13+
style={{
14+
color: '#333',
15+
fontWeight: '600',
16+
fontSize: 14,
17+
lineHeight: 44,
18+
}}>
19+
查看详情
20+
</Text>
21+
</TouchableOpacity>
22+
);
23+
return (
24+
<ScreenRoot
25+
title="ScreenRoot"
26+
headerRight={HeaderRight()}
27+
onBack={() => this.props.navigation.goBack()}
28+
/>
29+
);
30+
}
31+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
ScreenRoot 应用状态栏
2+
---
3+
4+
控制应用状态栏的组件
5+
6+
### 基础示例
7+
8+
```jsx
9+
import React from 'react';
10+
import { ScreenRoot } from '@uiw/react-native';
11+
import { Text,TouchableOpacity } from 'react-native'
12+
import { ComProps } from '../../routes';
13+
14+
export interface ScreenRootProps extends ComProps { }
15+
16+
export default class Demo extends React.Component<ScreenRootProps> {
17+
render() {
18+
const HeaderRight = () => (
19+
<TouchableOpacity onPress={()=>{}}>
20+
<Text style={{ color: '#333', fontWeight:"600",fontSize: 14, lineHeight: 44 }}>
21+
查看详情
22+
</Text>
23+
</TouchableOpacity>
24+
)
25+
return (
26+
<ScreenRoot
27+
title="ScreenRoot"
28+
headerRight={HeaderRight()}
29+
onBack={()=>this.props.navigation.goBack()}
30+
/>
31+
);
32+
}
33+
}
34+
```
35+
36+
### Props
37+
组件继承react-native-gesture-handler[`Swipeable`](https://docs.swmansion.com/react-native-gesture-handler/docs/api/components/swipeable)
38+
```tsx
39+
export interface ScreenRootProps {
40+
/**
41+
* 无需头部导航栏
42+
*/
43+
noHeader?: boolean
44+
/**
45+
* modal根结点样式,有时需要
46+
*/
47+
rootStyle?: StyleProp<any>;
48+
/**
49+
* 导航栏中间标题,支持字符串和ReactNode
50+
*/
51+
title?: string | React.ReactNode;
52+
// 导航栏左侧显示
53+
headerLeft?: React.ReactNode;
54+
// 导航栏右侧显示
55+
headerRight?: React.ReactNode;
56+
// 导航栏整体样式
57+
headerStyle?: StyleProp<any>;
58+
// 导航栏右侧显示样式
59+
headerRightStyle?: StyleProp<any>;
60+
// 页面内容样式
61+
containerStyle?: StyleProp<any>;
62+
loading?: boolean;
63+
// 默认左侧图标点击事件
64+
onBack?: () => void
65+
// 图标颜色
66+
iconColor?: string
67+
// screen背景色
68+
screenBackgroundColor?: string
69+
// modal背景色
70+
modalBackgroundColor?: string
71+
// 页面导航类型,screen modal
72+
pageType?: 'screen' | 'modal',
73+
children?: React.ReactNode;
74+
barStyle?: "default" | "light-content" | "dark-content";
75+
}
76+
```
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
import React from 'react';
2+
import {
3+
StyleSheet,
4+
View,
5+
Text,
6+
Pressable,
7+
SafeAreaView,
8+
ActivityIndicator,
9+
Platform,
10+
StatusBar,
11+
StyleProp,
12+
} from 'react-native';
13+
import Icon from '../Icon';
14+
import MaskLayer from '../MaskLayer';
15+
16+
export interface ScreenRootProps {
17+
/**
18+
* 无需头部导航栏
19+
*/
20+
noHeader?: boolean;
21+
/**
22+
* modal根结点样式,有时需要
23+
*/
24+
rootStyle?: StyleProp<any>;
25+
/**
26+
* 导航栏中间标题,支持字符串和ReactNode
27+
*/
28+
title?: string | React.ReactNode;
29+
// 导航栏左侧显示
30+
headerLeft?: React.ReactNode;
31+
// 导航栏右侧显示
32+
headerRight?: React.ReactNode;
33+
// 导航栏整体样式
34+
headerStyle?: StyleProp<any>;
35+
// 导航栏右侧显示样式
36+
headerRightStyle?: StyleProp<any>;
37+
// 页面内容样式
38+
containerStyle?: StyleProp<any>;
39+
loading?: boolean;
40+
// 默认左侧图标点击事件
41+
onBack?: () => void;
42+
// 图标颜色
43+
iconColor?: string;
44+
// screen背景色
45+
screenBackgroundColor?: string;
46+
// modal背景色
47+
modalBackgroundColor?: string;
48+
// 页面导航类型,screen modal
49+
pageType?: 'screen' | 'modal';
50+
children?: React.ReactNode;
51+
barStyle?: 'default' | 'light-content' | 'dark-content';
52+
}
53+
54+
const ScreenRoot = (props: ScreenRootProps) => {
55+
const {
56+
// 无需头部导航栏
57+
noHeader = false,
58+
// modal根结点样式,有时需要
59+
rootStyle = {},
60+
// 导航栏中间标题,支持字符串和ReactNode
61+
title = '',
62+
// 导航栏左侧显示
63+
headerLeft = null,
64+
// 导航栏右侧显示
65+
headerRight = null,
66+
// 导航栏整体样式
67+
headerStyle = {},
68+
// 页面内容样式
69+
containerStyle = {},
70+
loading = false,
71+
// 默认左侧图标点击事件
72+
onBack = null,
73+
iconColor = '#333333',
74+
screenBackgroundColor = '#f9f9f9',
75+
modalBackgroundColor = '#fff',
76+
// 页面导航类型,screen modal
77+
pageType = 'screen',
78+
children = null,
79+
// 状态栏主题 default light-content dark-content
80+
barStyle = 'dark-content',
81+
headerRightStyle = {},
82+
} = props;
83+
84+
const isScreen = pageType === 'screen';
85+
const isIOS = Platform.OS === 'ios';
86+
87+
const bgc = isScreen ? screenBackgroundColor : modalBackgroundColor;
88+
89+
// 页面左侧
90+
const pageHeaderLeft = (
91+
<Pressable style={styles.headerLeft} onPress={() => onBack && onBack()}>
92+
<Icon
93+
xml={`
94+
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="18" viewBox="0 0 11 18">
95+
<polyline fill="none" stroke="${iconColor}" stroke-width="2" points="26.871 58 19 65.935 26.871 73.935" transform="translate(-17 -57)"/>
96+
</svg>
97+
`}
98+
size={18}
99+
/>
100+
</Pressable>
101+
);
102+
103+
// modal弹框左侧
104+
const modalHeaderLeft = (
105+
<Pressable style={styles.headerLeft} onPress={() => onBack && onBack()}>
106+
<Icon name="close" size={16} color={iconColor} />
107+
</Pressable>
108+
);
109+
110+
const renderHeader = () => {
111+
let centerContainer = null;
112+
if (typeof title === 'string') {
113+
centerContainer = (
114+
<Text style={styles.title} numberOfLines={1}>
115+
{title}
116+
</Text>
117+
);
118+
} else {
119+
centerContainer = title;
120+
}
121+
if (!noHeader) {
122+
return (
123+
<View
124+
style={[
125+
styles.header,
126+
{
127+
backgroundColor: bgc,
128+
},
129+
isScreen ? { elevation: 4 } : {},
130+
isIOS ? styles.iosHeader : '',
131+
headerStyle,
132+
]}
133+
>
134+
<View style={styles.leftContainer}>
135+
{headerLeft ? headerLeft : isScreen ? pageHeaderLeft : modalHeaderLeft}
136+
</View>
137+
<View style={styles.centerContainer}>{centerContainer}</View>
138+
<View style={[styles.rightContainer, headerRightStyle]}>{headerRight}</View>
139+
</View>
140+
);
141+
}
142+
return null;
143+
};
144+
145+
return (
146+
<SafeAreaView style={[isScreen ? {} : { backgroundColor: modalBackgroundColor, ...rootStyle }, { flex: 1 }]}>
147+
<StatusBar barStyle={barStyle} backgroundColor="red" translucent={true} animated={true} />
148+
{loading && (
149+
<MaskLayer visible={loading} opacity={0.3}>
150+
<ActivityIndicator color="#333" size="large" style={{ marginTop: 300 }} />
151+
</MaskLayer>
152+
)}
153+
{renderHeader()}
154+
<View
155+
style={[
156+
{
157+
flex: 1,
158+
backgroundColor: bgc,
159+
},
160+
containerStyle,
161+
]}
162+
>
163+
{children}
164+
</View>
165+
</SafeAreaView>
166+
);
167+
};
168+
169+
const styles = StyleSheet.create({
170+
modalRootStyle: {
171+
backgroundColor: '#fff',
172+
},
173+
header: {
174+
height: 66,
175+
flexDirection: 'row',
176+
alignItems: 'center',
177+
paddingTop: 22,
178+
},
179+
iosHeader: {
180+
height: 44,
181+
paddingTop: 0,
182+
},
183+
leftContainer: {
184+
flex: 1,
185+
width: 60,
186+
paddingLeft: 10,
187+
flexDirection: 'row',
188+
},
189+
headerLeft: {
190+
flex: 1,
191+
justifyContent: 'center',
192+
},
193+
centerContainer: {
194+
flex: 4,
195+
justifyContent: 'center',
196+
alignItems: 'center',
197+
},
198+
title: {
199+
color: '#333',
200+
fontSize: 16,
201+
fontWeight: '600',
202+
},
203+
rightContainer: {
204+
flex: 1,
205+
width: 60,
206+
paddingRight: 10,
207+
flexDirection: 'row',
208+
},
209+
});
210+
211+
export default ScreenRoot;

packages/core/src/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ export * from './Picker';
106106
export { default as DatePicker } from './DatePicker';
107107
export * from './DatePicker';
108108

109+
export { default as ScreenRoot } from './ScreenRoot';
110+
export * from './ScreenRoot';
111+
109112
/**
110113
* Typography
111114
*/

0 commit comments

Comments
 (0)