0%

How to use ReactNative to implement a high-performance navigation bar

react-native-swipe-tabs why can’t meet my needs

We can know that the best animation performance of ReactNative is LayoutAnimation UIView animation, The best gesture performance is to use NativeEvent. These two solutions point to one direction, that is, to solve the performance problem of ReactNative. We can’t let the busy JS thread participate in these calls, so in terms of performance, I need to change from color to gradient The sliding and size of the text scaling and the scroll bar are all driven by the onScroll nativeEvent event, which is completely separated from the JS call to achieve the best performance

How to realize Label’s color gradient and text size scaling according to onScroll

We first bind the transform of the Label to the onScroll event. When Native needs to change the transform according to the onScroll calculation, we take the opportunity to change the gradient color of the Native

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//HTPageHeaderView
_itemTitleProps = (item, index) => {
let fontScale = 1 + (this.itemTitleSelectedStyle.fontSize - this.itemTitleNormalStyle.fontSize) / this.itemTitleNormalStyle.fontSize
if (fontScale == 1) {
fontScale = 1.0001
}
let scale = this.scrollPageIndexValue.interpolate({
inputRange: [index - 2, index - 1, index, index + 1, index + 2],
outputRange: [1, 1, fontScale, 1, 1]
})
let titleStyle = {
...
style: {
...this?.props?.itemTitleStyle,
transform: [{ scale }]
},
}
return titleStyle
}

We not only need to change the gradient color of the text, because the size of the text has also been changed, so we need to reset the size of the component through setIntrinsicContentSize for other components to re-typesetting

1
2
3
4
5
6
7
8
9
10
11
12
13
//HTSelectedLabel
- (void) reloadContentSize {
CGFloat progress = (self.layer.transform.m11 - 1) / (self.selectedScale - 1);
self.textColor = [[self class] appendColor:self.normalColor selectedColor:self.selectedColor progress:progress];
CGSize contentSize = [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
CGSize size = self. bounds. size;
if (size.width * size.height != 0 && !CGSizeEqualToSize(size, CGSizeZero)) {
contentSize = [self sizeThatFits:size];
}
if (size.width != contentSize.width || size.height != contentSize.height) {
[self.bridge.uiManager setIntrinsicContentSize:contentSize forView:self];
}
}

How to change the position and length of Cursor according to onScroll

If there is a fixed cursor length, then we can calculate the x offset that the cursor should have for each index
If there is no fixed cursor length, then we take the length of Label as the standard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//HTPageHeaderCursor
_reloadPageIndexValue = (isWidth) => {
let fixCursorWidth = this._findFixCursorWidth()
let rangeList = (isIndex) => {
let itemList = [isIndex? -1 : 0]
itemList = itemList.concat(this.itemContainerLayoutList.map((item, index) => {
if (isIndex) {
return index
} else {
if (item) {
if (fixCursorWidth) {
return isWidth ? fixCursorWidth : (item. x + (item. width - fixCursorWidth) / 2.0)
} else {
return isWidth ? item. width : (item. x + (item. width) / 2.0)
}
} else {
return 0
}
}
}))
itemList = itemList. concat([isIndex ? itemList. length - 1 : 0])
return itemList
}
return this.props.scrollPageIndexValue.interpolate({
inputRange: rangeList(true),
outputRange: rangeList(false),
})
}

Affiliated

The full code is here https://github.com/hellohublot/react-native-selected-page
I’m hublot, sharing some of my thoughts, I’m too busy with work, it’s inevitable that there will be negligence, please forgive me