Skip to content

Commit

Permalink
feat: refactor Tabs (#1218)
Browse files Browse the repository at this point in the history
  • Loading branch information
1uokun authored Feb 23, 2022
1 parent 1146566 commit ea2ae3e
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 182 deletions.
19 changes: 12 additions & 7 deletions components/carousel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class Carousel extends React.PureComponent<CarouselProps, CarouselState> {
height: 0,
isScrolling: false,
selectedIndex: index,
afterSelectedIndex: 0,
afterSelectedIndex: -1,
offset: { x: 0, y: 0 },
}
}
Expand Down Expand Up @@ -357,8 +357,9 @@ class Carousel extends React.PureComponent<CarouselProps, CarouselState> {
/**
* go to index
* @param index
* @param animated
*/
public goTo(index: number) {
public goTo(index: number, animated?: boolean) {
const { width, height } = this.state

const count = this.props.infinite ? this.count - 1 : this.count
Expand All @@ -370,11 +371,15 @@ class Carousel extends React.PureComponent<CarouselProps, CarouselState> {
)
}

this.scrollview?.current?.scrollTo(
this.props.vertical
? { x: 0, y: (index + (this.props.infinite ? 1 : 0)) * height }
: { x: (index + (this.props.infinite ? 1 : 0)) * width, y: 0 },
)
this.scrollview?.current?.scrollTo({
x: this.props.vertical
? 0
: (index + (this.props.infinite ? 1 : 0)) * width,
y: this.props.vertical
? (index + (this.props.infinite ? 1 : 0)) * height
: 0,
animated,
})
}

render() {
Expand Down
151 changes: 73 additions & 78 deletions components/tabs/DefaultTabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ export interface PropsType
scrollValue?: any
tabStyle?: ViewStyle
tabsContainerStyle?: ViewStyle
/** default: false */
dynamicTabUnderlineWidth?: boolean
keyboardShouldPersistTaps?: boolean
}

Expand All @@ -46,13 +44,13 @@ export class DefaultTabBar extends React.PureComponent<PropsType, StateType> {
tabBarActiveTextColor: '',
tabBarInactiveTextColor: '',
tabBarTextStyle: {},
dynamicTabUnderlineWidth: false,
}

_tabsMeasurements: any[] = []
_tabContainerMeasurements: any
_containerMeasurements: any
_scrollView: ScrollView
_newLineLeft: number

constructor(props: PropsType) {
super(props)
Expand Down Expand Up @@ -115,40 +113,36 @@ export class DefaultTabBar extends React.PureComponent<PropsType, StateType> {
newScrollX = newScrollX >= 0 ? newScrollX : 0

if (Platform.OS === 'android') {
this._scrollView.scrollTo({ x: newScrollX, y: 0, animated: false })
this._scrollView?.scrollTo({ x: newScrollX, y: 0 })
} else {
const rightBoundScroll =
this._tabContainerMeasurements.width - this._containerMeasurements.width
newScrollX = newScrollX > rightBoundScroll ? rightBoundScroll : newScrollX
this._scrollView.scrollTo({ x: newScrollX, y: 0, animated: false })
this._scrollView?.scrollTo({ x: newScrollX, y: 0 })
}
}

updateTabUnderline(position: number, pageOffset: number, tabCount: number) {
const { dynamicTabUnderlineWidth } = this.props

if (position >= 0 && position <= tabCount - 1) {
if (dynamicTabUnderlineWidth) {
const nowLeft = this._tabsMeasurements[position].left
const nowRight = this._tabsMeasurements[position].right
const nextTabLeft = this._tabsMeasurements[position + 1].left
const nextTabRight = this._tabsMeasurements[position + 1].right
const nowLeft = this._tabsMeasurements[position].left
const nowRight = this._tabsMeasurements[position].right
const nextTabLeft = this._tabsMeasurements[position + 1]?.left || 0
const nextTabRight = this._tabsMeasurements[position + 1]?.right || 0

const newLineLeft =
pageOffset * nextTabLeft + (1 - pageOffset) * nowLeft
const newLineRight =
pageOffset * nextTabRight + (1 - pageOffset) * nowRight
const newLineLeft = pageOffset * nextTabLeft + (1 - pageOffset) * nowLeft
const newLineRight =
pageOffset * nextTabRight + (1 - pageOffset) * nowRight

this.state._leftTabUnderline.setValue(newLineLeft)
this.state._widthTabUnderline.setValue(newLineRight - newLineLeft)
} else {
const nowLeft = (position * this.state._tabContainerWidth) / tabCount
const nextTabLeft =
((position + 1) * this.state._tabContainerWidth) / tabCount
const newLineLeft =
pageOffset * nextTabLeft + (1 - pageOffset) * nowLeft
this.state._leftTabUnderline.setValue(newLineLeft)
}
if (this._newLineLeft === newLineLeft) return
this._newLineLeft = newLineLeft
Animated.timing(this.state._leftTabUnderline, {
toValue: newLineLeft,
useNativeDriver: false,
}).start()
Animated.timing(this.state._widthTabUnderline, {
toValue: newLineRight - newLineLeft,
useNativeDriver: false,
}).start()
}
}

Expand Down Expand Up @@ -191,8 +185,8 @@ export class DefaultTabBar extends React.PureComponent<PropsType, StateType> {
<View
style={{
...StyleSheet.flatten(styles.tab),
minWidth: width,
...this.props.tabStyle,
width,
}}>
{renderTab ? (
renderTab(tab)
Expand Down Expand Up @@ -221,45 +215,69 @@ export class DefaultTabBar extends React.PureComponent<PropsType, StateType> {
this.updateView({ value: this.props.scrollValue._value })
}

getTabs = (styles: TabBarStyle, theme: Theme) => {
const { tabs, page = 0 } = this.props
return tabs.map((name, index) => {
let tab = { title: name } as TabData
if (tabs.length - 1 >= index) {
tab = tabs[index]
}
const tabWidth = this.state._containerWidth / Math.min(page, tabs.length)

return this.renderTab(
tab,
index,
tabWidth,
this.measureTab.bind(this, index),
styles,
theme,
)
})
}

getUnderLine = (styles: TabBarStyle) => {
const { tabBarUnderlineStyle, renderUnderline } = this.props

const tabUnderlineStyle = {
position: 'absolute',
bottom: 0,
...StyleSheet.flatten(styles.underline),
...StyleSheet.flatten(tabBarUnderlineStyle),
}

const dynamicTabUnderline = {
left: this.state._leftTabUnderline,
width: this.state._widthTabUnderline,
}
const underlineProps = {
style: {
...dynamicTabUnderline,
...tabUnderlineStyle,
},
}
return renderUnderline ? (
renderUnderline(underlineProps.style)
) : (
//@ts-ignore
<Animated.View {...underlineProps} />
)
}

render() {
const {
tabs,
page = 0,
tabBarUnderlineStyle,
tabBarBackgroundColor,
tabsContainerStyle,
renderUnderline,
keyboardShouldPersistTaps,
} = this.props
return (
<WithTheme styles={this.props.styles} themeStyles={TabBarStyles}>
{(styles, theme) => {
const tabUnderlineStyle = {
position: 'absolute',
bottom: 0,
...StyleSheet.flatten(styles.underline),
...StyleSheet.flatten(tabBarUnderlineStyle),
}

const dynamicTabUnderline = {
left: this.state._leftTabUnderline,
width: this.state._widthTabUnderline,
}

const tabWidth =
this.state._containerWidth / Math.min(page, tabs.length)
const underlineProps = {
style: {
...dynamicTabUnderline,
...tabUnderlineStyle,
},
}

return (
<View
style={[
styles.container,

{
backgroundColor: tabBarBackgroundColor,
},
Expand All @@ -281,32 +299,12 @@ export class DefaultTabBar extends React.PureComponent<PropsType, StateType> {
<View
style={[
styles.tabs,

{
...tabsContainerStyle,
backgroundColor: tabBarBackgroundColor,
},
tabsContainerStyle,
{ backgroundColor: tabBarBackgroundColor },
]}
onLayout={this.onTabContainerLayout}>
{tabs.map((name, index) => {
let tab = { title: name } as TabData
if (tabs.length - 1 >= index) {
tab = tabs[index]
}
return this.renderTab(
tab,
index,
tabWidth,
this.measureTab.bind(this, index),
styles,
theme,
)
})}
{renderUnderline ? (
renderUnderline(underlineProps.style)
) : (
<Animated.View {...underlineProps.style} />
)}
{this.getTabs(styles, theme)}
{this.getUnderLine(styles)}
</View>
</ScrollView>
</View>
Expand All @@ -324,9 +322,6 @@ export class DefaultTabBar extends React.PureComponent<PropsType, StateType> {
// width = WINDOW_WIDTH;
// }
this.setState({ _tabContainerWidth: width })
if (!this.props.dynamicTabUnderlineWidth) {
this.state._widthTabUnderline.setValue(width / this.props.tabs.length)
}
this.updateView({ value: this.props.scrollValue._value })
}

Expand Down
Loading

0 comments on commit ea2ae3e

Please sign in to comment.