- 实现的效果:
- 页面向上滑动有吸顶的效果。
-
便民服务,查询服务 ...
所在的tabBar
与页面下方对应的模块内容一一对应。 - 页面滑动对应的
tabBar
的title
居中偏移。 - 编辑模式下:数据的
新增
与删除
。
- 效果展示:
-
实现吸顶的代码(噗~感觉这个没啥好写 ...... 很尴尬):
—— 段子手是运用ScrollView
==>onScroll
==>e.nativeEvent.contentOffset.y
获取页面滑动的当前坐标;
然后和页面初次加载时tabBar
==>onLayout
==>e.nativeEvent.layout.y
的值做比较获取状态。this.moveHeight = e.nativeEvent.contentOffset.y; if (this.moveHeight >= typeY) { this.setState({ positionType: true, }) } else { this.setState({ positionType: false }) }
-
实现滑动模块和标题一一对应代码(这个有点篇幅):
-
先说:点击标题,对应的模块自动置顶
- 首先初次加载时,我把
tabBar
下的各个模块的y
坐标都存下来,push
到数组中,并且对应的模块下标i
也存起来。
//保存 模块的下标和 y 轴 let params = { key: i, tmpY: e.nativeEvent.layout.y }; //数组去重(判断命名的变量不建议用 type) let typePis = tmpArr.some(v => v.key == params.key); if (typePis) { tmpArr.filter((v) => { return v.key != params.key }) } else { tmpArr.push(params); } break;
- 去重是因为吸顶的原因,会导致页面的
onLayout
重新加载。 - 这里还有一个小坑:模块返回的坐标顺序并不是按页面展示顺序来的。
- 拿到模块的坐标数组
tmpArr
后,根据点击tabBar
的下标index
和tmpArr
的key
去匹配,一致时取出tmpArr
对应的tmpY
值,根据该值去计算页面的偏移量。
let y; tmpArr.map((v, i) => { if (v.key == index) { y = v.tmpY; } }); // 页面中模块的 y 轴移动 (typeY: tabBar 的坐标, // y:模块的坐标,头部 固定位置的搜索: autoHeight(45)) this.refs.refMoveHeight.scrollTo({y: typeY + y - autoHeight(45)});
- 在点击
tabBar
最后的标题,模块的内容的高度不够去偏移到置顶的位置的处理(根据已有的内容高度,去自适应填充空白区域)。- 保存最后一个模块的
y
轴
// i:就是点击标题的下标;typeList:是标题数组。 if (i == typeList.length - 1) { this.setState({ listCellHeight: e.nativeEvent.layout.y }) }
- 在最后的一个模块后面添加一个高度为
1
的View
,然后保存它的坐标footHeight = e.nativeEvent.layout.y
,接着再设置一个填充空白页面View
,高度为屏幕全高 - (footHeight - listCellHeight - typeY + autoHeight(45))
。
- 保存最后一个模块的
- 首先初次加载时,我把
-
再说下滑动模块和
tabBar
的标题对应- 获取手势在屏幕上的滑动方向,把
<=
当前页面滑动高度的模块都塞选出来,然后取出最大的下标,然后和tabBar
中的标题下标去匹配,一致则标题显示高亮。let maxValue = 0; if (this.moveHeight > e.nativeEvent.contentOffset.y) { tmpArr.map((v, i) => { if (e.nativeEvent.contentOffset.y >= (typeY + v.tmpY - autoHeight(45))) { // console.log(i + '下下下'); //因为模块高度的下标不是按在页面中的位置返回的,所以和 tabBar 的下标并不能一一对应,所以要塞选出下标的最大值 if (tmpArr[i].key >= maxValue) { maxValue = tmpArr[i].key } // console.log(maxValue + 'maxValue下========='); } } ) } else { tmpArr.map((v, i) => { if (e.nativeEvent.contentOffset.y >= (typeY + v.tmpY - autoHeight(45))) { // console.log(i + '下下下'); //因为模块高度的下标不是按在页面中的位置返回的,所以和 tabBar 的下标并不能一一对应,所以要塞选出下标的最大值 if (tmpArr[i].key >= maxValue) { maxValue = tmpArr[i].key } // console.log(maxValue + 'maxValue上======'); } } ) } this.state.currentIndex = maxValue;
- 获取手势在屏幕上的滑动方向,把
-
-
实现页面滑动对应的
tabBar
的title
居中偏移代码-
获取屏幕
width
的宽度的一半。let widthHalf = 屏幕宽度 / 2;
-
获取到
tabBar
中各个标题位置的width
,同时保存对应的挑剔位置的下标,数组为tmpArrX
。//保存 tabBar 的下标和 width let param = { index: i, tmpX: e.nativeEvent.layout.width }; //数组去重 let tmpType = tmpArrX.some(v => v.index == param.index); if (tmpType) { tmpArrX.filter((v) => { return v.index != param.index }) } else { tmpArrX.push(param); }
-
拿到点击
tabBar
的下标,获取到这个下标之前的模块width
。//获取 index 之前模块 width let widthX = 0; //获取选中的 width let indexWidth; for (let i = 0; i <= index; i++) { // console.log('i===' + i); tmpArrX.map((item, key) => { if (item.index == i) { widthX += item.tmpX } if (index == item.index) { indexWidth = item.tmpX } }) }
-
根据判断出来是不是
tabBar
中最后一个标题,然后拿widthX
和indexWidth
然后去判断编写逻辑。let moveX; // index*20 是每个模块的空隙 20 if (widthX + index * 20 > widthHalf && index != tmpArrX.length - 1) { moveX = (widthX - widthHalf + indexWidth) / 2 } else if (index == tmpArrX.length - 1) { //index + 1 :间距比个数多一个; 10 :marGinLeft = 10 moveX = (index + 1) * 20 + widthX - SCREEN_WIDTH + 10 } // 页面中 tabBar 的 x 轴移动 this.refs.moveX.scrollTo({x: autoWidth(moveX)})
-
-
实现编辑模式下:数据的
新增
与删除
的代码(段子手快饿死了,写不动注释了 ......)//数组的加减 _addOrDelete(keyType, data, i) { console.log('data===' + JSON.stringify(data) + '===' + i); //更改 severListType 的数据 const {severListType, headList}=this.state; let tmpType = severListType.some(item => item.id === data.id); switch (keyType) { case 1: // severListType.splice(i, 1); if (tmpType) { // tmpSeverId :用来存储选中的截取的 id this.state.severListType = severListType.filter((item) => { return item.id != data.id }); //编辑模式下,是否为已有模块, true:加号,false:减号 data.select = !tmpType; } break; case 2: case 3: if (!tmpType) { if (severListType.length > 10) { RootToast.show('首页最多添加 11 个应用') } else { severListType.push(data) } } else { //获取输入的值和在另一个模块数组中的下标,然后删除 console.log('data1===' + JSON.stringify(data) + '===ss' + i); console.log('severListType===' + JSON.stringify(severListType)); this.state.severListType = severListType.filter((item) => { return item.id != data.id }); data.select = !tmpType; } break; } //刷新数据 this.setState({ severListType: this.state.severListType }, () => { // console.log('severListType===' + JSON.stringify(this.state.severListType)); }); }
TIP:
- 吸顶效果在
android
低配中会出现卡顿现象。 - 页面滑动对应的
tabBar
的title
居中偏移(我的写法还是有问题的,还有就是模块滑动时tabBar
对应居中也会有卡顿)。
新增手势
-
TouchableHighlight
属性
名称 | 属性 | 注释 |
---|---|---|
accessibilityComponentType | View.AccessibilityComponentType | 设置可访问的组件类型 |
accessibilityTraits | View.AccessibilityTraits | 设置访问特征 |
accessible | bool | 设置当前组件是否可以访问 |
delayLongPress | View.AccessibilityTraits | 设置当前组件是否可以访问 |
accessibilityTraits | number | 设置延迟的时间,单位为毫秒。从 onPressIn 方法开始,到 onLongPress 被调用这一段时间 |
delayPressIn | number | 设置延迟的时间,单位为毫秒,从用户触摸控件开始到 onPressIn 被调用这一段时间 |
delayPressOut | number | 设置延迟的时间,单位为毫秒,从用户触摸事件释放开始到 onPressOut 被调用这一段时间 |
onLayout | function | 当组件加载或者改组件的布局发生变化的时候调用。调用传入的参数为 {nativeEvent:{layout:{x,y,width,height}}} |
onLongPress | function | 当用户长时间按压组件(长按效果)的时候调用该方法 |
onPress | function | 当用户点击的时候调用(触摸结束)。 但是如果事件被取消了就不会调用。(例如:当前被滑动事件所替代) |
onPressIn | function | 用户开始触摸组件回调方法 |
onPressOut | function | 用户完成触摸组件之后回调方法 |
pressRetentionOffset | {top: ,left: ,bottom: ,right: } | 该设置当视图滚动禁用的情况下,可以定义当手指距离组件的距离。当大于该距离该组件会失去响应。当少于该距离的时候,该组件会重新进行响应。确保你传入一个常量来减少内存分配。 |
段子手不才,欢迎来补充
- 由于篇幅原因,具体想要知道整个效果图的代码或者有补充地方的可以加技术群:631730313