diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md
index b72d38da3..2c43b4255 100644
--- a/CHANGELOG.en-US.md
+++ b/CHANGELOG.en-US.md
@@ -14,6 +14,12 @@ toc: false
---
+### 5.2.3
+`2024-09-09`
+- 🔥 **Carousel**
+ - fix: Carousel autoplay and manual conflict. [#1259](https://github.com/ant-design/ant-design-mobile-rn/issues/1259)
+- fix: **Button** `children` support `string[]` type. [~commit](https://github.com/ant-design/ant-design-mobile-rn/commit/ce08b346cd1f53c39ea9cd861626247880720af4)
+
### 5.2.2
`2024-08-12`
- 🔥 **NoticeBar**
diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md
index 315478fb8..e279a993d 100644
--- a/CHANGELOG.zh-CN.md
+++ b/CHANGELOG.zh-CN.md
@@ -14,6 +14,12 @@ toc: false
---
+### 5.2.3
+`2024-09-09`
+- 🔥 **Carousel**
+ - fix: Carousel自动切换和手动切换冲突。[#1259](https://github.com/ant-design/ant-design-mobile-rn/issues/1259)
+- fix: **Button** `children` 支持 `string[]` 类型。[~commit](https://github.com/ant-design/ant-design-mobile-rn/commit/ce08b346cd1f53c39ea9cd861626247880720af4)
+
### 5.2.2
`2024-08-12`
- 🔥 **NoticeBar**
diff --git a/README.md b/README.md
index 4a71d5dc6..9832cf699 100644
--- a/README.md
+++ b/README.md
@@ -32,18 +32,18 @@ A configurable Mobile UI specification and React-based implementation.
> HTML5 Preview: [ant-design-mobile-rn/index.html](https://1uokun.github.io/ant-design-mobile-rn/index.html)
-|SDK 49+|
+|SDK 51|
|--|
-| [](https://expo.dev/preview/update?message=5.2.2&updateRuntimeVersion=5.2.2&createdAt=2024-08-12T13%3A33%3A56.096Z&slug=exp&projectId=7729a68b-f881-4294-89f5-5ae751bfb2b2&group=bbf0a647-4ff2-46bd-9aad-dfd81bc6ba08) |
+| [](https://expo.dev/preview/update?message=5.2.3&updateRuntimeVersion=5.2.3&createdAt=2024-09-09T09%3A01%3A36.394Z&slug=exp&projectId=7729a68b-f881-4294-89f5-5ae751bfb2b2&group=2e623b22-08d9-4ab2-92f2-017c7a92d5aa) |
Open the camera app on your device and scan the code above,
need install expo app: https://expo.io/tools
-Expo SDK history version
+Expo SDK(44, 47, 49, 50) history version
-|Expo SDK 44|SDK 47 iOS|SDK 47 Android|
-|--|--|--|
-| [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) |
+|Expo SDK 44|SDK 47 iOS|SDK 47 Android|SDK 49,50|
+|--|--|--|--|
+| [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/preview/update?message=5.2.2&updateRuntimeVersion=5.2.2&createdAt=2024-08-12T13%3A33%3A56.096Z&slug=exp&projectId=7729a68b-f881-4294-89f5-5ae751bfb2b2&group=bbf0a647-4ff2-46bd-9aad-dfd81bc6ba08) |
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 1733c1d7e..3349c0340 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -30,17 +30,17 @@ Ant Design 移动端设计规范。`@ant-design/react-native` 是 Ant Design 的
> HTML5 预览: [ant-design-mobile-rn/index.html](https://1uokun.github.io/ant-design-mobile-rn/index.html)
-|SDK 49+|
+|SDK 51|
|--|
-| [](https://expo.dev/preview/update?message=5.2.2&updateRuntimeVersion=5.2.2&createdAt=2024-08-12T13%3A33%3A56.096Z&slug=exp&projectId=7729a68b-f881-4294-89f5-5ae751bfb2b2&group=bbf0a647-4ff2-46bd-9aad-dfd81bc6ba08) |
+| [](https://expo.dev/preview/update?message=5.2.3&updateRuntimeVersion=5.2.3&createdAt=2024-09-09T09%3A01%3A36.394Z&slug=exp&projectId=7729a68b-f881-4294-89f5-5ae751bfb2b2&group=2e623b22-08d9-4ab2-92f2-017c7a92d5aa) |
提示:使用本地原相机扫瞄上面的二维码, 需要下载 Expo App: https://expo.io/tools
-Expo SDK历史版本
+Expo SDK(44, 47, 49, 50) 历史版本
-|Expo SDK 44|SDK 47 iOS|SDK 47 Android|
-|--|--|--|
-| [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) |
+|Expo SDK 44|SDK 47 iOS|SDK 47 Android|SDK 49,50|
+|--|--|--|--|
+| [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/@1uokun/ant-design-mobile-rn) | [](https://expo.dev/preview/update?message=5.2.2&updateRuntimeVersion=5.2.2&createdAt=2024-08-12T13%3A33%3A56.096Z&slug=exp&projectId=7729a68b-f881-4294-89f5-5ae751bfb2b2&group=bbf0a647-4ff2-46bd-9aad-dfd81bc6ba08) |
## 安装 & 使用
diff --git a/components/button/__tests__/__snapshots__/demo.test.js.snap b/components/button/__tests__/__snapshots__/demo.test.js.snap
index 91c6b2533..ce368e53f 100644
--- a/components/button/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/button/__tests__/__snapshots__/demo.test.js.snap
@@ -984,22 +984,37 @@ exports[`renders ./components/button/demo/basic.tsx correctly 1`] = `
}
}
>
-
-
-
+
+
+
+
diff --git a/components/button/index.tsx b/components/button/index.tsx
index eda65044a..3dbb572b7 100644
--- a/components/button/index.tsx
+++ b/components/button/index.tsx
@@ -5,13 +5,13 @@ import {
GestureResponderEvent,
StyleProp,
StyleSheet,
- Text,
TouchableHighlight,
TouchableHighlightProps,
View,
ViewStyle,
} from 'react-native'
import { WithTheme, WithThemeStyles } from '../style'
+import AntmView from '../view'
import { ButtonPropsType } from './PropsType'
import buttonStyles, { ButtonStyles } from './style/index'
@@ -140,11 +140,7 @@ export default class Button extends React.Component {
size="small"
/>
) : null}
- {typeof this.props.children === 'string' ? (
- {this.props.children}
- ) : (
- <>{this.props.children}>
- )}
+ {this.props.children}
)
diff --git a/components/carousel/PropsType.tsx b/components/carousel/PropsType.tsx
new file mode 100644
index 000000000..aea2cf4e4
--- /dev/null
+++ b/components/carousel/PropsType.tsx
@@ -0,0 +1,37 @@
+import { ReactNode } from 'react'
+import { ScrollViewProps, StyleProp, ViewStyle } from 'react-native'
+import { CarouselStyle } from './style/index'
+
+export interface CarouselProps extends ScrollViewProps {
+ accessibilityLabel?: string
+ autoplay?: boolean
+ autoplayInterval?: number
+ afterChange?: (index: number) => void
+ children?: ReactNode
+ dots?: boolean
+ dotActiveStyle?: StyleProp
+ dotStyle?: StyleProp
+ infinite?: boolean
+ pageStyle?: StyleProp
+ pagination?: (props: PaginationProps) => ReactNode
+ selectedIndex?: number
+ style?: StyleProp
+ styles?: Partial
+ vertical?: boolean
+}
+
+export interface PaginationProps {
+ current: number
+ count: number
+ dotStyle?: StyleProp
+ dotActiveStyle?: StyleProp
+ styles: Partial
+ vertical?: boolean
+}
+
+export interface CarouselForwardedRef {
+ scrollToStart: () => void
+ scrollToEnd: () => void
+ scrollNextPage: () => void
+ goTo: (index: number, animated?: boolean) => void
+}
diff --git a/components/carousel/__tests__/__snapshots__/demo.test.js.snap b/components/carousel/__tests__/__snapshots__/demo.test.js.snap
index a74ed90af..115537b93 100644
--- a/components/carousel/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/carousel/__tests__/__snapshots__/demo.test.js.snap
@@ -1,303 +1,447 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/carousel/demo/basic.tsx correctly 1`] = `
-
-
-
- horizontal
-
+
-
+
+ horizontal
+
+
-
-
+ }
+ directionalLockEnabled={true}
+ disableIntervalMomentum={false}
+ dotActiveStyle={Object {}}
+ dotStyle={Object {}}
+ dots={true}
+ horizontal={true}
+ infinite={true}
+ nestedScrollEnabled={true}
+ onScroll={[Function]}
+ onScrollBeginDrag={[Function]}
+ onScrollEndDrag={[Function]}
+ onTouchEnd={[Function]}
+ onTouchStart={[Function]}
+ pageStyle={Object {}}
+ pagination={[Function]}
+ pagingEnabled={true}
+ scrollEventThrottle={16}
+ selectedIndex={2}
+ showsHorizontalScrollIndicator={false}
+ showsVerticalScrollIndicator={false}
+ style={
+ Object {
+ "backgroundColor": "#fff",
+ "height": 150,
+ "width": "100%",
+ }
+ }
+ vertical={false}
+ >
+
-
- Carousel 5
-
+
+
+ Carousel 5
+
+
-
-
+
+
+ Carousel 1
+
+
+
+
-
- Carousel 1
-
+
+
+ Carousel 2
+
+
-
-
+
+
+ Carousel 3
+
+
+
+
-
- Carousel 2
-
+
+
+ Carousel 4
+
+
-
-
+
+
+ Carousel 5
+
+
+
+
-
- Carousel 3
-
+
+
+ Carousel 1
+
+
+
+
-
- Carousel 4
-
-
-
-
+ />
-
- Carousel 5
-
-
-
-
+ />
-
- Carousel 1
-
-
+ />
+
+
-
+
@@ -308,637 +452,487 @@ exports[`renders ./components/carousel/demo/basic.tsx correctly 1`] = `
}
}
>
-
-
-
-
-
+ >
+ Go to 0
+
+
+ vertical
+
-
- Go to 0
-
-
-
-
-
-
- vertical
-
-
-
-
-
+
-
- Carousel 5
-
+
+
+ Carousel 5
+
+
-
-
+
+
+ Carousel 1
+
+
+
+
-
- Carousel 1
-
+
+
+ Carousel 2
+
+
-
-
+
+
+ Carousel 3
+
+
+
+
-
- Carousel 2
-
+
+
+ Carousel 4
+
+
-
-
+
+
+ Carousel 5
+
+
+
+
-
- Carousel 3
-
+
+
+ Carousel 1
+
+
+
+
-
- Carousel 4
-
-
-
-
+ />
-
- Carousel 5
-
-
-
-
+ />
-
- Carousel 1
-
-
+ />
+
+
-
+
-
-
-
-
-
+ >
+ Toggle autoplay true
+
-
-
-
- Toggle autoplay true
-
-
-
-
+
`;
diff --git a/components/carousel/demo/basic.tsx b/components/carousel/demo/basic.tsx
index 83b7ee2c5..e26347c13 100644
--- a/components/carousel/demo/basic.tsx
+++ b/components/carousel/demo/basic.tsx
@@ -1,5 +1,12 @@
import React from 'react'
-import { StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'
+import {
+ ScrollView,
+ StyleSheet,
+ Text,
+ TextStyle,
+ View,
+ ViewStyle,
+} from 'react-native'
import { Button, Carousel } from '../../'
export default class BasicCarouselExample extends React.Component {
@@ -22,7 +29,7 @@ export default class BasicCarouselExample extends React.Component {
}
render() {
return (
-
+
horizontal
{
{`Toggle autoplay ${this.state.autoplay ? 'true' : 'false'}`}
-
+
)
}
}
@@ -121,13 +128,11 @@ const styles = StyleSheet.create<{
flexGrow: 1,
alignItems: 'center',
justifyContent: 'center',
- height: 150,
},
containerVertical: {
flexGrow: 1,
alignItems: 'center',
justifyContent: 'center',
- height: 150,
},
text: {
color: '#fff',
diff --git a/components/carousel/index.en-US.md b/components/carousel/index.en-US.md
index b0f874fed..949a9e41f 100644
--- a/components/carousel/index.en-US.md
+++ b/components/carousel/index.en-US.md
@@ -8,23 +8,29 @@ title: Carousel
Properties | Descrition | Type | Default
-----------|------------|------|--------
-| selectedIndex | current selected index | number | 0 |
-| dots | whether to display the indication dots | Boolean | true |
-| vertical | controls the pagination display direction. | Boolean | false |
+| afterChange | callback to be called after a slide is changed | (current: number) => void | |
| autoplay | autoplay mode active | Boolean | false |
| autoplayInterval | interval for autoplay iteration | Number | 3000 |
-| infinite | whether is infinite loop | Boolean | false |
-| afterChange | callback to be called after a slide is changed | (current: number): void | |
+| dots | whether to display the indication dots | Boolean | true |
| dotStyle | style of dots | ViewStyle | |
| dotActiveStyle | style of active dot | ViewStyle | |
+| infinite | whether is infinite loop | Boolean | false |
| pageStyle | style of the carousel page | ViewStyle | |
-| pagination | A generator function which could be used to customized pagination. | (props) => React.ReactNode | |
+| pagination | A generator function which could be used to customized pagination. | (props) => ReactNode | |
+| selectedIndex | current selected index | number | 0 |
+| style | ScrollView style
(`tips: Recommended setting, the overall carousel size is determined by the container scrollview and not the inner page`) | ViewStyle | |
+| vertical | controls the pagination display direction. | Boolean | false |
+
+The rest of the props of Carousel are exactly the same as the react-native [ScrollView](https://reactnative.dev/docs/scrollview.html);
-## Carousel methods
+eg: `scrollEnabled`、`onScroll` (if it not works, it is a mandatory prop of Carousel)
-属性 | 说明 | 类型 | 默认值
-----|-----|------|------
-| goTo | jump to specified index | (index: number, animated?: boolean): void | - |
+## Carousel ref methods
+
+Properties | Descrition | Type
+----|-----|------
+| goTo | jump to specified index | `(index: number, animated?: boolean): void` |
+| scrollNextPage | scroll to next page | `() => void` |
## FAQ
@@ -37,4 +43,9 @@ Support in `5.1.3`. Set the `nestedScrollEnabled` property of `ScrollView` to `t
...
-```
\ No newline at end of file
+```
+
+### Why choose Carousel instead of `react-native-pager-view` ?
+
+First, Carousel supports the `infinite` property, which means 🌟a true infinite loop🌟.
+Second, Carousel is completely based on `ScrollView`, which is not only lighter but also more compatible.
\ No newline at end of file
diff --git a/components/carousel/index.tsx b/components/carousel/index.tsx
index 53387c87b..b52f0ca60 100644
--- a/components/carousel/index.tsx
+++ b/components/carousel/index.tsx
@@ -1,68 +1,33 @@
import React from 'react'
import {
- LayoutRectangle,
+ GestureResponderEvent,
+ LayoutChangeEvent,
NativeScrollEvent,
NativeSyntheticEvent,
Platform,
ScrollView,
- ScrollViewProps,
- StyleProp,
View,
- ViewStyle,
} from 'react-native'
import devWarning from '../_util/devWarning'
-import { WithTheme, WithThemeStyles } from '../style'
-import CarouselStyles, { CarouselStyle } from './style/index'
-
-export interface CarouselPropsType
- extends WithThemeStyles,
- ScrollViewProps {
- accessibilityLabel?: string
- pageStyle?: ViewStyle
- children?: React.ReactNode
-
- selectedIndex?: number
- dots?: boolean
- vertical?: boolean
- autoplay?: boolean
- autoplayInterval?: number
- infinite?: boolean
-}
-
-export interface CarouselProps extends CarouselPropsType {
- style?: StyleProp
- dotStyle?: StyleProp
- dotActiveStyle?: StyleProp
- pagination?: (props: PaginationProps) => React.ReactNode
- afterChange?: (index: number) => void
-}
+import { WithTheme } from '../style'
+import { CarouselProps, PaginationProps } from './PropsType'
+import CarouselStyles from './style/index'
+// fix: Compatible History
+export { CarouselProps, PaginationProps } from './PropsType'
interface NativeScrollPoint {
x: number
y: number
}
-interface TargetedEvent {
- target: number
-}
export interface CarouselState {
width: number
height: number
selectedIndex: number
afterSelectedIndex: number
- isScrolling: boolean
offset: NativeScrollPoint
}
-export interface PaginationProps {
- vertical?: boolean
- current: number
- count: number
- styles: ReturnType
- dotStyle?: StyleProp
- dotActiveStyle?: StyleProp
-}
-
const defaultPagination = (props: PaginationProps) => {
const { styles, current, vertical, count, dotStyle, dotActiveStyle } = props
const positionStyle = vertical ? 'paginationY' : 'paginationX'
@@ -89,7 +54,7 @@ const defaultPagination = (props: PaginationProps) => {
)
}
class Carousel extends React.PureComponent {
- static defaultProps: CarouselProps = {
+ static defaultProps = {
accessibilityLabel: 'Carousel',
pageStyle: {},
@@ -116,7 +81,6 @@ class Carousel extends React.PureComponent {
this.state = {
width: 0,
height: 0,
- isScrolling: false,
selectedIndex: index,
afterSelectedIndex: -1,
offset: { x: 0, y: 0 },
@@ -132,13 +96,11 @@ class Carousel extends React.PureComponent {
const { width, height } = this.state
if (autoplay !== this.props.autoplay) {
if (autoplay) {
- this.autoplay()
+ this.autoplay(autoplay)
} else {
- this.autoplayTimer && clearTimeout(this.autoplayTimer)
+ this.clearTimeout()
}
}
- // selectedIndex only take effect once
- // ...
if (
children &&
@@ -153,7 +115,6 @@ class Carousel extends React.PureComponent {
: { x: width * (infinite ? 1 : 0), y: 0 }
this.setState(
{
- isScrolling: false,
afterSelectedIndex: -1,
selectedIndex: 0,
offset: offset,
@@ -165,84 +126,108 @@ class Carousel extends React.PureComponent {
)
}
- private autoplayTimer: ReturnType
- private scrollEndTimter: ReturnType
+ private autoplayTimer: ReturnType | undefined
+ private isScrolling: boolean | undefined
componentWillUnmount() {
- this.autoplayTimer && clearTimeout(this.autoplayTimer)
- this.scrollEndTimter && clearTimeout(this.scrollEndTimter)
- }
-
- onScrollBegin = (e: NativeSyntheticEvent) => {
- this.setState(
- {
- isScrolling: true,
- },
- () => {
- if (this.props.onScrollBeginDrag) {
- this.props.onScrollBeginDrag(e)
- }
- },
- )
+ this.clearTimeout()
}
- onScrollEnd = (e: NativeSyntheticEvent) => {
- e.persist?.()
- // android/web hack
- if (!e.nativeEvent.contentOffset) {
- //@ts-ignore
- const { position } = e.nativeEvent
- e.nativeEvent.contentOffset = {
- x: this.props.vertical ? 0 : position * this.state.width,
- y: this.props.vertical ? position * this.state.height : 0,
- }
+ /**
+ * Plathform: iOS & android
+ * 手势介入时: onScrollBeginDrag -> onScrollEndDrag
+ * **/
+ private onScrollBeginDrag = (e: NativeSyntheticEvent) => {
+ this.isScrolling = true
+
+ if (this.props.onScrollBeginDrag) {
+ this.props.onScrollBeginDrag(e)
}
- this.autoplay()
- clearTimeout(this.scrollEndTimter)
- this.scrollEndTimter = setTimeout(() => {
- this.updateIndex(e.nativeEvent.contentOffset)
-
- if (this.props.onMomentumScrollEnd) {
- this.props.onMomentumScrollEnd(e)
- }
- }, 50) //idle time
}
+ private onScrollEndDrag = (e: NativeSyntheticEvent) => {
+ this.isScrolling = false
+ // fix: drag page in Perfect fit
+ this.onScrollAnimationEnd(
+ JSON.parse(JSON.stringify(e.nativeEvent.contentOffset)),
+ )
- onScrollEndDrag = (e: NativeSyntheticEvent) => {
- e.persist?.()
- const { offset, selectedIndex } = this.state
- const previousOffset = offset
- const newOffset = e.nativeEvent.contentOffset
- if (
- (this.props.vertical
- ? previousOffset.y === newOffset.y
- : previousOffset.x === newOffset.x) &&
- (selectedIndex === 0 || selectedIndex === this.count - 1)
- ) {
- this.setState({
- isScrolling: false,
- })
- }
if (this.props.onScrollEndDrag) {
this.props.onScrollEndDrag(e)
}
}
- onTouchStartForWeb = () => {
- this.setState({ isScrolling: true })
+ /**
+ * Plathform: web
+ * 手势介入时: onTouchStart -> onScroll…onScroll(只要动了就会触发) -> onTouchEnd -> onScroll(动画结束时触发)
+ * autoplay: [onScroll...onScroll] -> onScroll(动画结束时触发)
+ * **/
+ private onTouchStartForWeb = (e: GestureResponderEvent) => {
+ this.isScrolling = true
+ if (this.props.onTouchStart) {
+ this.props.onTouchStart(e)
+ }
+ }
+ private onTouchEndForWeb = (e: GestureResponderEvent) => {
+ this.isScrolling = false
+ if (this.props.onTouchEnd) {
+ this.props.onTouchEnd(e)
+ }
}
- onTouchEndForWeb = () => {
- this.autoplay()
+ private onScroll = (e: NativeSyntheticEvent) => {
+ // Simulate infinite pages
+ if (this.props.infinite) {
+ const contentOffset = JSON.parse(
+ JSON.stringify(e.nativeEvent.contentOffset),
+ )
+ const { width, height } = this.state
+
+ const offset = this.props.vertical ? 'y' : 'x'
+ const maxOffset =
+ (this.props.vertical ? height : width) * (this.count + 1)
+
+ if (contentOffset[offset] <= 0) {
+ contentOffset[offset] = 0
+ this.updateIndex(contentOffset)
+ } else if (contentOffset[offset] >= maxOffset) {
+ contentOffset[offset] = maxOffset
+ this.updateIndex(contentOffset)
+ }
+ }
+
+ this.onScrollAnimationEnd(
+ JSON.parse(JSON.stringify(e.nativeEvent.contentOffset)),
+ )
+
+ if (this.props.onScroll) {
+ this.props.onScroll(e)
+ }
+ }
+ /**
+ * 所有scroll事件结束时触发
+ * **/
+ private onScrollAnimationEnd = (currentOffset: NativeScrollPoint) => {
+ const { x, y } = currentOffset
+ const { width, height } = this.state
+ // 🌟 fix: `onMomentumScrollEnd` & `onScrollAnimationEnd` not support for web & android 🌟
+ const isScrollAnimationEnd =
+ !this.isScrolling &&
+ (this.props.vertical ? y / height : x / width) % 1 === 0
+
+ if (isScrollAnimationEnd) {
+ this.updateIndex(currentOffset)
+ this.autoplay()
+ }
}
- onScrollForWeb = (e: any) => {
- this.onScrollEnd(JSON.parse(JSON.stringify(e)))
+ private clearTimeout = () => {
+ if (this.autoplayTimer) {
+ clearTimeout(this.autoplayTimer)
+ this.autoplayTimer = undefined
+ }
}
- onLayout = (
- e: NativeSyntheticEvent,
- ) => {
+ private onLayout = (e: LayoutChangeEvent) => {
const { selectedIndex, infinite, vertical } = this.props
const scrollIndex =
(this.count > 1 && Math.min(selectedIndex as number, this.count - 1)) || 0
@@ -263,8 +248,8 @@ class Carousel extends React.PureComponent {
offset,
},
() => {
- // web
- this.scrollview?.current?.scrollTo({ ...offset, animated: false })
+ // web & android
+ this.scrollview?.current?.scrollTo({ ...offset, animated: true })
this.autoplay()
},
)
@@ -351,8 +336,8 @@ class Carousel extends React.PureComponent {
}
scrollNextPage = () => {
- const { selectedIndex, isScrolling, width, height } = this.state
- if (isScrolling || this.count < 2) {
+ const { selectedIndex, width, height } = this.state
+ if (this.isScrolling || this.count < 2) {
return
}
const diff = selectedIndex + 1 + (this.props.infinite ? 1 : 0)
@@ -361,22 +346,6 @@ class Carousel extends React.PureComponent {
? { x: 0, y: diff * height }
: { x: diff * width, y: 0 },
)
-
- this.setState(
- {
- isScrolling: true,
- },
- () => {
- if (Platform.OS !== 'ios') {
- this.onScrollEnd({
- nativeEvent: {
- // @ts-ignore
- position: diff,
- },
- })
- }
- },
- )
}
/**
@@ -441,48 +410,37 @@ class Carousel extends React.PureComponent {
)
}
- private autoplay = () => {
- this.setState({ isScrolling: false }, () => {
- const { children, autoplay, autoplayInterval, infinite } = this.props
- const { selectedIndex } = this.state
- if (!Array.isArray(children) || !autoplay) {
- return
- }
- clearTimeout(this.autoplayTimer)
- this.autoplayTimer = setTimeout(() => {
- if (!infinite && selectedIndex + 1 === this.count - 1) {
- return
- }
- this.scrollNextPage()
- }, autoplayInterval)
- })
+ private autoplay = (autoplay = this.props.autoplay) => {
+ const { children, autoplayInterval } = this.props
+ if (!Array.isArray(children) || !autoplay) {
+ return
+ }
+ this.clearTimeout()
+ this.autoplayTimer = setTimeout(() => {
+ this.scrollNextPage()
+ }, autoplayInterval)
}
private renderScroll = (pages: React.ReactNode) => {
return (
+ onScroll={this.onScroll}
+ onTouchStart={this.onTouchStartForWeb}
+ onTouchEnd={this.onTouchEndForWeb}>
{pages}
)
diff --git a/components/carousel/index.zh-CN.md b/components/carousel/index.zh-CN.md
index 1b446b8a7..0f1f6a177 100644
--- a/components/carousel/index.zh-CN.md
+++ b/components/carousel/index.zh-CN.md
@@ -11,27 +11,33 @@ subtitle: 走马灯
属性 | 说明 | 类型 | 默认值
----|-----|------|------
-| selectedIndex | 手动设置当前显示的索引 | number | 0 |
-| dots | 是否显示面板指示点 | Boolean | true |
-| vertical | 垂直显示 | Boolean | false |
+| afterChange | 切换面板后的回调函数 | (current: number) => void | 无 |
| autoplay | 是否自动切换 | Boolean | false |
| autoplayInterval | 自动切换的时间间隔 | Number | 3000 |
-| infinite | 是否循环播放 | Boolean | false |
-| afterChange | 切换面板后的回调函数 | (current: number): void | 无 |
+| dots | 是否显示面板指示点 | Boolean | true |
| dotStyle | 指示点样式 | ViewStyle | 无 |
| dotActiveStyle | 当前激活的指示点样式 | ViewStyle | 无 |
-| pageStyle | 轮播页样式 | ViewStyle | 无 |
-| pagination | 自定义 pagination | (props) => React.ReactNode | |
+| infinite | 是否循环播放 | Boolean | false |
+| pageStyle | 轮播页内样式 | ViewStyle | 无 |
+| pagination | 自定义 pagination | (props) => ReactNode | |
+| selectedIndex | 手动设置当前显示的索引 | number | 0 |
+| style | 轮播容器样式
(建议设置,整体轮播大小由容器决定非页内决定) | ViewStyle | 无 |
+| vertical | 垂直显示 | Boolean | false |
+
+
+Carousel 的其他属性和 react-native 内置组件[ScrollView](https://reactnative.dev/docs/scrollview.html) 一致;
+比如:`scrollEnabled`、`onScroll` (若设置后不生效则为Carousel强制属性)
## Carousel methods
-属性 | 说明 | 类型 | 默认值
-----|-----|------|------
-| goTo | 跳转到指定位置 | (index: number, animated?: boolean): void | - |
+属性 | 说明 | 类型
+----|-----|------
+| goTo | 跳转到指定位置 | `(index: number, animated?: boolean) => void` |
+| scrollNextPage | 滚动到下一页 | `() => void` |
## FAQ
-### 在Android平台,ScrollView中嵌套使用Carousel,会发生Carousel Item不能滑动的情况,怎么办?
+### 1. 在Android平台,ScrollView中嵌套使用Carousel,会发生Carousel Item不能滑动的情况,怎么办?
`5.1.3`新增支持。 设置`ScrollView`的`nestedScrollEnabled`属性为`true`即可。
@@ -40,4 +46,9 @@ subtitle: 走马灯
...
-```
\ No newline at end of file
+```
+
+### 2. Carousel和 `react-native-pager-view` 有什么区别(或优势)?
+
+首先,Carousel支持`infinite`属性,即🌟真正的无限循环🌟。
+其次,Carousel是完全基于`ScrollView`实现,不仅更轻量,且更具有兼容性。
\ No newline at end of file
diff --git a/components/grid/__tests__/__snapshots__/demo.test.js.snap b/components/grid/__tests__/__snapshots__/demo.test.js.snap
index 87613c192..b657dcecb 100644
--- a/components/grid/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/grid/__tests__/__snapshots__/demo.test.js.snap
@@ -926,19 +926,22 @@ exports[`renders ./components/grid/demo/basic.tsx correctly 1`] = `
}
}
directionalLockEnabled={true}
+ disableIntervalMomentum={false}
dotActiveStyle={Object {}}
dotStyle={Object {}}
dots={true}
horizontal={true}
infinite={false}
nestedScrollEnabled={true}
- onMomentumScrollEnd={[Function]}
+ onScroll={[Function]}
onScrollBeginDrag={[Function]}
onScrollEndDrag={[Function]}
+ onTouchEnd={[Function]}
+ onTouchStart={[Function]}
pageStyle={Object {}}
pagination={[Function]}
pagingEnabled={true}
- removeClippedSubviews={false}
+ scrollEventThrottle={16}
selectedIndex={0}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
diff --git a/example/app.json b/example/app.json
index 3b5866e01..0cf6791f0 100644
--- a/example/app.json
+++ b/example/app.json
@@ -4,7 +4,7 @@
"expo": {
"name": "@ant-design/react-native",
"slug": "ant-design-mobile-rn",
- "version": "5.2.2",
+ "version": "5.2.3",
"description": "基于蚂蚁金服移动设计规范的 React Native 组件库",
"icon": "../rn-kitchen-sink/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png",
"splash": {
diff --git a/example/package.json b/example/package.json
index 7c54ee1f3..44a6405fd 100644
--- a/example/package.json
+++ b/example/package.json
@@ -1,6 +1,6 @@
{
"name": "@ant-design/react-native-example",
- "version": "5.2.2",
+ "version": "5.2.3",
"description": "Demo app for ant-design mobile RN UI Library",
"private": true,
"homepage": ".",
@@ -18,17 +18,17 @@
},
"dependencies": {
"@ant-design/icons-react-native": "^2.3.2",
- "@expo/metro-runtime": "~3.1.3",
- "expo": "^50.0.3",
+ "@expo/metro-runtime": "~3.2.3",
+ "expo": "51",
"expo-haptics": "^13.0.1",
- "expo-splash-screen": "~0.26.3",
- "expo-status-bar": "~1.11.1",
- "expo-updates": "~0.24.11",
+ "expo-splash-screen": "~0.27.5",
+ "expo-status-bar": "~1.12.1",
+ "expo-updates": "~0.25.24",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.73.2",
- "react-native-gesture-handler": "~2.14.0",
- "react-native-reanimated": "~3.6.2",
+ "react-native-gesture-handler": "~2.16.1",
+ "react-native-reanimated": "~3.10.1",
"react-native-web": "~0.19.6"
},
"devDependencies": {
diff --git a/package.json b/package.json
index 76d0f30a5..c61b39178 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@ant-design/react-native",
- "version": "5.2.2",
+ "version": "5.2.3",
"description": "基于蚂蚁金服移动设计规范的 React Native 组件库",
"keywords": [
"ant",