Skip to content

Commit

Permalink
Update title & opacity of title+navbar
Browse files Browse the repository at this point in the history
- Change title to accept string/component
- Added `alwaysShowTitle` & `alwaysShowNavBar` property
- Added status bar to display same color as navBarColor
- Change default `extraScrollHeight` to 30
- Change default `headerMaxHeight` to 170
  • Loading branch information
kyaroru committed Jan 28, 2019
1 parent fbbaf04 commit c2a7a50
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 71 deletions.
31 changes: 14 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,26 @@
$ npm i react-native-parallax-header --save
```
## Demo
### iPhone X or XS (Using `alwaysShowTitle={false}` & `alwaysShowNavBar={false}`)
![iPhone X](https://i.gyazo.com/24343e2127b8e479a52f4bc5853ef457.gif)

### iPhone X or XS
![iPhone X (Image)](http://g.recordit.co/iWW0MOia6i.gif)
![iPhone X (Color)](http://g.recordit.co/vDfanKwzy0.gif)
![iPhone X](https://i.gyazo.com/b24881b191ce5a69e7de14b7d0bb688e.gif)

### iPhone 8
![iPhone 8 (Image)](http://g.recordit.co/g7zcxrsKD6.gif)
![iPhone 8 (Color)](http://g.recordit.co/3JYXSvjFAM.gif)
![iPhone 8](https://i.gyazo.com/eebeff28c7df7b0233fabb9cf2a9c5dc.gif)

## Example
```jsx
import Icon from 'react-native-vector-icons/MaterialIcons';
import ReactNativeParallaxHeader from 'react-native-parallax-header';

const IS_IPHONE_X = SCREEN_HEIGHT === || SCREEN_HEIGHT === 896;
const IS_IPHONE_X = SCREEN_HEIGHT === 812 || SCREEN_HEIGHT === 896;
const STATUS_BAR_HEIGHT = Platform.OS === 'ios' ? (IS_IPHONE_X ? 44 : 20) : 0;
const HEADER_HEIGHT = Platform.OS === 'ios' ? (IS_IPHONE_X ? 88 : 64) : 45;
const HEADER_HEIGHT = Platform.OS === 'ios' ? (IS_IPHONE_X ? 88 : 64) : 64;
const NAV_BAR_HEIGHT = HEADER_HEIGHT - STATUS_BAR_HEIGHT;

const viewImages = {
const images = {
background: require('../../../img/test.jpg'),
};

Expand All @@ -53,12 +54,6 @@ const styles = StyleSheet.create({
flexDirection: 'row',
backgroundColor: Colors.transparent,
},
innerContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
margin: 10,
},
titleStyle: {
color: Colors.white,
fontWeight: 'bold',
Expand Down Expand Up @@ -90,7 +85,7 @@ render() {
navbarColor={Colors.primary}
title="Parallax Header ~"
titleStyle={styles.titleStyle}
backgroundImage={viewImages.background}
backgroundImage={images.background}
backgroundImageScale={1.2}
renderNavBar={this.renderNavBar}
renderContent={this.renderContent}
Expand All @@ -107,15 +102,17 @@ render() {
| -------- | ---- | -------- | ----------- | ------- |
| `renderNavBar` | `func` | No | This renders the nav bar component | Empty `<View />` |
| `renderContent` | `func` | **YES** | This renders the scroll view content | - |
| `headerMaxHeight` | `number` | No | This is the header maximum height | Default to `200` |
| `headerMaxHeight` | `number` | No | This is the header maximum height | Default to `170` |
| `headerMinHeight` | `number` | No | This is the header minimum height | Default to common ios & android navbar height (have support for iPhone X too :p) |
| `backgroundImage` | `image source` | No | This renders the background image of the header (**if specified, background color will not take effect**) | Default is `null` |
| `backgroundImageScale` | `number` | No | This is the image scale - either enlarge or shrink (after scrolling to bottom & exceed the headerMaxHeight) | Default is `1.5` |
| `backgroundColor` | `string` | No | This is the color of the parallax background (before scrolling up), **will not be used if `backgroundImage` is specified** | Default color is `#303F9F` |
| `extraScrollHeight` | `number` | No | This is the extra scroll height (after scrolling to bottom & exceed the headerMaxHeight) | Default is `50` |
| `extraScrollHeight` | `number` | No | This is the extra scroll height (after scrolling to bottom & exceed the headerMaxHeight) | Default is `30` |
| `navbarColor` | `string` | No | This is the background color of the navbar (after scroll up) | Default color is `#3498db` |
| `title` | `string` | No | This is the title to be display in the header | Default is empty string `‘’` |
| `title` | `any` | No | This is the title to be display in the header, can be string or component | Default to null |
| `titleStyle` | `style` | No | This is the title style to override default font size/color | Default to `color: ‘white’ `text and `fontSize: 16` |
| `scrollEventThrottle` | `number` | No | This is the scroll event throttle | Default is `16` |
| `contentContainerStyle` | `style` | No | This is the contentContainerStyle style to override default `<ScrollView>` contentContainerStyle style | Default to null |
| `contentStyle` | `style` | No | This is the inner content style to override default `<View>` style inside `<ScrollView>` component | Default to null |
| `alwaysShowTitle` | `bool` | No | This is to determine whether show or hide the title after scroll | Default to `true` |
| `alwaysShowNavBar` | `bool` | No | This is to determine whether show or hide the navBar before scroll | Default to `true` |
152 changes: 99 additions & 53 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Text,
View,
Dimensions,
StatusBar,
} from 'react-native';

const {
Expand All @@ -15,12 +16,12 @@ const {

const IS_IPHONE_X = SCREEN_HEIGHT === 812 || SCREEN_HEIGHT === 896;
const STATUS_BAR_HEIGHT = Platform.OS === 'ios' ? (IS_IPHONE_X ? 44 : 20) : 0;
const NAV_BAR_HEIGHT = Platform.OS === 'ios' ? (IS_IPHONE_X ? 88 : 64) : 45;
const NAV_BAR_HEIGHT = Platform.OS === 'ios' ? (IS_IPHONE_X ? 88 : 64) : 64;

const SCROLL_EVENT_THROTTLE = 16;
const DEFAULT_HEADER_MAX_HEIGHT = 200;
const DEFAULT_HEADER_MAX_HEIGHT = 170;
const DEFAULT_HEADER_MIN_HEIGHT = NAV_BAR_HEIGHT;
const DEFAULT_EXTRA_SCROLL_HEIGHT = 50;
const DEFAULT_EXTRA_SCROLL_HEIGHT = 30;
const DEFAULT_BACKGROUND_IMAGE_SCALE = 1.5;

const DEFAULT_NAVBAR_COLOR = '#3498db';
Expand Down Expand Up @@ -114,91 +115,77 @@ class RNParallax extends Component {
}

getHeaderHeight() {
return this.state.scrollY.interpolate({
const { scrollY } = this.state;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [this.getHeaderMaxHeight() + this.getExtraScrollHeight(), this.getHeaderMaxHeight(), this.getHeaderMinHeight()],
extrapolate: 'clamp',
});
}

getNavBarOpacity() {
return this.state.scrollY.interpolate({
const { scrollY } = this.state;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [0, 1, 1],
extrapolate: 'clamp',
});
}

getNavBarForegroundOpacity() {
const { scrollY } = this.state;
const { alwaysShowNavBar } = this.props;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [alwaysShowNavBar ? 1 : 0, alwaysShowNavBar ? 1 : 0, 1],
extrapolate: 'clamp',
});
}

getImageOpacity() {
return this.state.scrollY.interpolate({
const { scrollY } = this.state;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [1, 1, 0],
extrapolate: 'clamp',
});
}

getImageTranslate() {
return this.state.scrollY.interpolate({
const { scrollY } = this.state;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [0, 0, -50],
extrapolate: 'clamp',
});
}

getImageScale() {
return this.state.scrollY.interpolate({
const { scrollY } = this.state;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [this.getBackgroundImageScale(), 1, 1],
extrapolate: 'clamp',
});
}

getTitleTranslate() {
return this.state.scrollY.interpolate({
getTitleTranslateY() {
const { scrollY } = this.state;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [5, 0, 0],
extrapolate: 'clamp',
});
}

renderHeaderTitle() {
const { title, titleStyle } = this.props;
const titleTranslate = this.getTitleTranslate();

return (
<Animated.View
style={[
styles.headerTitle,
{
transform: [
{ translateY: titleTranslate },
],
height: this.getHeaderHeight(),
},
]}
>
<Text style={[styles.headerText, titleStyle]}>
{title}
</Text>
</Animated.View>
);
}

renderHeaderForeground() {
const { renderNavBar } = this.props;

return (
<Animated.View
style={[
styles.bar,
{
height: this.getHeaderMinHeight(),
},
]}
>
{renderNavBar()}
</Animated.View>
);
getTitleOpacity() {
const { scrollY } = this.state;
const { alwaysShowTitle } = this.props;
return scrollY.interpolate({
inputRange: this.getInputRange(),
outputRange: [1, 1, alwaysShowTitle ? 1 : 0],
extrapolate: 'clamp',
});
}

renderBackgroundImage() {
Expand Down Expand Up @@ -280,15 +267,66 @@ class RNParallax extends Component {
);
}

renderScrollView() {
const { renderContent, scrollEventThrottle, contentContainerStyle, containerStyle } = this.props;
renderHeaderTitle() {
const { title, titleStyle } = this.props;
const titleTranslateY = this.getTitleTranslateY();
const titleOpacity = this.getTitleOpacity();

return (
<Animated.View
style={[
styles.headerTitle,
{
transform: [
{ translateY: titleTranslateY },
],
height: this.getHeaderHeight(),
opacity: titleOpacity,
},
]}
>
{typeof title === 'string'
&& (
<Text style={[styles.headerText, titleStyle]}>
{title}
</Text>
)
}
{typeof title !== 'string' && title}
</Animated.View>
);
}

renderHeaderForeground() {
const { renderNavBar } = this.props;
const navBarOpacity = this.getNavBarForegroundOpacity();

return (
<Animated.View
style={[
styles.bar,
{
height: this.getHeaderMinHeight(),
opacity: navBarOpacity,
},
]}
>
{renderNavBar()}
</Animated.View>
);
}

renderScrollView() {
const {
renderContent, scrollEventThrottle, contentContainerStyle, containerStyle,
} = this.props;
const { scrollY } = this.state;
return (
<Animated.ScrollView
style={styles.scrollView}
scrollEventThrottle={scrollEventThrottle}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
)}
contentContainerStyle={contentContainerStyle}
>
Expand All @@ -300,8 +338,12 @@ class RNParallax extends Component {
}

render() {
const { navbarColor } = this.props;
return (
<View style={styles.container}>
<StatusBar
backgroundColor={navbarColor}
/>
{this.renderScrollView()}
{this.renderNavbarBackground()}
{this.renderHeaderBackground()}
Expand All @@ -318,7 +360,7 @@ RNParallax.propTypes = {
backgroundColor: PropTypes.string,
backgroundImage: PropTypes.any,
navbarColor: PropTypes.string,
title: PropTypes.string,
title: PropTypes.any,
titleStyle: PropTypes.any,
headerMaxHeight: PropTypes.number,
headerMinHeight: PropTypes.number,
Expand All @@ -327,14 +369,16 @@ RNParallax.propTypes = {
backgroundImageScale: PropTypes.number,
contentContainerStyle: PropTypes.any,
containerStyle: PropTypes.any,
alwaysShowTitle: PropTypes.bool,
alwaysShowNavBar: PropTypes.bool,
};

RNParallax.defaultProps = {
renderNavBar: () => <View />,
navbarColor: DEFAULT_NAVBAR_COLOR,
backgroundColor: DEFAULT_BACKGROUND_COLOR,
backgroundImage: null,
title: '',
title: null,
titleStyle: styles.headerText,
headerMaxHeight: DEFAULT_HEADER_MAX_HEIGHT,
headerMinHeight: DEFAULT_HEADER_MIN_HEIGHT,
Expand All @@ -343,6 +387,8 @@ RNParallax.defaultProps = {
backgroundImageScale: DEFAULT_BACKGROUND_IMAGE_SCALE,
contentContainerStyle: null,
containerStyle: null,
alwaysShowTitle: true,
alwaysShowNavBar: true,
};

export default RNParallax;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-parallax-header",
"version": "1.0.7",
"version": "1.1.0",
"description": "A react native scroll view component with Parallax header :p",
"main": "index.js",
"scripts": {
Expand Down

0 comments on commit c2a7a50

Please sign in to comment.