ReactNative ViewPageAndroid组件详解

源码传送门

在我们开发Android的时候,ViewPage这个控件的使用频率还是很高的,最简单的就是制作引导页,应用程序的主界面等,在ReactNative开发中实现该功能的组件是ViewPageAndroid,当你看到该组件是以Android结尾,你就明白该组件只对Android平台有效,如果使用就要考虑适配iOS(目前学习到的ScrollView组件可以实现此效果,具体实现不在本篇文章介绍),今天就通过下面示例图,介绍ViewPageAndroid的API以及使用。


viewpage.gif

基本用法

对于该组件内部可以嵌套View,每一个子View就相当于一个Page,每一个单独的页面显示时它会拉伸填满ViewPageAndroid。

        return (
            <ViewPagerAndroid style={{backgroundColor: 'red', flex: 1}}>
                <View ><Text>1</Text></View>
                <View><Text>2</Text></View>
                <View><Text>3 </Text></View>
            </ViewPagerAndroid>
        )

在上面我么给出了一个最简单的展示ViewPagerAndroid的例子。我们在其内部加入了3个View,那么也将显示3页,虽然View没有设置样式,如宽和高,,但是它会填充ViewPagerAndroid ,其实设置了宽和高也没有用,不管设置宽高多少都是填满ViewPageAndroid。如果不信你可以尝试给第一个View添加样式

style={{backgroundColor:'green'}}

设置后,发现第一页显示的背景是绿色。然后再给第一个View增加宽高属性,都设置为100.如下

style={{backgroundColor:'green',width:100,height:100}}

设置后发现第一页的背景仍然全部是绿色,设置宽高属性并没有产生什么作用。对于文章开始的示例图展示,我们就是在VewPageAndroid组件中添加了5个子View,每一个View中有一个Image用于显示图片,和一个可点击的组件并且显示点击次数。

const styles = StyleSheet.create({
    button: {
        backgroundColor: '#2196f3',
        borderRadius: 5,
        marginHorizontal: 20,
        marginTop: 10,
        padding: 10,
    },
    buttonText: {
        color: 'white',
    },
    container: {
        flex: 1,
        backgroundColor: 'white',
    },
    image: {
        width: 300,
        height: 200,
        padding: 20,
    },
    viewPager: {
        flex: 1,
    },
});

由于ViewPageAndroid 5页显示的内容只是图片,背景不一样,其他都是通用的,我们就按如下创建


    render() {
        var pages = []
        for (var i = 0; i < PAGES; i++) {
            var pageStyle = {
                backgroundColor: BGCOLOR[i % BGCOLOR.length],
                alignItems: 'center',
                padding: 20,
            }
            pages.push(
                <View key={i} style={pageStyle} collapsable={false}>
                    <Image
                        style={styles.image}
                        resizeMode={Image.resizeMode.contain}
                        source={IMAGE_URIS[i % BGCOLOR.length]}
                    />
                    <CustomCount/>
                </View>
            )
        }
        return (
            <View style={styles.container}>
                <ViewPagerAndroid
                    style={styles.viewPager}
                    ref={(viewPage) => {
                        this.viewPage = viewPage;
                    }}>
                    {pages}
                </ViewPagerAndroid>
            </View>
        )
    }

用到的图片资源常量以及背景常量和页数常量如下

const PAGES = 5;
const BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273'];
const IMAGE_URIS = [
    require('./Thumbnails/cat.png'),
    require('./Thumbnails/monkey.png'),
    require('./Thumbnails/rabbit.png'),
    require('./Thumbnails/tiger.png'),
    require('./Thumbnails/duck.png'),
];

对于Image组件通过source指定要显示的图片,其它属性使用可以参考之前的文章ReactNative Image组件详解,CustomCount是定义的一个组件,

class CustomCount extends Component {
    state = {
        count: 1,
    }
    render() {
        return (
            <View>
                <TouchableOpacity
                    activeOpacity={0.5}
                    onPress={() => this.setState({count: this.state.count + 1})}
                    style={{backgroundColor: '#38adff', borderRadius: 5, marginTop: 20, padding: 10}}
                >
                    <Text>我是可点击的 {this.state.count}</Text>
                </TouchableOpacity>
            </View>)
    }
}

在定义的点击组件中设置一个状态count,用于显示点击次数。这样我们就可以实现看到大致效果了。

设置初始化时显示页数

在默认的时候,总是显示第一页,很多时候,我们需要显示指定的页数,例如我们实现了一个日历,有12页(12个月),那我们点击打开日历时,要显示当前月的信息。如果当前是8月,那么就要默认显示第八页,不需要再我们一页一页的翻到该页,这时候就要使用initialPage 属性,它可以指定第一个显示的页数,该值从0开始。如设置默认显示第二页,如下

 initialPage={1}

keyboardDismissMode

如果我们使用了用于输入的组件,就会弹出软键盘,那么在拖动翻页时需要隐藏软键盘,就需要使用此属性,它有两个值分别是none(默认值,拖拽不会让键盘消失)和on-drag(当拖拽开始的时候会让键盘消失)。如果我们设置滑动时隐藏软键盘,如下

 keyboardDismissMode="on-drag"

设置每相邻页之间的间距

在上面的展示图中,我们看到每两个相邻页显示有10像素的白色间距,这个效果是通过pageMargin属性设置的,颜色对于间距显示的的颜色,是ViewPagerAndroid中样式设置的背景色,如果没有设置,从它父视图继承。如我们设置间距10像素

pageMargin={10}

scrollEnabled

该属性是用来设置是否可以滚动支持,当设置true时表示可以滚动翻页,默认值也是true,如果设置false的话,就表示不可滚动翻页,如此此时想实现翻页效果,那就需要使用setPage方法,稍后再介绍其使用。

显示页数指示器

在图例中,我们看到有一个显示当前页数以及总页数的指示器,要实现此功能,我们我们需要用到onPageSelected属性函数,每当页面切换完成后,该函数会调用,该函数有一个参数event,可以通过event.nativeEvent.position 获取当前页面的下标。

//增加属性
 onPageSelected={this._onPageSelected}
  
_onPageSelected = (event) => {
        console.log('_onPageSelected')
        this.setState({page: event.nativeEvent.position});
    }

我们增加了一个状态值page用于标示当前页面的下标。然后在ViewPageAndroid下面添加组件Text,用于显示当前页面指示器。

<Text style={[style, {textAlign: 'center'}]}>{this.state.page + 1}/{pages.length}</Text>

由于页面下标从0开始,我们显示时对其加1。通过上面我们实现了页面指示器显示。

很多时候,我们需要在需要在翻页时实现一些动画,例如翻页时Tab的颜色变化动画,在RN中,我们也可以实现效果,实现此效果时通过onPageScroll属性函数,当我们拖动页面时这个函数会一直回调,该函数有一个参数,我们可以通过event.nativeEvent获取我们需要的数据。

  • position 从左数起第一个当前可见的页面的下标。(经过测试这个数据的用处不大,切记这个position和onPageSelected携带的position值不一样,不是当前页面下标)
  • offset 一个在[0,1)(大于等于0,小于1)之间的范围,代表当前页面切换的状态。值x表示现在"position"所表示的页有(1 - x)的部分可见,而下一页有x的部分可见。
    看到了把offset 变化时0到1之间的数值,当向左滑动翻页时(相当于下一页)该值时0到1变化,向右滑动翻页(相当于上一页)是1到0变化。我们就可以通过该值进行一些类似微信那种透明读,或者颜色深浅,等我们任何想要实现的动画。

onPageScrollStateChanged

该函数用于监测ViewPageAndroid的状态,它有三个值

  • idle 空闲,意味着当前没有交互。
  • dragging 拖动中,意味着当前页面正在被拖动。
  • settling 处理中,意味着当前页面发生过交互,且正在结束开头或收尾的动画。

我们增加一个状态scrollState。然后如图例一样,将状态显示。

 onPageScrollStateChanged={this._onPageScrollStateChanged}

_onPageScrollStateChanged = (state: ViewPagerScrollState) => {
        console.log('_onPageScrollStateChanged')
        this.setState({scrollState: state});
    };

使用按钮实现上下翻页

在图例中我们有上一页和下一页两个按钮。实现此功能可以通过ViewPagerAndroid的setPage方法

    _onPress = (offset) => {
        var goPage = (this.state.page + offset + PAGES) % PAGES
        if (this.state.animationsAreEnabled) {
            this.viewPage.setPage(goPage)
        } else {
            this.viewPage.setPageWithoutAnimation(goPage)
        }
        this.setState({page: goPage})
    }

我将上一页和下一页点击事件统一处理了,当点击下一页时参数传1,当点击上一页时参数传-1。goPage 即使我们对将要跳转的页面下标做计算。如果当前是第一页,再点击上一页时将跳转到最后一页,计算到要跳转的页面下标后,调用setPage或者setPageWithoutAnimation都可以实现,区别通过名字页显而易见。当使用setPage时最后一页和第一页相互切换时会有个过度动画。如果使用setPageWithoutAnimation就没有动画。

好了,ViewPageAndroid的相关介绍就到此为止了,想查看全部源码,可前往GitHub,今天的这篇文章就到此结束了,若文中有错误的地方欢迎指出,共同进步,谢谢。Have a wonderful day.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,595评论 4 59
  • 六月的武汉下起白雪 牛顿的苹果飞向了天际 太阳换了轨迹,西升东落 雷雨的天气里, 雷声赶来,闪电随后而至 这个世界...
    印恋阅读 383评论 0 1
  • 译文参考自六祖讲《金刚经》。 解读是个人暂时的浅见。 【原文】 “须菩提,于意云何?若有人满三千大千世界七宝以用布...
    吾宗老孙子阅读 436评论 0 0
  • 有如下这样一个变态的表格。我们需要在右边红色的单元格中计算出左边的数据的和。这个求和的变态之处在于左边的数据可能有...
    大道至简峰阅读 749评论 0 0