ReactNative实现scrollable-tab-view嵌套使用

今天自己写了个小demo,实现我们平常最常见的UI界面效果,如下图:


比较常见的是使用 react-navigation 库去实现,但是这里我用的scrollable-tab-view嵌套实现的效果,这里顶部的图标我使用的本地图标,底部图标用的是iconfont库中的图标。

这里我们创建好项目之后,接下来我们一步步来实现它。

第一步:引入相关库

 iconfont 图标库 :react-native-vector-icons
 自动链接iconfont库:react-native link react-native-vector-icons
 滑动切换控件:react-native-scrollable-tab-view

 类型检测库:prop-types

第二步:实现外层的底部tab栏

先准备好三个界面文件,我这里分别是Home.js 、Classfy.js、Person.js三个js文件,将其导入在APP.js中,再在APP.js中设置默认的底部tab

这里的图标使用的是在线iconfont库中的,如果想要查看图标的字符串对应表,可以在node_modules->glyphmaps->Ionicons.json文件查看,也可以在iconfont中用自定义图标,可参考这位前辈写的https://blog.csdn.net/f409031mn/article/details/79522129

constructor(props) {
  super(props);
  this.state = {
    tabLabels: ['首页', '分类', '我的'],
    normalIcons: ['ios-home-outline', 'ios-pricetags-outline', 'ios-person-outline'],
    selectIcons: ['ios-home', 'ios-pricetags','ios-person'],
  }
}
 
render() {
    return (
      <ScrollableTabView
        tabBarPosition='bottom'
        initialPage={0} //默认为第一页
        locked={true} //表示手指是否能拖动视图,默认为false(表示可以拖动)。设为true的话,我们只能点击Tab来切换视图。
        renderTabBar={() =>   <BottomTabBar
          tabNames={this.state.tabLabels}
          tabIconNames={this.state.normalIcons}
          selectedTabIconNames={this.state.selectIcons}/>} // 可使用自定义控件 也可以使用默认的ScrollableTabView
        tabBarBackgroundColor='#fff'
        tabBarActiveTextColor='#2c2c2c'
        tabBarInactiveTextColor='#666'
      >
        <View style={styles.container}><HomePage/></View>
        <View style={styles.container}><ClassfyPage/></View>
        <View style={styles.container}><PersonPage/></View>
      </ScrollableTabView>

    );
  }
}

此处的BottomTabBar是自己定义的组件,如下:

export default class BottomTabBar extends Component {

  static propType = {
    goToPage: PropTypes.func,
    activeTab: PropTypes.number,
    tabs: PropTypes.array,
    tabNames: PropTypes.array,
    tabIconNames: PropTypes.array,
    selectedTabIconNames: PropTypes.array
  };


  render() {
    return (
      <View style={styles.tabs}>
        {this.props.tabs.map((tab, i) => {
          let color = this.props.activeTab === i ? '#2c2c2c' : '#666';
          let bottomLinecolor = this.props.activeTab === i ? '#2c2c2c' : '#fff';
          let icon = this.props.activeTab == i ? this.props.selectedTabIconNames[i] : this.props.tabIconNames[i];
          return (
            <TouchableOpacity
              key={i}
              activeOpacity={0.8}
              style={styles.tabItem}
              onPress={() => this.props.goToPage(i)}>
                <View style={styles.tabItem}>
                  <Icon
                    size = {scaleSize(50)}
                    name={icon}
                    style={{marginTop:5}}/>
                  <Text style={{color: color, fontSize: 12, marginLeft: 3}}>
                    {this.props.tabNames[i]}
                  </Text>
                </View>
            </TouchableOpacity>
          )
        })}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#ffffff',
    marginTop: 20
  },
  tabs: {
    flexDirection: 'row',
    height: 45,
    backgroundColor: '#ffffff',
  },
  tabItem: {
    flex: 1,
    alignItems: 'center',
    flexDirection:'column',
    justifyContent:'space-between'
  },
});

到现在第一个外层界面已经出来了。

第三步:实现子页面

这里的图标使用本地图标,自己可以新建一个文件夹,将图片进行导入

// 正常展示的顶部图标
import hotNormalIcon from '../imgs/icon_hot_normal.png'
import recommendNormalIcon from '../imgs/icon_recommend_normal.png'
import videoNormalIcon from '../imgs/icon_video_normal.png'


// 选中的顶部图标
import hotSeclectIcon from '../imgs/icon_hot_select.png'
import recommendSeclectIcon from '../imgs/icon_recommend_select.png'
import videoSeclectIcon from '../imgs/icon_video_select.png'

export default class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tabLabels: ['热门', '推荐', '视频'],
      normalIcons: [hotNormalIcon,recommendNormalIcon,videoNormalIcon],
      selectIcons: [hotSeclectIcon,recommendSeclectIcon,videoSeclectIcon],
    }
  }

  render() {
    return (
      <ScrollableTabView
        initialPage={0} //默认为第一页
        locked={false} //表示手指是否能拖动视图,默认为false(表示可以拖动)。设为true的话,我们只能点击Tab来切换视图。
        renderTabBar={() =>
          <TopScrollTabItem
            tabNames={this.state.tabLabels}
            tabIconNames={this.state.normalIcons}
            selectedTabIconNames={this.state.selectIcons}/>} // 可使用自定义控件 也可以使用默认的ScrollableTabView
        tabBarBackgroundColor='#fff'
        tabBarActiveTextColor='#2c2c2c'
        tabBarInactiveTextColor='#666'
        tabBarUnderlineStyle={styles.tabBarUnderline}
      >
        <View style={styles.container}><Text>暂无数据</Text></View>
        <View style={styles.container}><Text>暂无数据</Text></View>
        <View style={styles.container}><Text>暂无数据</Text></View>
      </ScrollableTabView>

    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#eeeeee',
  },
  tabBarUnderline: {
    height: 2,
    backgroundColor: '#2c2c2c',
  },
});
上面的这个TopScrollTabItem组件和BottomTabBar组件类似,用的是本地的图标。

就样已经完成了。

代码已经放到github上去了,有兴趣的可以下载,地址:https://github.com/min476/scrollable-tab-view-demo


实现 ViewPager2+TabLayout+Fragment 实现页面切换,需要以下步骤: 1. 在 XML 布局文件中定义 ViewPager2 和 TabLayout,并将它们嵌套在一个父布局中。 ```xml <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.tabs.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="scrollable" app:tabGravity="center"/> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toBottomOf="@id/tab_layout" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> ``` 2. 创建 Fragment,并实现 ViewPager2 的适配器。 ```kotlin class MyFragmentAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) { private val fragmentList = listOf( FirstFragment(), SecondFragment(), ThirdFragment() ) override fun getItemCount() = fragmentList.size override fun createFragment(position: Int) = fragmentList[position] } ``` 3. 在 Activity 或 Fragment 中,初始化 ViewPager2 和 TabLayout,并将适配器设置给 ViewPager2。 ```kotlin val viewPager: ViewPager2 = findViewById(R.id.view_pager) val tabLayout: TabLayout = findViewById(R.id.tab_layout) val adapter = MyFragmentAdapter(this) viewPager.adapter = adapter TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = "Tab ${position + 1}" }.attach() ``` 这样就可以实现 ViewPager2+TabLayout+Fragment 实现页面切换了。注意,TabLayoutMediator 是用来关联 TabLayout 和 ViewPager2 的,它的第一个参数是 TabLayout,第二个参数是 ViewPager2,第三个参数是一个回调函数,用来设置 TabLayout 的标签文本。在最后一行调用 attach() 方法即可完成关联。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值