From c5b52333fab7a4fc245cbeebbd95e53d01ad7d78 Mon Sep 17 00:00:00 2001 From: wangcuijuan Date: Fri, 27 Sep 2024 12:06:23 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E4=BF=AE=E6=AD=A3modal=E8=A1=A5=E5=85=85?= =?UTF-8?q?onKeyboardHeightChange&offKeyboardHeightChange?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/api/keyboard/index.android.js | 1 + .../src/platform/api/keyboard/index.ios.js | 48 +++++++++++++++++++ .../src/platform/api/keyboard/index.js | 10 ++++ .../src/platform/api/modal/rnModal.jsx | 8 +++- packages/api-proxy/src/platform/index.js | 3 ++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 packages/api-proxy/src/platform/api/keyboard/index.android.js create mode 100644 packages/api-proxy/src/platform/api/keyboard/index.ios.js create mode 100644 packages/api-proxy/src/platform/api/keyboard/index.js diff --git a/packages/api-proxy/src/platform/api/keyboard/index.android.js b/packages/api-proxy/src/platform/api/keyboard/index.android.js new file mode 100644 index 0000000000..df7053eff6 --- /dev/null +++ b/packages/api-proxy/src/platform/api/keyboard/index.android.js @@ -0,0 +1 @@ +export * from './index' diff --git a/packages/api-proxy/src/platform/api/keyboard/index.ios.js b/packages/api-proxy/src/platform/api/keyboard/index.ios.js new file mode 100644 index 0000000000..4501974cdb --- /dev/null +++ b/packages/api-proxy/src/platform/api/keyboard/index.ios.js @@ -0,0 +1,48 @@ +import { Keyboard } from 'react-native' + +import { ENV_OBJ, envError } from '../../../common/js' +let hasListener = false +let callbacks = [] + +function keyboardShowListener(e) { + const endCoordinates = e.endCoordinates || {} + callbacks.forEach(cb => cb({ + height: endCoordinates.height + })) +} +function keyboardHideListener(e) { + const endCoordinates = e.endCoordinates || {} + let height + if (__mpx_mode__ === 'ios') { + height = 0 + } else { + height = endCoordinates.height + } + callbacks.forEach(cb => cb({ + height + })) +} +const onKeyboardHeightChange = function (callback) { + if (!hasListener) { + Keyboard.addListener("keyboardDidShow", keyboardShowListener) + Keyboard.addListener("keyboardDidHide", keyboardHideListener) + hasListener = true + } + callbacks.push(callback) +} +const offKeyboardHeightChange = function (callback) { + const index = callbacks.indexOf(callback) + if (index > -1) { + callbacks.splice(index, 1) + } + if (callbacks.length === 0) { + Keyboard.removeAllListeners('keyboardDidShow') + Keyboard.removeAllListeners('keyboardDidHide') + hasListener = false + } +} + +export { + onKeyboardHeightChange, + offKeyboardHeightChange +} diff --git a/packages/api-proxy/src/platform/api/keyboard/index.js b/packages/api-proxy/src/platform/api/keyboard/index.js new file mode 100644 index 0000000000..977e4686d4 --- /dev/null +++ b/packages/api-proxy/src/platform/api/keyboard/index.js @@ -0,0 +1,10 @@ +import { ENV_OBJ, envError } from '../../../common/js' + +const onKeyboardHeightChange = ENV_OBJ.onKeyboardHeightChange || envError('onKeyboardHeightChange') + +const offKeyboardHeightChange = ENV_OBJ.offKeyboardHeightChange || envError('offKeyboardHeightChange') + +export { + onKeyboardHeightChange, + offKeyboardHeightChange +} diff --git a/packages/api-proxy/src/platform/api/modal/rnModal.jsx b/packages/api-proxy/src/platform/api/modal/rnModal.jsx index c4d23e82f9..11060afae0 100644 --- a/packages/api-proxy/src/platform/api/modal/rnModal.jsx +++ b/packages/api-proxy/src/platform/api/modal/rnModal.jsx @@ -20,10 +20,13 @@ const showModal = function (options = {}) { const modalWidth = width - 60 const styles = StyleSheet.create({ modalTask: { - width, - height, + left: 0, + right: 0, + top: 0, + bottom: 0, justifyContent: 'center', alignItems: 'center', + display: 'flex', backgroundColor: 'rgba(0,0,0,0.6)', position: 'absolute' }, @@ -144,6 +147,7 @@ const showModal = function (options = {}) { height: 40, backgroundColor: '#eeeeee', width: '100%', + keyboardType: 'default', paddingLeft: 10, paddingRight: 10 }} onChangeText={text => onChangeText(text)} defaultValue={content}>)} diff --git a/packages/api-proxy/src/platform/index.js b/packages/api-proxy/src/platform/index.js index c9728aec68..71a0ef4bb8 100644 --- a/packages/api-proxy/src/platform/index.js +++ b/packages/api-proxy/src/platform/index.js @@ -113,3 +113,6 @@ export * from './api/location' // getExtConfig, getExtConfigSync export * from './api/ext' + +// onKeyboardHeightChange, offKeyboardHeightChange +export * from './api/keyboard' From 3873f138b07b4e4c310f91909bd13fba6d46e88e Mon Sep 17 00:00:00 2001 From: wangcuijuan Date: Fri, 27 Sep 2024 13:49:51 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E4=BF=AE=E6=AD=A3lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/platform/api/keyboard/index.ios.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/api-proxy/src/platform/api/keyboard/index.ios.js b/packages/api-proxy/src/platform/api/keyboard/index.ios.js index 4501974cdb..405424ae79 100644 --- a/packages/api-proxy/src/platform/api/keyboard/index.ios.js +++ b/packages/api-proxy/src/platform/api/keyboard/index.ios.js @@ -1,16 +1,16 @@ import { Keyboard } from 'react-native' -import { ENV_OBJ, envError } from '../../../common/js' let hasListener = false -let callbacks = [] +const callbacks = [] -function keyboardShowListener(e) { +function keyboardShowListener (e) { const endCoordinates = e.endCoordinates || {} + // eslint-disable-next-line node/no-callback-literal callbacks.forEach(cb => cb({ height: endCoordinates.height })) } -function keyboardHideListener(e) { +function keyboardHideListener (e) { const endCoordinates = e.endCoordinates || {} let height if (__mpx_mode__ === 'ios') { @@ -18,14 +18,15 @@ function keyboardHideListener(e) { } else { height = endCoordinates.height } + // eslint-disable-next-line node/no-callback-literal callbacks.forEach(cb => cb({ height })) } const onKeyboardHeightChange = function (callback) { if (!hasListener) { - Keyboard.addListener("keyboardDidShow", keyboardShowListener) - Keyboard.addListener("keyboardDidHide", keyboardHideListener) + Keyboard.addListener('keyboardDidShow', keyboardShowListener) + Keyboard.addListener('keyboardDidHide', keyboardHideListener) hasListener = true } callbacks.push(callback) From c82ad64defbe75702ab3658a0db01fe0b0c3a342 Mon Sep 17 00:00:00 2001 From: luyongfang Date: Mon, 30 Sep 2024 15:33:02 +0800 Subject: [PATCH 03/13] picker-view abandon antd-desin picker --- .../react/mpx-picker-view-column.tsx | 123 ++++++++++++++--- .../components/react/mpx-picker-view.tsx | 124 +++++++++--------- 2 files changed, 167 insertions(+), 80 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx index 01c7be4e70..be8c49ca66 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx @@ -1,27 +1,116 @@ -import { View } from 'react-native' -import React, { forwardRef, useRef } from 'react' -import useInnerProps from './getInnerListeners' -import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 - +import { View, Animated, NativeScrollEvent, NativeSyntheticEvent } from 'react-native' +import React, { forwardRef, useRef, useState, useEffect } from 'react' +import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数 interface ColumnProps { - children: React.ReactNode + children: React.ReactNode, + selectedIndex: number, + onColumnLayoutChange: Function, + getInnerLayout: Function + onSelectChange: Function } +// 每个Column 都有个外层的高度, 内部的元素高度 +// 默认的高度 const _PickerViewColumn = forwardRef, ColumnProps>((props: ColumnProps, ref) => { - const { children } = props + const { children, selectedIndex, onColumnLayoutChange, onSelectChange, getInnerLayout } = props + // scrollView的ref + const { nodeRef: scrollViewRef } = useNodesRef(props, ref, {}) + // scrollView的布局存储 const layoutRef = useRef({}) - const { nodeRef } = useNodesRef(props, ref, {}) - const innerProps = useInnerProps(props, {}, [], { layoutRef }) - return ( - - {children} - - ) + // item的ref + const itemDomRef = useRef(null) + // item的布局存储 + const itemPosRef = useRef({}) + // 每个元素的高度 + let [itemH, setItemH] = useState(0) + // scrollView内容的初始offset + let [offset, setOffset] = useState(0) + + useEffect(() => { + if (selectedIndex && itemH) { + offset = (selectedIndex + 2) * itemH + setOffset(offset) + } + }, [selectedIndex, itemH]) + + const onScrollViewLayout = () => { + scrollViewRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { + layoutRef.current = { x, y, width, height, offsetLeft, offsetTop } + getInnerLayout && getInnerLayout(layoutRef) + }) + } + + const onItemLayout = () => { + itemDomRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { + if (height > 0 && itemH !== height) { + itemPosRef.current = { x, y, width, height, offsetLeft, offsetTop } + itemH = height + setItemH(height) + onColumnLayoutChange && onColumnLayoutChange({ height: height * 5 }) + } + }) + } + + const onMomentumScrollEnd = (e: NativeSyntheticEvent) => { + if (scrollViewRef && itemH) { + const { y: scrollY } = e.nativeEvent.contentOffset + const selIndex = scrollY / itemH + onSelectChange(selIndex) + } + } + + const renderInnerchild = () => { + // Fragment 节点 + const realChilds = Array.isArray(children) ? children : (children.props?.children && Array.isArray(children.props?.children) ? children.props.children : [children]) + + const arrChild = realChilds.map((item: React.ReactNode, index: number) => { + const InnerProps = index === 0 ? { onLayout: onItemLayout } : {} + return {item} + }) + const emptyEle = () + arrChild.unshift(emptyEle) + arrChild.unshift(emptyEle) + arrChild.push(emptyEle) + arrChild.push(emptyEle) + return arrChild + } + + const renderScollView = () => { + const wheelStyle = { + // display: "flex", + // flex: 1, + height: itemH + } + + return ( + {renderInnerchild()} + ) + } + + return ( + {renderScollView()} + ) }) -_PickerViewColumn.displayName = 'mpx-picker-view-column' +_PickerViewColumn.displayName = 'mpx-picker-view-column'; export default _PickerViewColumn + diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx index 074226df30..b73aa87bd1 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx @@ -1,6 +1,5 @@ import { View } from 'react-native' -import React, { forwardRef, useState, useRef, useEffect } from 'react' -import { PickerView } from '@ant-design/react-native' +import React, { forwardRef, MutableRefObject, useState, useRef } from 'react' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 /** @@ -22,81 +21,80 @@ interface PickerViewProps { bindchange?: Function } -const _PickerView = forwardRef, PickerViewProps>((props: PickerViewProps, ref) => { - const { children, ...restProps } = props - const layoutRef = useRef({}) - const { nodeRef } = useNodesRef(props, ref, {}) - const [value, setValue] = useState(props.value) - useEffect(() => { - // 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行 - setValue(props.value) - }, [props.value]) +interface PickerLayout { + height: number +} - const onLayout = () => { - nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { - layoutRef.current = { x, y, width, height, offsetLeft, offsetTop } - }) +const styles: { [key: string]: Object } = { + wrapper: { + display: 'flex', + flex: 1, + flexDirection: "row", + justifyContent: "space-around" } - const innerProps = useInnerProps(props, {}, [], { layoutRef }) +} +const _PickerView = forwardRef, PickerViewProps>((props: PickerViewProps, ref) => { + const { children, value = [], bindchange } = props + const innerLayout = useRef({}) + const cloneRef = useRef(null) + let [pickH, setPickH] = useState(0) - const onChange = (val: Array): void => { - const eventData = getCustomEvent('change', {}, { detail: { value: val, source: 'touch' }, layoutRef: layoutRef }) - setValue(val) - props.bindchange && props.bindchange(eventData) - } + const { nodeRef } = useNodesRef(props, ref, {}) - const joinString = (data: string | any[] | React.ReactElement): string => { - return (Array.isArray(data) ? data : [data]).join('') - } + // value 如何关联picker-view-column这几个slot的内容呢 - const getLabelFromChildren = (child: React.ReactElement): string => { - return child.props && child.props.children ? getLabelFromChildren(child.props.children) : joinString(child) + const onColumnLayoutChange = (layoutConfig: PickerLayout) => { + pickH = layoutConfig.height + setPickH(layoutConfig.height) } - const handleChildren = (children: React.ReactNode[]): any[] => { - return children.map((child: any, index: number) => { - return { - label: getLabelFromChildren(child), - value: index - } - }) + const onSelectChange = (columnIndex: number, selIndex: number) => { + const changeValue = value.slice() + changeValue[columnIndex] = selIndex + const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef: {} }) + console.log('-------------------onSelectChange:eventData', eventData) + bindchange && bindchange(eventData) } + + const getInnerLayout = (layout: MutableRefObject<{}>) => { + innerLayout.current = layout.current + } + + const innerProps = useInnerProps(props, {ref: nodeRef}, [], { layoutRef: innerLayout }) - const getDataFromChildren = (children: React.ReactNode): any[] => { - return (Array.isArray(children) ? children : [children]).map((child: any) => { - return handleChildren(child.props && child.props.children ? child.props.children : [child]) - }) + const cloneChild = (child: React.ReactNode, index: number) => { + const extraProps = index === 0 ? { + getInnerLayout: getInnerLayout, + innerProps + } : {} + const childProps = { + ...child.props, + ref: cloneRef, + onColumnLayoutChange, + onSelectChange: onSelectChange.bind(null, index), + selectedIndex: value?.[index] || 0, + ...extraProps + } + return React.cloneElement(child, childProps) } - const columns = Array.isArray(children) ? children.length : 1 - const originData = getDataFromChildren(children) - // 子节点默认的序号,这里是更新默认值的 - const subChildLength = originData.map((item) => { - return item.length - }) - const defaultValue = (props.value || []).map((item, index) => { - if (item > subChildLength[index]) { - return subChildLength[index] - 1 + const renderSubChild = () => { + if (Array.isArray(children)) { + return children.map((item, index) => { + return cloneChild(item, index) + }) } else { - return item + return cloneChild(children, 0) } - }) - - return ( - - ) + } + + return ( + + {renderSubChild()} + + ) }) -_PickerView.displayName = 'mpx-picker-view' +_PickerView.displayName = 'mpx-picker-view'; export default _PickerView From a63ec469420341d140efde0005a92d44cfb31697 Mon Sep 17 00:00:00 2001 From: luyongfang Date: Tue, 1 Oct 2024 21:28:33 +0800 Subject: [PATCH 04/13] add pickerview column unselected line mask --- .../react/mpx-picker-view-column.tsx | 18 +++--- .../components/react/mpx-picker-view.tsx | 60 +++++++++++++++++-- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx index be8c49ca66..ea6ecd15cf 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx @@ -1,7 +1,8 @@ -import { View, Animated, NativeScrollEvent, NativeSyntheticEvent } from 'react-native' +import { View, Animated, ScrollView, NativeScrollEvent, NativeSyntheticEvent } from 'react-native' import React, { forwardRef, useRef, useState, useEffect } from 'react' -import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数 +// import { Reanimated } from 'react-native-reanimated'; +import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 interface ColumnProps { children: React.ReactNode, selectedIndex: number, @@ -11,7 +12,7 @@ interface ColumnProps { } // 每个Column 都有个外层的高度, 内部的元素高度 // 默认的高度 - +// const AnimatedScrollView = Reanimated.createAnimatedComponent(ScrollView); const _PickerViewColumn = forwardRef, ColumnProps>((props: ColumnProps, ref) => { const { children, selectedIndex, onColumnLayoutChange, onSelectChange, getInnerLayout } = props // scrollView的ref @@ -68,7 +69,8 @@ const _PickerViewColumn = forwardRef, ColumnProps> const InnerProps = index === 0 ? { onLayout: onItemLayout } : {} return {item} }) - const emptyEle = () + // 渐变待支持 + const emptyEle = () arrChild.unshift(emptyEle) arrChild.unshift(emptyEle) arrChild.push(emptyEle) @@ -78,10 +80,11 @@ const _PickerViewColumn = forwardRef, ColumnProps> const renderScollView = () => { const wheelStyle = { - // display: "flex", - // flex: 1, height: itemH } + const contentContainerStyle = { + textAlign: "center" + } return (, ColumnProps> showsVerticalScrollIndicator={false} pagingEnabled={false} snapToInterval={itemH} + contentContainerStyle={contentContainerStyle} automaticallyAdjustContentInsets={false} // contentOffset={offset} // directionalLockEnabled={true} @@ -105,7 +109,7 @@ const _PickerViewColumn = forwardRef, ColumnProps> ) } - return ( + return ( {renderScollView()} ) }) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx index b73aa87bd1..ee9aede5eb 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx @@ -1,4 +1,4 @@ -import { View } from 'react-native' +import { View, ViewStyle } from 'react-native' import React, { forwardRef, MutableRefObject, useState, useRef } from 'react' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 @@ -19,10 +19,12 @@ interface PickerViewProps { // 初始的defaultValue数组中的数字依次表示 picker-view 内的 picker-view-column 选择的第几项(下标从 0 开始),数字大于 picker-view-column 可选项长度时,选择最后一项。 value?: Array bindchange?: Function + style?: Object } interface PickerLayout { - height: number + height: number, + itemHeight: number } const styles: { [key: string]: Object } = { @@ -30,13 +32,33 @@ const styles: { [key: string]: Object } = { display: 'flex', flex: 1, flexDirection: "row", - justifyContent: "space-around" + justifyContent: "space-around", + overflow: 'hidden' + }, + + maskTop: { + position: 'absolute', + backgroundColor: "#fcfcfc", + opacity: 0.6, + top: 0, + width: "100%", + zIndex: 100 + }, + + maskBottom: { + position: 'absolute', + backgroundColor: "#fcfcfc", + opacity: 0.6, + bottom: 0, + width: "100%", + zIndex: 100 } } const _PickerView = forwardRef, PickerViewProps>((props: PickerViewProps, ref) => { - const { children, value = [], bindchange } = props + const { children, value = [], bindchange, style} = props const innerLayout = useRef({}) const cloneRef = useRef(null) + const wrapRef = useRef(null) let [pickH, setPickH] = useState(0) const { nodeRef } = useNodesRef(props, ref, {}) @@ -52,12 +74,20 @@ const _PickerView = forwardRef, PickerViewProp const changeValue = value.slice() changeValue[columnIndex] = selIndex const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef: {} }) - console.log('-------------------onSelectChange:eventData', eventData) + // console.log('-------------------onSelectChange:eventData', eventData) bindchange && bindchange(eventData) } + const onWrapperLayout = (e) => { + wrapRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { + const a = { x, y, width, height, offsetLeft, offsetTop } + console.log('-----onWrapperLayout', a) + }) + } + const getInnerLayout = (layout: MutableRefObject<{}>) => { innerLayout.current = layout.current + console.log('--------------getInnerLayout', innerLayout) } const innerProps = useInnerProps(props, {ref: nodeRef}, [], { layoutRef: innerLayout }) @@ -76,6 +106,14 @@ const _PickerView = forwardRef, PickerViewProp ...extraProps } return React.cloneElement(child, childProps) + } + + const renderTopMask = () => { + return + } + + const renderBottomMask = () => { + return } const renderSubChild = () => { @@ -87,12 +125,22 @@ const _PickerView = forwardRef, PickerViewProp return cloneChild(children, 0) } } - + // innerLayout.current.offsetTop + console.log('----------mpx-picker-view: render', style) + return ( + {renderTopMask()} + + {renderSubChild()} + + {renderBottomMask()} + ) + /* return ( {renderSubChild()} ) + */ }) _PickerView.displayName = 'mpx-picker-view'; From 4a6c7a9b0a12b17050b19e3bca632595b199b4f5 Mon Sep 17 00:00:00 2001 From: luyongfang Date: Tue, 8 Oct 2024 10:08:45 +0800 Subject: [PATCH 05/13] fix: mask position & selected item position --- .../components/react/mpx-picker-view.tsx | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx index ee9aede5eb..fec6575891 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx @@ -1,4 +1,4 @@ -import { View, ViewStyle } from 'react-native' +import { View } from 'react-native' import React, { forwardRef, MutableRefObject, useState, useRef } from 'react' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 @@ -19,7 +19,9 @@ interface PickerViewProps { // 初始的defaultValue数组中的数字依次表示 picker-view 内的 picker-view-column 选择的第几项(下标从 0 开始),数字大于 picker-view-column 可选项长度时,选择最后一项。 value?: Array bindchange?: Function - style?: Object + style?: { + height?: number + } } interface PickerLayout { @@ -27,6 +29,11 @@ interface PickerLayout { itemHeight: number } +interface PosType { + height?: number, + top?: number +} + const styles: { [key: string]: Object } = { wrapper: { display: 'flex', @@ -44,7 +51,6 @@ const styles: { [key: string]: Object } = { width: "100%", zIndex: 100 }, - maskBottom: { position: 'absolute', backgroundColor: "#fcfcfc", @@ -59,7 +65,16 @@ const _PickerView = forwardRef, PickerViewProp const innerLayout = useRef({}) const cloneRef = useRef(null) const wrapRef = useRef(null) + const fixPosition: PosType = {} + const maskPos: PosType = {} let [pickH, setPickH] = useState(0) + if (style?.height && pickH) { + const fixH = Math.floor((pickH - style.height) / 2) + fixPosition.top = -fixH + maskPos.height = pickH / 5 * 2 - fixH + } else { + maskPos.height = pickH / 5 * 2 + } const { nodeRef } = useNodesRef(props, ref, {}) @@ -74,20 +89,17 @@ const _PickerView = forwardRef, PickerViewProp const changeValue = value.slice() changeValue[columnIndex] = selIndex const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef: {} }) - // console.log('-------------------onSelectChange:eventData', eventData) bindchange && bindchange(eventData) } const onWrapperLayout = (e) => { wrapRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { const a = { x, y, width, height, offsetLeft, offsetTop } - console.log('-----onWrapperLayout', a) }) } const getInnerLayout = (layout: MutableRefObject<{}>) => { innerLayout.current = layout.current - console.log('--------------getInnerLayout', innerLayout) } const innerProps = useInnerProps(props, {ref: nodeRef}, [], { layoutRef: innerLayout }) @@ -106,14 +118,14 @@ const _PickerView = forwardRef, PickerViewProp ...extraProps } return React.cloneElement(child, childProps) - } + } const renderTopMask = () => { - return + return } const renderBottomMask = () => { - return + return } const renderSubChild = () => { @@ -125,22 +137,14 @@ const _PickerView = forwardRef, PickerViewProp return cloneChild(children, 0) } } - // innerLayout.current.offsetTop - console.log('----------mpx-picker-view: render', style) - return ( + + return ( {renderTopMask()} - + {renderSubChild()} {renderBottomMask()} ) - /* - return ( - - {renderSubChild()} - - ) - */ }) _PickerView.displayName = 'mpx-picker-view'; From 6739fda49741dd1797ae2e3f3d130d7d1127b90d Mon Sep 17 00:00:00 2001 From: luyongfang Date: Tue, 8 Oct 2024 12:19:25 +0800 Subject: [PATCH 06/13] feat: picker add LinearGradient --- .../components/react/mpx-picker-view.tsx | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx index fec6575891..1ecef9f415 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx @@ -1,4 +1,5 @@ import { View } from 'react-native' +import LinearGradient from 'react-native-linear-gradient'; import React, { forwardRef, MutableRefObject, useState, useRef } from 'react' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 @@ -42,21 +43,14 @@ const styles: { [key: string]: Object } = { justifyContent: "space-around", overflow: 'hidden' }, - maskTop: { position: 'absolute', - backgroundColor: "#fcfcfc", - opacity: 0.6, - top: 0, - width: "100%", + width: "200%", zIndex: 100 }, maskBottom: { position: 'absolute', - backgroundColor: "#fcfcfc", - opacity: 0.6, - bottom: 0, - width: "100%", + width: "200%", zIndex: 100 } } @@ -121,11 +115,35 @@ const _PickerView = forwardRef, PickerViewProp } const renderTopMask = () => { - return + return + + // return } const renderBottomMask = () => { - return + return + + // return } const renderSubChild = () => { @@ -137,7 +155,7 @@ const _PickerView = forwardRef, PickerViewProp return cloneChild(children, 0) } } - + return ( {renderTopMask()} From b1c0a2d66e536873aacbc8b7cc243f7948931308 Mon Sep 17 00:00:00 2001 From: luyongfang Date: Wed, 9 Oct 2024 17:07:28 +0800 Subject: [PATCH 07/13] picker-view fix eslint & scroll position --- .../react/mpx-picker-view-column.tsx | 80 +++++++++---------- .../components/react/mpx-picker-view.tsx | 61 +++++++------- 2 files changed, 65 insertions(+), 76 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx index ea6ecd15cf..95070bbd6f 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx @@ -1,5 +1,5 @@ -import { View, Animated, ScrollView, NativeScrollEvent, NativeSyntheticEvent } from 'react-native' +import { View, Animated, SafeAreaView, NativeScrollEvent, NativeSyntheticEvent, Platform } from 'react-native' import React, { forwardRef, useRef, useState, useEffect } from 'react' // import { Reanimated } from 'react-native-reanimated'; import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 @@ -7,22 +7,23 @@ interface ColumnProps { children: React.ReactNode, selectedIndex: number, onColumnLayoutChange: Function, - getInnerLayout: Function - onSelectChange: Function + getInnerLayout: Function, + onSelectChange: Function, + style: Object, + wrapperStyle: { + height?: number + }, + prefix: number } // 每个Column 都有个外层的高度, 内部的元素高度 // 默认的高度 // const AnimatedScrollView = Reanimated.createAnimatedComponent(ScrollView); const _PickerViewColumn = forwardRef, ColumnProps>((props: ColumnProps, ref) => { - const { children, selectedIndex, onColumnLayoutChange, onSelectChange, getInnerLayout } = props + const { children, selectedIndex, onColumnLayoutChange, onSelectChange, getInnerLayout, wrapperStyle } = props // scrollView的ref const { nodeRef: scrollViewRef } = useNodesRef(props, ref, {}) // scrollView的布局存储 const layoutRef = useRef({}) - // item的ref - const itemDomRef = useRef(null) - // item的布局存储 - const itemPosRef = useRef({}) // 每个元素的高度 let [itemH, setItemH] = useState(0) // scrollView内容的初始offset @@ -42,15 +43,13 @@ const _PickerViewColumn = forwardRef, ColumnProps> }) } - const onItemLayout = () => { - itemDomRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { - if (height > 0 && itemH !== height) { - itemPosRef.current = { x, y, width, height, offsetLeft, offsetTop } - itemH = height - setItemH(height) - onColumnLayoutChange && onColumnLayoutChange({ height: height * 5 }) - } - }) + const onItemLayout = (e: NativeSyntheticEvent) => { + const layout = e.nativeEvent.layout + if (layout.height && itemH !== layout.height) { + itemH = layout.height + setItemH(layout.height) + onColumnLayoutChange && onColumnLayoutChange({ height: layout.height * 5 }) + } } const onMomentumScrollEnd = (e: NativeSyntheticEvent) => { @@ -64,30 +63,33 @@ const _PickerViewColumn = forwardRef, ColumnProps> const renderInnerchild = () => { // Fragment 节点 const realChilds = Array.isArray(children) ? children : (children.props?.children && Array.isArray(children.props?.children) ? children.props.children : [children]) - - const arrChild = realChilds.map((item: React.ReactNode, index: number) => { + const arrChild = realChilds.map((item: React.ReactNode, index: number) => { const InnerProps = index === 0 ? { onLayout: onItemLayout } : {} - return {item} + const strKey = 'picker' + props.prefix + '-column' + index + return {item} }) - // 渐变待支持 - const emptyEle = () - arrChild.unshift(emptyEle) - arrChild.unshift(emptyEle) - arrChild.push(emptyEle) - arrChild.push(emptyEle) + const totalHeight = itemH * 5 + if (wrapperStyle.height && totalHeight > wrapperStyle.height) { + const fix = Math.ceil((totalHeight - wrapperStyle.height) / 2) + arrChild.unshift() + arrChild.unshift() + arrChild.push() + arrChild.push() + } else { + arrChild.unshift() + arrChild.unshift() + arrChild.push() + arrChild.push() + } return arrChild } const renderScollView = () => { - const wheelStyle = { - height: itemH - } const contentContainerStyle = { - textAlign: "center" + textAlign: 'center' } return (, ColumnProps> snapToInterval={itemH} contentContainerStyle={contentContainerStyle} automaticallyAdjustContentInsets={false} - // contentOffset={offset} - // directionalLockEnabled={true} onLayout={onScrollViewLayout} - // onMomentumScrollBegin={onMomentumScrollBegin} - // onScrollEndDrag={onScrollEndDrag} onMomentumScrollEnd={onMomentumScrollEnd}> - {renderInnerchild()} + {renderInnerchild()} ) } - return ( - {renderScollView()} - ) + return ( + { renderScollView() } + ) }) -_PickerViewColumn.displayName = 'mpx-picker-view-column'; - +_PickerViewColumn.displayName = 'mpx-picker-view-column' export default _PickerViewColumn - diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx index 1ecef9f415..8b30fd45ba 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx @@ -1,5 +1,5 @@ import { View } from 'react-native' -import LinearGradient from 'react-native-linear-gradient'; +import LinearGradient from 'react-native-linear-gradient' import React, { forwardRef, MutableRefObject, useState, useRef } from 'react' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 @@ -39,33 +39,31 @@ const styles: { [key: string]: Object } = { wrapper: { display: 'flex', flex: 1, - flexDirection: "row", - justifyContent: "space-around", - overflow: 'hidden' + flexDirection: 'row', + justifyContent: 'space-around', + overflow: 'hidden', + alignItems: 'center' }, maskTop: { position: 'absolute', - width: "200%", + width: 1000, zIndex: 100 }, maskBottom: { position: 'absolute', - width: "200%", + width: 1000, zIndex: 100 } } const _PickerView = forwardRef, PickerViewProps>((props: PickerViewProps, ref) => { - const { children, value = [], bindchange, style} = props + const { children, value = [], bindchange, style } = props const innerLayout = useRef({}) const cloneRef = useRef(null) const wrapRef = useRef(null) - const fixPosition: PosType = {} const maskPos: PosType = {} let [pickH, setPickH] = useState(0) if (style?.height && pickH) { - const fixH = Math.floor((pickH - style.height) / 2) - fixPosition.top = -fixH - maskPos.height = pickH / 5 * 2 - fixH + maskPos.height = pickH / 5 * 2 + (style.height - pickH) } else { maskPos.height = pickH / 5 * 2 } @@ -85,8 +83,8 @@ const _PickerView = forwardRef, PickerViewProp const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef: {} }) bindchange && bindchange(eventData) } - - const onWrapperLayout = (e) => { + + const onWrapperLayout = () => { wrapRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { const a = { x, y, width, height, offsetLeft, offsetTop } }) @@ -96,16 +94,18 @@ const _PickerView = forwardRef, PickerViewProp innerLayout.current = layout.current } - const innerProps = useInnerProps(props, {ref: nodeRef}, [], { layoutRef: innerLayout }) + const innerProps = useInnerProps(props, { ref: nodeRef }, [], { layoutRef: innerLayout }) const cloneChild = (child: React.ReactNode, index: number) => { - const extraProps = index === 0 ? { - getInnerLayout: getInnerLayout, - innerProps - } : {} + const extraProps = index === 0 ? { getInnerLayout: getInnerLayout, innerProps } : {} const childProps = { - ...child.props, + ...child?.props, ref: cloneRef, + prefix: index, + key: 'pick-view' + index, + wrapperStyle: { + height: style?.height || 0 + }, onColumnLayoutChange, onSelectChange: onSelectChange.bind(null, index), selectedIndex: value?.[index] || 0, @@ -115,35 +115,29 @@ const _PickerView = forwardRef, PickerViewProp } const renderTopMask = () => { - return - // return } const renderBottomMask = () => { - return - // return } const renderSubChild = () => { @@ -155,16 +149,15 @@ const _PickerView = forwardRef, PickerViewProp return cloneChild(children, 0) } } - - return ( + return ( {renderTopMask()} - + {renderSubChild()} {renderBottomMask()} ) }) -_PickerView.displayName = 'mpx-picker-view'; +_PickerView.displayName = 'mpx-picker-view' export default _PickerView From ede3c737cede2f65c17fb77e43fe1f8fe3706e49 Mon Sep 17 00:00:00 2001 From: wangcuijuan Date: Thu, 10 Oct 2024 09:59:28 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E8=A1=A5=E5=85=85vibrate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/platform/api/vibrate/index.android.js | 1 + .../src/platform/api/vibrate/index.ios.js | 39 +++++++++++++++++++ .../src/platform/api/vibrate/index.js | 10 +++++ packages/api-proxy/src/platform/index.js | 3 ++ 4 files changed, 53 insertions(+) create mode 100644 packages/api-proxy/src/platform/api/vibrate/index.android.js create mode 100644 packages/api-proxy/src/platform/api/vibrate/index.ios.js create mode 100644 packages/api-proxy/src/platform/api/vibrate/index.js diff --git a/packages/api-proxy/src/platform/api/vibrate/index.android.js b/packages/api-proxy/src/platform/api/vibrate/index.android.js new file mode 100644 index 0000000000..25aabdbcf9 --- /dev/null +++ b/packages/api-proxy/src/platform/api/vibrate/index.android.js @@ -0,0 +1 @@ +export * from './index.ios' diff --git a/packages/api-proxy/src/platform/api/vibrate/index.ios.js b/packages/api-proxy/src/platform/api/vibrate/index.ios.js new file mode 100644 index 0000000000..38cc4de600 --- /dev/null +++ b/packages/api-proxy/src/platform/api/vibrate/index.ios.js @@ -0,0 +1,39 @@ +import ReactNativeHapticFeedback from 'react-native-haptic-feedback' +import { Vibration } from 'react-native' +import { successHandle, failHandle } from '../../../common/js' + +const getType = function (type = 'light') { + return 'impact' + type[0].toUpperCase() + type.substr(1) +} +const vibrateShort = function (options = {}) { + const { type = 'light', success, fail, complete } = options + try { + ReactNativeHapticFeedback.trigger(getType(type), { + ignoreAndroidSystemSettings: true, + enableVibrateFallback: true + }) + const result = { + errMsg: 'vibrateShort:ok' + } + successHandle(result, success, complete) + } catch (e) { + const result = { + errMsg: 'vibrateShort:fail' + } + successHandle(result, fail, complete) + } +} + +const vibrateLong = function (options = {}) { + const { success, complete } = options + Vibration.vibrate(400) + const result = { + errMsg: 'vibrateLong:ok' + } + successHandle(result, success, complete) +} + +export { + vibrateShort, + vibrateLong +} diff --git a/packages/api-proxy/src/platform/api/vibrate/index.js b/packages/api-proxy/src/platform/api/vibrate/index.js new file mode 100644 index 0000000000..8f7f5e1bef --- /dev/null +++ b/packages/api-proxy/src/platform/api/vibrate/index.js @@ -0,0 +1,10 @@ +import { ENV_OBJ, envError } from '../../../common/js' + +const vibrateShort = ENV_OBJ.vibrateShort || envError('vibrateShort') + +const vibrateLong = ENV_OBJ.vibrateLong || envError('vibrateLong') + +export { + vibrateShort, + vibrateLong +} diff --git a/packages/api-proxy/src/platform/index.js b/packages/api-proxy/src/platform/index.js index c9728aec68..4703aafa6a 100644 --- a/packages/api-proxy/src/platform/index.js +++ b/packages/api-proxy/src/platform/index.js @@ -113,3 +113,6 @@ export * from './api/location' // getExtConfig, getExtConfigSync export * from './api/ext' + +// vibrateShort, vibrateLong +export * from './api/vibrate' From 8e8dfa43747596a9739239d7df4eacb330950360 Mon Sep 17 00:00:00 2001 From: wangcuijuan Date: Thu, 10 Oct 2024 10:17:25 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E8=A1=A5=E5=85=85package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/api-proxy/package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/api-proxy/package.json b/packages/api-proxy/package.json index 7b3bf79036..551b863f1f 100644 --- a/packages/api-proxy/package.json +++ b/packages/api-proxy/package.json @@ -48,7 +48,8 @@ "expo-clipboard": "~6.0.3", "react-native-device-info": "^10.13.2", "react-native-get-location": "^4.0.1", - "react-native-safe-area-context": "^4.10.1" + "react-native-safe-area-context": "^4.10.1", + "react-native-haptic-feedback": "^2.3.3" }, "peerDependenciesMeta": { "@react-native-async-storage/async-storage": { @@ -74,6 +75,9 @@ }, "expo-brightness": { "optional": true + }, + "react-native-haptic-feedback": { + "optional": true } } } From 78562766365c4c352bc96df6fb1a5075ce76043e Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Thu, 10 Oct 2024 10:35:16 +0800 Subject: [PATCH 10/13] [Fix]rn-ref-style array to object --- .../api/create-selector-query/rnNodesRef.js | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js b/packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js index 87977e03fe..d8d9eba21b 100644 --- a/packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js +++ b/packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js @@ -6,7 +6,6 @@ import { hump2dash, isArray } from '@mpxjs/utils' -import { StyleSheet } from 'react-native' const flushRefFns = (nodeInstances, fns, single) => { // wx的数据格式:对于具体方法接受到的回调传参,如果获取的 nodeRef 只有一个,那么只需要返回一条数据而不是数组,但是 exec 里面统一都是数组 @@ -61,8 +60,8 @@ const getMeasureProps = (measureProps = []) => { } const getDataset = (props) => { - return wrapFn((nodeRef, resolve) => { - props = nodeRef.props.current + return wrapFn((nodeInstance, resolve) => { + props = nodeInstance.props.current resolve({ dataset: collectDataset(props) }) @@ -70,9 +69,9 @@ const getDataset = (props) => { } const getPlainProps = (config) => { - return wrapFn((nodeRef, resolve) => { + return wrapFn((nodeInstance, resolve) => { const res = {} - const props = nodeRef.props.current + const props = nodeInstance.props.current config.forEach((key) => { // props 属性默认不转驼峰,用户写什么格式不会变化,取值做兼容 res[key] = props[key] || props[hump2dash(key)] || '' @@ -82,12 +81,15 @@ const getPlainProps = (config) => { } const getComputedStyle = (config = []) => { - return wrapFn((nodeRef, resolve) => { + return wrapFn((nodeInstance, resolve) => { config = new Set(config) const res = {} - const styles = nodeRef.props.current.style || [] - const defaultStyle = nodeRef.instance.defaultStyle || {} - const computedStyle = StyleSheet.flatten([defaultStyle, ...styles]) + const styles = nodeInstance.props.current.style || {} + const defaultStyle = nodeInstance.instance.defaultStyle || {} + const computedStyle = { + ...defaultStyle, + ...styles + } config.forEach((key) => { const humpKey = dash2hump(key) // 取 style 的 key 是根据传入的 key 来设置,传什么设置什么 key,只不过取值需要做兼容 @@ -99,8 +101,8 @@ const getComputedStyle = (config = []) => { } const getInstanceConfig = (config) => { - return wrapFn((nodeRef, resolve) => { - const instance = nodeRef.instance + return wrapFn((nodeInstance, resolve) => { + const instance = nodeInstance.instance resolve({ [config]: instance[config] || {} }) }) } @@ -113,8 +115,8 @@ const defaultScrollOffset = { } const getScrollOffset = () => { - return wrapFn((nodeRef, resolve) => { - const instance = nodeRef.instance + return wrapFn((nodeInstance, resolve) => { + const instance = nodeInstance.instance resolve( (instance.scrollOffset && instance.scrollOffset.current) || defaultScrollOffset From a6afd30775b3692ffa9000bdfb25d551d97b4dbd Mon Sep 17 00:00:00 2001 From: luyongfang Date: Thu, 10 Oct 2024 20:00:58 +0800 Subject: [PATCH 11/13] fix: eslint --- .../components/react/mpx-swiper/carouse.tsx | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx index a3e00bba8c..0111a94c11 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx @@ -116,27 +116,35 @@ const _Carouse = forwardRef, Carouse */ function updateIndex (scrollViewOffset: NativeScrollPoint, useIndex = false) { const { nextIndex, nextOffset } = getNextConfig(scrollViewOffset) - internalsRef.current.offset = nextOffset + updateState(nextIndex, nextOffset) + // 更新完状态之后, 开启新的loop + } + + /** + * 更新索引状态 + */ + function updateState (index: number, offset: { x: number, y: number}) { + internalsRef.current.offset = offset setState((preState) => { const newState = { ...preState, - index: nextIndex, + index: index, // offset用来指示当前scrollView的偏移量 - offset: nextOffset + offset: offset } return newState }) internalsRef.current.isScrolling = false // getCustomEvent - const eventData = getCustomEvent('change', {}, { detail: { current: nextIndex, source: 'touch' }, layoutRef: layoutRef }) + const eventData = getCustomEvent('change', {}, { detail: { current: index, source: 'touch' }, layoutRef: layoutRef }) props.bindchange && props.bindchange(eventData) - // 更新完状态之后, 开启新的loop } /** * @desc: 获取下一个位置的索引、scrollView的contentOffset、scrollTo到的offset * @desc: 包括正循环、反向循环、不循环 - * 其中循环模式为了实现无缝链接, 会将结合contentOffset, 和 scrollTo的offset, 先scrollTo一个位置的坐标, 然后通过updateIndex设置真正的index和内容的offset,视觉上是无缝 + * 其中循环模式为了实现无缝链接, 会将结合contentOffset, 和 scrollTo的offset, + * 先scrollTo一个位置的坐标, 然后通过updateIndex设置真正的index和内容的offset,视觉上是无缝 */ function getNextConfig (scrollViewOffset: NativeScrollPoint) { const step = state.dir === 'x' ? state.width : state.height @@ -181,8 +189,11 @@ const _Carouse = forwardRef, Carouse } } return { + // 下一个要滚动到的实际元素的索引 nextIndex, + // 下一个要滚动到实际元素的offset nextOffset, + // scrollTo一个位置的坐标, 虚拟元素的位置 autoMoveOffset, isAutoEnd } @@ -216,7 +227,6 @@ const _Carouse = forwardRef, Carouse } else { if (!isAutoEnd) { scrollViewRef.current?.scrollTo({ x: nextOffset.x, y: nextOffset.y, animated: true }) - // 这里包裹了一层contentOffset需要测试下 onScrollEnd({ nativeEvent: { contentOffset: { @@ -226,23 +236,14 @@ const _Carouse = forwardRef, Carouse } } as NativeSyntheticEvent) } else { - // 同上 - setTimeout(() => { - onScrollEnd({ - nativeEvent: { - contentOffset: { - x: 0, - y: 0 - } - } - } as NativeSyntheticEvent) - }, 10) + // 安卓无法实现视觉的无缝连接, 只能回到真正的位置, 且安卓调用scrollTo不能触发onMomentumScrollEnd,还未找到为啥 if (state.dir === 'x') { scrollViewRef.current?.scrollTo({ x: step, y: step, animated: true }) - // scrollViewRef.current?.scrollTo({ x: autoMoveOffset['x'], y: autoMoveOffset['x'], animated: true }) + // scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: autoMoveOffset.y, animated: true }) } else { - scrollViewRef.current?.scrollTo({ x: autoMoveOffset.y, y: autoMoveOffset.y, animated: true }) + scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: step, animated: true }) } + updateState(0, nextOffset) } } } From bda36068facf47894b3af1f382f8d89d16fea128 Mon Sep 17 00:00:00 2001 From: wangcuijuan Date: Thu, 10 Oct 2024 20:42:23 +0800 Subject: [PATCH 12/13] =?UTF-8?q?fix=20navigation.setOptions=20=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/set-navigation-bar/index.ios.js | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/api-proxy/src/platform/api/set-navigation-bar/index.ios.js b/packages/api-proxy/src/platform/api/set-navigation-bar/index.ios.js index 70e4b671ca..3f83c65f34 100644 --- a/packages/api-proxy/src/platform/api/set-navigation-bar/index.ios.js +++ b/packages/api-proxy/src/platform/api/set-navigation-bar/index.ios.js @@ -1,13 +1,15 @@ import { successHandle, failHandle, getFocusedNavigation } from '../../../common/js' - +import { nextTick } from '../next-tick' function setNavigationBarTitle (options = {}) { const { title = '', success, fail, complete } = options const navigation = getFocusedNavigation() if (!(navigation && navigation.setOptions)) { failHandle({ errMsg: 'setNavigationBarTitle:fail' }, fail, complete) } else { - navigation.setOptions({ headerTitle: title }) - successHandle({ errMsg: 'setNavigationBarTitle:ok' }, success, complete) + nextTick(() => { + navigation.setOptions({ headerTitle: title }) + successHandle({ errMsg: 'setNavigationBarTitle:ok' }, success, complete) + }) } } @@ -17,13 +19,15 @@ function setNavigationBarColor (options = {}) { if (!(navigation && navigation.setOptions)) { failHandle({ errMsg: 'setNavigationBarColor:fail' }, fail, complete) } else { - navigation.setOptions({ - headerStyle: { - backgroundColor: backgroundColor - }, - headerTintColor: frontColor + nextTick(() => { + navigation.setOptions({ + headerStyle: { + backgroundColor: backgroundColor + }, + headerTintColor: frontColor + }) + successHandle({ errMsg: 'setNavigationBarColor:ok' }, success, complete) }) - successHandle({ errMsg: 'setNavigationBarColor:ok' }, success, complete) } } From 72e0f6b89dc962d151993cc89fea0ed4e985258d Mon Sep 17 00:00:00 2001 From: luyongfang Date: Fri, 11 Oct 2024 14:30:15 +0800 Subject: [PATCH 13/13] fix: picker linear tsc --- package.json | 10 ++++-- .../react/mpx-picker-view-column.tsx | 24 +++++++++---- .../components/react/mpx-picker-view.tsx | 36 ++++++++++--------- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 41d831e2c9..cad1d9f705 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "@docsearch/js": "^3.0.0", "@testing-library/jest-dom": "^4.2.4", "@types/jest": "^27.0.1", + "@typescript-eslint/eslint-plugin": "^5.2.0", + "@typescript-eslint/parser": "^5.2.0", "@vuepress/plugin-back-to-top": "^1.8.2", "@vuepress/plugin-pwa": "^1.8.0", "eslint": "^7.32.0", @@ -30,8 +32,6 @@ "eslint-plugin-jest": "^27.0.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.1", - "@typescript-eslint/eslint-plugin": "^5.2.0", - "@typescript-eslint/parser": "^5.2.0", "identity-obj-proxy": "^3.0.0", "jest": "^27.2.0", "lerna": "^8.1.8", @@ -40,5 +40,9 @@ }, "workspaces": [ "packages/*" - ] + ], + "dependencies": { + "@types/react": "^18.3.11", + "react-native-linear-gradient": "^2.8.3" + } } diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx index 95070bbd6f..b641d76745 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx @@ -1,6 +1,6 @@ -import { View, Animated, SafeAreaView, NativeScrollEvent, NativeSyntheticEvent, Platform } from 'react-native' -import React, { forwardRef, useRef, useState, useEffect } from 'react' +import { View, Animated, SafeAreaView, NativeScrollEvent, NativeSyntheticEvent, LayoutChangeEvent, ScrollView } from 'react-native' +import React, { forwardRef, useRef, useState, useEffect, ReactElement } from 'react' // import { Reanimated } from 'react-native-reanimated'; import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 interface ColumnProps { @@ -18,7 +18,7 @@ interface ColumnProps { // 每个Column 都有个外层的高度, 内部的元素高度 // 默认的高度 // const AnimatedScrollView = Reanimated.createAnimatedComponent(ScrollView); -const _PickerViewColumn = forwardRef, ColumnProps>((props: ColumnProps, ref) => { +const _PickerViewColumn = forwardRef, ColumnProps>((props: ColumnProps, ref) => { const { children, selectedIndex, onColumnLayoutChange, onSelectChange, getInnerLayout, wrapperStyle } = props // scrollView的ref const { nodeRef: scrollViewRef } = useNodesRef(props, ref, {}) @@ -43,7 +43,7 @@ const _PickerViewColumn = forwardRef, ColumnProps> }) } - const onItemLayout = (e: NativeSyntheticEvent) => { + const onItemLayout = (e: LayoutChangeEvent) => { const layout = e.nativeEvent.layout if (layout.height && itemH !== layout.height) { itemH = layout.height @@ -62,7 +62,20 @@ const _PickerViewColumn = forwardRef, ColumnProps> const renderInnerchild = () => { // Fragment 节点 - const realChilds = Array.isArray(children) ? children : (children.props?.children && Array.isArray(children.props?.children) ? children.props.children : [children]) + const getRealChilds = () => { + if (Array.isArray(children)) { + return children + } else { + const tempChild = children as ReactElement + if (tempChild.props.children && tempChild.props.children) { + return tempChild.props.children + } else { + return [children] + } + } + } + // const realChilds = Array.isArray(children) ? children : (children?.props?.children && Array.isArray(children.props?.children) ? children.props.children : [children]) + const realChilds = getRealChilds() const arrChild = realChilds.map((item: React.ReactNode, index: number) => { const InnerProps = index === 0 ? { onLayout: onItemLayout } : {} const strKey = 'picker' + props.prefix + '-column' + index @@ -99,7 +112,6 @@ const _PickerViewColumn = forwardRef, ColumnProps> showsVerticalScrollIndicator={false} pagingEnabled={false} snapToInterval={itemH} - contentContainerStyle={contentContainerStyle} automaticallyAdjustContentInsets={false} onLayout={onScrollViewLayout} onMomentumScrollEnd={onMomentumScrollEnd}> diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx index 8b30fd45ba..1115248aae 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view.tsx @@ -1,6 +1,6 @@ import { View } from 'react-native' -import LinearGradient from 'react-native-linear-gradient' -import React, { forwardRef, MutableRefObject, useState, useRef } from 'react' +import { LinearGradient, LinearGradientProps } from 'react-native-linear-gradient' +import React, { forwardRef, MutableRefObject, useState, useRef, ReactElement, JSX } from 'react' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 /** @@ -80,16 +80,16 @@ const _PickerView = forwardRef, PickerViewProp const onSelectChange = (columnIndex: number, selIndex: number) => { const changeValue = value.slice() changeValue[columnIndex] = selIndex - const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef: {} }) + const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef: innerLayout }) bindchange && bindchange(eventData) } - + /* const onWrapperLayout = () => { wrapRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { const a = { x, y, width, height, offsetLeft, offsetTop } }) } - + */ const getInnerLayout = (layout: MutableRefObject<{}>) => { innerLayout.current = layout.current } @@ -99,7 +99,7 @@ const _PickerView = forwardRef, PickerViewProp const cloneChild = (child: React.ReactNode, index: number) => { const extraProps = index === 0 ? { getInnerLayout: getInnerLayout, innerProps } : {} const childProps = { - ...child?.props, + ...(child as ReactElement)?.props, ref: cloneRef, prefix: index, key: 'pick-view' + index, @@ -111,33 +111,37 @@ const _PickerView = forwardRef, PickerViewProp selectedIndex: value?.[index] || 0, ...extraProps } - return React.cloneElement(child, childProps) + return React.cloneElement(child as ReactElement, childProps) } const renderTopMask = () => { - return - + ] + } + return () } const renderBottomMask = () => { - return - + ] + } + return } const renderSubChild = () => { @@ -149,7 +153,7 @@ const _PickerView = forwardRef, PickerViewProp return cloneChild(children, 0) } } - return ( + return ( {renderTopMask()} {renderSubChild()}