9-9 自定义头部渐变背景

233 阅读2分钟

在本章中,我们将学习如何为顶部标签导航器添加自定义渐变背景,并实现根据滚动位置动态改变背景色的效果。

一、隐藏首页标题栏

我们将在首页标签页时隐藏顶部标题栏。

1. 更新 HomeTabs.tsx

navigator/HomeTabs.tsx 中,使用 headerTransparent 属性隐藏标题栏:

<Tab.Navigator
  tabBar={(props) => <TopTabBarWrapper {...props} />}
  sceneContainerStyle={styles.sceneContainer}
>
  ...
</Tab.Navigator>;

const styles = StyleSheet.create({
  sceneContainer: {
    backgroundColor: 'transparent',
  },
});

2. 更新导航逻辑

src/navigator/index.tsx 中,设置标题栏的显示状态:

function getHeaderTitle(routeName: string) {
  switch (routeName) {
    case 'HomeTabs':
      return '';
    case 'Listen':
      return '我听';
    case 'Found':
      return '发现';
    case 'Account':
      return '账户';
    default:
      return '首页';
  }
}

class App extends React.Component {
  setOptions = () => {
    const { navigation, route } = this.props;
    const routeName = route.state
      ? route.state.routes[route.state.index].name
      : route.params
      ? route.params.screen
      : 'HomeTabs';

    navigation.setOptions({
      headerTitle: getHeaderTitle(routeName),
      headerTransparent: routeName === 'HomeTabs',
    });
  };

  componentDidMount() {
    this.setOptions();
  }

  componentDidUpdate() {
    this.setOptions();
  }

  render() {
    return (
      <Navigator />
    );
  }
}

二、自定义顶部标签栏

1. 引入 MaterialTopTabBar

pages/views/TopTabBarWrapper.tsx 中,自定义顶部标签栏:

import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Platform } from 'react-native';
import { MaterialTopTabBarProps } from '@react-navigation/material-top-tabs';
import LinearGradient from 'react-native-linear-gradient';
import { getStatusBarHeight } from 'react-native-iphone-x-helper';

interface IProps extends MaterialTopTabBarProps {
  gradientVisible: boolean;
  linearColors: string[];
}

const TopTabBarWrapper: React.FC<IProps> = (props) => {
  const { gradientVisible, linearColors } = props;

  return (
    <View style={styles.container}>
      <LinearGradient
        colors={gradientVisible ? linearColors : ['#fff', '#fff']}
        style={styles.gradient}
      />
      <View style={styles.topTabBarView}>
        <MaterialTopTabBar {...props} labelStyle={styles.labelStyle} />
        <TouchableOpacity style={styles.categoryBtn}>
          <Text style={styles.text}>分类</Text>
        </TouchableOpacity>
      </View>
      <View style={styles.bottom}>
        <TouchableOpacity style={styles.searchBtn}>
          <Text style={styles.text}>搜索按钮</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.historyBtn}>
          <Text style={styles.text}>历史记录</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    paddingTop: getStatusBarHeight(),
  },
  gradient: {
    ...StyleSheet.absoluteFillObject,
    height: 260,
  },
  topTabBarView: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  labelStyle: {
    fontWeight: 'bold',
  },
  categoryBtn: {
    paddingHorizontal: 8,
    borderLeftColor: '#eee',
    borderLeftWidth: StyleSheet.hairlineWidth,
  },
  bottom: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    paddingVertical: 7,
    paddingHorizontal: 15,
  },
  searchBtn: {
    flex: 1,
    justifyContent: 'center',
    paddingLeft: 12,
    height: 30,
    borderRadius: 15,
    backgroundColor: 'rgba(0, 0, 0, 0.1)',
  },
  historyBtn: {
    marginLeft: 24,
  },
  text: {
    color: '#fff',
  },
});

export default TopTabBarWrapper;

2. 集成渐变背景

pages/Home/Carousel.tsx 中,将轮播图切换的索引保存到 Dva 仓库:

export interface HomeModelState {
  carousels: ICarousel[];
  activeCarouselIndex: number;
}

export interface HomeModelType {
  namespace: 'home';
  state: HomeModelState;
  effects: {
    fetchCarousels: Effect;
  };
  reducers: {
    setState: Reducer<HomeModelState>;
  };
}

const homeModel: HomeModelType = {
  namespace: 'home',
  state: {
    carousels: [],
    activeCarouselIndex: 0,
  },
  effects: {
    *fetchCarousels({ payload }, { call, put }) {
      const { data } = yield call(axios.get, CAROUSEL_URL);
      yield put({
        type: 'setState',
        payload: {
          carousels: data,
          activeCarouselIndex: 0,
        },
      });
    },
  },
  reducers: {
    setState(state, { payload }) {
      return {
        ...state,
        ...payload,
      };
    },
  },
};

pages/Home/Carousel.tsx 中,将轮播图的索引保存到 Dva 仓库:

<Carousel
  data={carouselList}
  renderItem={this.renderItem}
  sliderWidth={sliderWidth}
  itemWidth={itemWidth}
  hasParallaxImages
  loop
  autoPlay
  onSnapToItem={(index) => this.setState({ activeCarouselIndex: index })}
/>

3. 动态渐变背景

pages/views/TopTabBarWrapper.tsx 中,根据轮播图的索引动态更新渐变背景:

const TopTabBarWrapper: React.FC<IProps> = (props) => {
  const { gradientVisible, linearColors } = props;

  return (
    <View style={styles.container}>
      <LinearGradient
        colors={gradientVisible ? linearColors : ['#fff', '#fff']}
        style={styles.gradient}
      />
      ...
    </View>
  );
};

三、总结

在本章中,我们为顶部标签导航器添加了自定义渐变背景,并实现了根据滚动位置动态改变背景色的效果。这包括以下步骤:

  1. 隐藏首页标题栏。
  2. 自定义顶部标签栏,添加渐变背景和额外的交互按钮。
  3. 使用 Dva 管理状态,根据轮播图的切换动态更新渐变颜色。
  4. 根据滚动位置动态显示或隐藏渐变背景。

下一章,我们将继续学习更多高级功能。