Skip to content

Commit daa50bb

Browse files
authored
Merge pull request #14 from bamlab/fix-button
Add a touchableFixedForeground
2 parents 8a7e0d1 + 63d4f04 commit daa50bb

File tree

12 files changed

+235
-115
lines changed

12 files changed

+235
-115
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ The `HeaderImageScrollView` handle also the following props. None is required :
6363
| Property | Type | Default | Description |
6464
| -------- | ---- | ------- | ----------- |
6565
| `renderForeground` | `function` | Empty view | Function which return the component to use at foreground. The component is render in front of the header and scroll with the ScrollView. It can return a title for example.|
66-
| `renderFixedForeground` | `function` | Empty view | Function which return the component to use as fixed foreground. The component is displayed with the header but not affected by the overlay. Perfect for navbar content.|
66+
| `renderFixedForeground` | `function` | Empty view | Function which return the component to use as fixed foreground. The component is displayed with the header but not affected by the overlay.|
6767
| `foregroundParallaxRatio` | `number` | `1` | Ration for parallax effect of foreground when scrolling. If 2, the header goes up two times faster than the scroll |
6868
| `fadeOutForeground` | `bool` | `false` | If set, add a fade out effect on the foreground when scroll up |
69+
| `renderFixedForeground` | `function` | Empty view | Same as `renderFixedForeground` but allow to use touchable in it. [*Can cause performances issues on Android*](https://github.com/bamlab/react-native-image-header-scroll-view/issues/6)|
6970

7071

7172
### TriggeringView

example/Pages/Avignon.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React from 'react';
2+
import { StyleSheet, Text, Image, TouchableOpacity, View, Dimensions } from 'react-native';
3+
import { NavigationBar } from '@exponent/ex-navigation';
4+
5+
import HeaderImageScrollView, { TriggeringView } from 'react-native-image-header-scroll-view';
6+
7+
const MIN_HEIGHT = NavigationBar.DEFAULT_HEIGHT;
8+
const MAX_HEIGHT = 200;
9+
10+
class BasicUsage extends React.Component {
11+
render() {
12+
return (
13+
<View style={styles.container}>
14+
<HeaderImageScrollView
15+
maxHeight={MAX_HEIGHT}
16+
minHeight={MIN_HEIGHT}
17+
minOverlayOpacity={0.4}
18+
renderHeader={() => (
19+
<Image source={require('../assets/avignon.jpg')} style={styles.image} />
20+
)}
21+
renderTouchableFixedForeground={() => (
22+
<View style={{ height: MAX_HEIGHT, justifyContent: 'center', alignItems: 'center' }}>
23+
<TouchableOpacity onPress={() => console.log('tap!!')} style={styles.button}>
24+
<Text style={styles.buttonText}>Discover Avignon now!</Text>
25+
</TouchableOpacity>
26+
</View>
27+
)}
28+
>
29+
<View style={{ height: 1000 }}>
30+
<TriggeringView onHide={() => console.log('text hidden')}>
31+
<TouchableOpacity onPress={() => console.log('tap!!')} style={styles.button}>
32+
<Text style={styles.buttonText}>Discover Another city</Text>
33+
</TouchableOpacity>
34+
</TriggeringView>
35+
</View>
36+
</HeaderImageScrollView>
37+
</View>
38+
);
39+
}
40+
}
41+
42+
const styles = StyleSheet.create({
43+
container: {
44+
marginTop: -MIN_HEIGHT,
45+
flex: 1,
46+
},
47+
image: {
48+
height: MAX_HEIGHT,
49+
width: Dimensions.get('window').width,
50+
},
51+
button: {
52+
borderWidth: 1,
53+
borderRadius: 8,
54+
paddingVertical: 10,
55+
paddingHorizontal: 30,
56+
borderColor: 'white',
57+
backgroundColor: '#00000066',
58+
},
59+
buttonText: {
60+
color: 'white',
61+
backgroundColor: 'transparent',
62+
},
63+
});
64+
65+
BasicUsage.route = {
66+
navigationBar: {
67+
tintColor: 'white',
68+
backgroundColor: 'transparent',
69+
borderBottomWidth: 0,
70+
statusBarHeight: 0,
71+
elevation: 0,
72+
},
73+
};
74+
75+
export default BasicUsage;

example/Pages/Menu.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import React from 'react';
2-
import { StyleSheet, Text, Image, TouchableOpacity, StatusBar, View, Dimensions } from 'react-native';
2+
import {
3+
StyleSheet,
4+
Text,
5+
Image,
6+
TouchableOpacity,
7+
StatusBar,
8+
View,
9+
ScrollView,
10+
Dimensions,
11+
} from 'react-native';
312
import { withNavigation } from '@exponent/ex-navigation';
413
import { Router } from '../main';
514

@@ -8,6 +17,8 @@ import tvShowContent from '../assets/tvShowContent';
817
const styles = StyleSheet.create({
918
page: {
1019
flex: 1,
20+
},
21+
pageContent: {
1122
alignItems: 'stretch',
1223
padding: 30,
1324
},
@@ -29,20 +40,22 @@ const styles = StyleSheet.create({
2940
alignSelf: 'stretch',
3041
justifyContent: 'center',
3142
alignItems: 'center',
32-
}
43+
},
3344
});
3445

35-
@withNavigation
36-
class Button extends React.Component {
46+
@withNavigation class Button extends React.Component {
3747
render() {
3848
const props = this.props;
3949
return (
40-
<TouchableOpacity activeOpacity={0.7} onPress={() => {
41-
this.props.navigator.push(Router.getRoute(props.target));
42-
}}>
50+
<TouchableOpacity
51+
activeOpacity={0.7}
52+
onPress={() => {
53+
this.props.navigator.push(Router.getRoute(props.target));
54+
}}
55+
>
4356
<Image style={styles.button} source={props.image}>
4457
<View style={styles.overlay}>
45-
<Text style={styles.buttonText}>{ props.text }</Text>
58+
<Text style={styles.buttonText}>{props.text}</Text>
4659
</View>
4760
</Image>
4861
</TouchableOpacity>
@@ -51,12 +64,13 @@ class Button extends React.Component {
5164
}
5265

5366
const Menu = () => (
54-
<View style={styles.page}>
67+
<ScrollView style={styles.page} contentContainerStyle={styles.pageContent}>
5568
<StatusBar />
5669
<Button image={require('../assets/NZ.jpg')} text="BasicUsage" target="basicUsage" />
5770
<Button image={tvShowContent.image} text="TV Show" target="tvShow" />
5871
<Button image={require('../assets/cutecat.jpg')} text="Cute cat" target="colors" />
59-
</View>
72+
<Button image={require('../assets/avignon.jpg')} text="Forms and buttons" target="avignon" />
73+
</ScrollView>
6074
);
6175

6276
Menu.route = {

example/Pages/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { default as Menu } from './Menu';
22
export { default as TvShow } from './TvShow';
33
export { default as BasicUsage } from './BasicUsage';
44
export { default as ColorsPage } from './Colors';
5+
export { default as Avignon } from './Avignon';

example/assets/avignon.jpg

105 KB
Loading

example/main.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
11
import React from 'react';
2-
import {
3-
AppRegistry,
4-
Text,
5-
View,
6-
} from 'react-native';
2+
import { AppRegistry, Text, View } from 'react-native';
73

8-
import {
9-
createRouter,
10-
NavigationProvider,
11-
StackNavigation,
12-
} from '@exponent/ex-navigation';
4+
import { createRouter, NavigationProvider, StackNavigation } from '@exponent/ex-navigation';
135

14-
import { Menu, TvShow, BasicUsage, ColorsPage } from './Pages';
6+
import { Menu, TvShow, BasicUsage, ColorsPage, Avignon } from './Pages';
157

168
export const Router = createRouter(() => ({
179
menu: () => Menu,
1810
tvShow: () => TvShow,
1911
basicUsage: () => BasicUsage,
2012
colors: () => ColorsPage,
13+
avignon: () => Avignon,
2114
}));
2215

2316
class App extends React.Component {

example/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "imageHeaderScrollView",
3-
"version": "0.5.1",
3+
"version": "0.6.0",
44
"private": true,
55
"scripts": {
66
"start": "node node_modules/react-native/local-cli/cli.js start"
@@ -11,7 +11,7 @@
1111
"react": "~15.4.1",
1212
"react-native": "0.42.0",
1313
"react-native-animatable": "^1.1.0",
14-
"react-native-image-header-scroll-view": "^0.5.1"
14+
"react-native-image-header-scroll-view": "^0.6.0"
1515
},
1616
"devDependencies": {
1717
"babel-jest": "19.0.0",

example/yarn.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,9 +2571,9 @@ react-native-drawer-layout@^1.0.0:
25712571
autobind-decorator "^1.3.2"
25722572
react-native-dismiss-keyboard "1.0.0"
25732573

2574-
react-native-image-header-scroll-view@^0.5.1:
2575-
version "0.5.1"
2576-
resolved "https://registry.yarnpkg.com/react-native-image-header-scroll-view/-/react-native-image-header-scroll-view-0.5.1.tgz#d2ab403c3aa220e502760c39a452bac47e38e155"
2574+
react-native-image-header-scroll-view@^0.6.0:
2575+
version "0.6.0"
2576+
resolved "https://registry.yarnpkg.com/react-native-image-header-scroll-view/-/react-native-image-header-scroll-view-0.6.0.tgz#3cf08955dd3615b5852824b993d9ad60ba1f5bfc"
25772577
dependencies:
25782578
lodash "^4.17.4"
25792579

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-image-header-scroll-view",
3-
"version": "0.5.1",
3+
"version": "0.6.0",
44
"description": "ScrollView with an image in header which become a navbar",
55
"main": "src/index.js",
66
"scripts": {

src/ImageHeaderScrollView.js

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import React, { Component } from 'react';
2-
import {
3-
Animated,
4-
ScrollView,
5-
StyleSheet,
6-
View,
7-
} from 'react-native';
2+
import { Animated, ScrollView, StyleSheet, View } from 'react-native';
83
import _ from 'lodash';
94

105
const SCROLLVIEW_REF = 'ScrollView';
@@ -40,9 +35,11 @@ const styles = StyleSheet.create({
4035
bottom: 0,
4136
zIndex: 101,
4237
},
38+
touchableFixedForeground: {
39+
zIndex: 102,
40+
},
4341
});
4442

45-
4643
class ImageHeaderScrollView extends Component {
4744
constructor(props) {
4845
super(props);
@@ -79,7 +76,7 @@ class ImageHeaderScrollView extends Component {
7976
this.getScrollResponder().scrollTo(...args);
8077
}
8178

82-
interpolateOnImageHeight(outputRange) {
79+
interpolateOnImageHeight(outputRange: Array<number>) {
8380
const headerScrollDistance = this.props.maxHeight - this.props.minHeight;
8481
return this.state.scrollY.interpolate({
8582
inputRange: [0, headerScrollDistance],
@@ -112,11 +109,11 @@ class ImageHeaderScrollView extends Component {
112109

113110
return (
114111
<Animated.View style={[styles.header, headerTransformStyle]}>
112+
{this.props.renderHeader(this.state.scrollY)}
115113
<Animated.View style={overlayStyle} />
116114
<View style={styles.fixedForeground}>
117-
{ this.props.renderFixedForeground(this.state.scrollY) }
115+
{this.props.renderFixedForeground(this.state.scrollY)}
118116
</View>
119-
{ this.props.renderHeader(this.state.scrollY) }
120117
</Animated.View>
121118
);
122119
}
@@ -136,7 +133,32 @@ class ImageHeaderScrollView extends Component {
136133
};
137134
return (
138135
<Animated.View style={[styles.header, headerTransformStyle]}>
139-
{ this.props.renderForeground() }
136+
{this.props.renderForeground()}
137+
</Animated.View>
138+
);
139+
}
140+
141+
renderTouchableFixedForeground() {
142+
if (!this.props.renderTouchableFixedForeground) {
143+
return <View />;
144+
}
145+
146+
const height = this.interpolateOnImageHeight([this.props.maxHeight, this.props.minHeight]);
147+
148+
const headerScale = this.state.scrollY.interpolate({
149+
inputRange: [-this.props.maxHeight, 0],
150+
outputRange: [3, 1],
151+
extrapolate: 'clamp',
152+
});
153+
154+
const headerTransformStyle = {
155+
height,
156+
transform: [{ scale: headerScale }],
157+
};
158+
159+
return (
160+
<Animated.View style={[styles.header, styles.touchableFixedForeground, headerTransformStyle]}>
161+
{this.props.renderTouchableFixedForeground(this.state.scrollY)}
140162
</Animated.View>
141163
);
142164
}
@@ -159,26 +181,29 @@ class ImageHeaderScrollView extends Component {
159181
return (
160182
<View
161183
style={styles.container}
162-
ref={(ref) => { this.container = ref; }}
184+
ref={ref => (this.container = ref)}
163185
onLayout={() => this.container.measureInWindow((x, y) => this.setState({ pageY: y }))}
164186
>
165-
{ this.renderHeader() }
187+
{this.renderHeader()}
166188
<Animated.View style={[styles.container, { transform: [{ translateY: topMargin }] }]}>
167189
<ScrollView
168-
ref={(ref) => { this[SCROLLVIEW_REF] = ref; }}
190+
ref={ref => (this[SCROLLVIEW_REF] = ref)}
169191
style={styles.container}
192+
onStartShouldSetResponder={() => false}
193+
onMoveShouldSetResponder={() => false}
170194
scrollEventThrottle={16}
171-
onScroll={Animated.event(
172-
[{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
173-
)}
195+
onScroll={Animated.event([
196+
{ nativeEvent: { contentOffset: { y: this.state.scrollY } } },
197+
])}
174198
{...scrollViewProps}
175199
>
176200
<Animated.View style={childrenContainerStyle}>
177201
{this.props.children}
178202
</Animated.View>
179203
</ScrollView>
180-
{ this.renderForeground() }
181204
</Animated.View>
205+
{this.renderTouchableFixedForeground()}
206+
{this.renderForeground()}
182207
</View>
183208
);
184209
}
@@ -197,6 +222,7 @@ ImageHeaderScrollView.propTypes = {
197222
renderFixedForeground: React.PropTypes.func,
198223
renderForeground: React.PropTypes.func,
199224
renderHeader: React.PropTypes.func,
225+
renderTouchableFixedForeground: React.PropTypes.func,
200226
...ScrollView.propTypes,
201227
};
202228

0 commit comments

Comments
 (0)