fix(android): return size after loading gif (#3001)

* fix(android): return size after loading gif

* fix(vue, vue-next): handle onLoadEnd params

* Revert "fix(vue, vue-next): handle onLoadEnd params"

This reverts commit 52aae10130.

* fix(android): return image size using onLoad

* fix(img): update demo about onLoad usage

* docs(img): update doc about onLoad usage

* fix(demo): modify attribute name

* fix(android): change if condition order

* fix(vue, vue-next): handle onLoadEnd params

* fix(vue, vue-next): remove unexpected events

* fix(vue, vue-next): modify code expression

* feat(react): update gif onLoad

* feat(vue, vue-next): update demo expression

---------

Co-authored-by: andrezhuang <andrezhuang@tencent.com>
This commit is contained in:
Xuanquan Zhuang
2023-03-16 17:30:31 +08:00
committed by zoomchan-cxj
co-authored by andrezhuang
parent 9c2d0bfb6c
commit 28fdfa925f
10 changed files with 216 additions and 97 deletions
@@ -351,7 +351,21 @@ public class HippyImageView extends AsyncImageView implements CommonBorder, Hipp
protected void handleGetImageSuccess() {
// send onLoad event
if (mShouldSendImageEvent[ImageEvent.ONLOAD.ordinal()]) {
getOnLoadEvent().send(this, null);
HippyMap map = new HippyMap();
if (mSourceDrawable != null) {
if (mSourceDrawable instanceof HippyDrawable) {
HippyDrawable hippyTarget = (HippyDrawable) mSourceDrawable;
map.pushInt("width", hippyTarget.getWidth());
map.pushInt("height", hippyTarget.getHeight());
map.pushString("url", mUrl != null ? mUrl : "");
} else if (mSourceDrawable.getBitmap() != null) {
Bitmap bitmap = mSourceDrawable.getBitmap();
map.pushInt("width", bitmap.getWidth());
map.pushInt("height", bitmap.getHeight());
map.pushString("url", mUrl != null ? mUrl : "");
}
}
getOnLoadEvent().send(this, map);
}
// send onLoadEnd event
if (mShouldSendImageEvent[ImageEvent.ONLOAD_END.ordinal()]) {
+11 -11
View File
@@ -194,17 +194,17 @@ Image component, same as browser.
## Events
| Event Name | Description | Type | Supported Platforms |
| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- |
| layout | Called when an element is mounted or the layout changes. The argument is: `nativeEvent: { layout: { x, y, width, height } }`, where `x` and `y` are coordinates relative to the parent element | `Function` | `Android、iOS、Web-Renderer` |
| load | Called when the web page is successfully loaded | `Function` | `Android、iOS、Web-Renderer` |
| loadStart | Called when the web page starts loading | `Function` | `Android、iOS、Web-Renderer` |
| loadEnd | After loading, whether it successes or nor, this callback function is called with or without success | `Function` | `Android、iOS、Web-Renderer` |
| error | Called when loading errors occur.| `Function` | `Android、iOS、Web-Renderer` |
| progress | In the process of loading calls, parameters `nativeEvent: { loaded: number, total: number }`, `loaded` indicate the size of the loading image, `total` indicates the total size of the image. | `iOS` |
| touchstart | Called when screen touch starts, minimum supported version 2.6.2, the parameters are `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` and `clientY` respectively represent the absolute position of the click within the screen. | `Function` | `Android、iOS、Web-Renderer` |
| touchmove | Called when screen touch moves, minimum supported version 2.6.2, the parameters are `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` and `clientY` respectively represent the absolute position of the click within the screen. | `Function` | `Android、iOS、Web-Renderer` |
| touchend | Called when screen touch ends, minimum supported version 2.6.2, the parameters are `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` and `clientY` respectively represent the absolute position of the click within the screen. | `Function` | `Android、iOS、Web-Renderer` |
| Event Name | Description | Type | Supported Platforms |
| ------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------------------------------- | -------- |
| layout | Called when an element is mounted or the layout changes. The argument is: `nativeEvent: { layout: { x, y, width, height } }`, where `x` and `y` are coordinates relative to the parent element | `Function` | `Android、iOS、Web-Renderer` |
| load | Called when the image is successfully loaded. Argument will be returned after version `2.16.0`, which is `evt: { width: number, height: number, url: string }` | `Function` | `Android、iOS、Web-Renderer` |
| loadStart | Called when the image starts loading | `Function` | `Android、iOS、Web-Renderer` |
| loadEnd | After loading, whether it successes or nor, this callback function is called with or without success | `Function` | `Android、iOS、Web-Renderer` |
| error | Called when loading errors occur. | `Function` | `Android、iOS、Web-Renderer` |
| progress | In the process of loading calls, parameters `nativeEvent: { loaded: number, total: number }`, `loaded` indicate the size of the loading image, `total` indicates the total size of the image. | `iOS` |
| touchstart | Called when screen touch starts, minimum supported version 2.6.2, the parameters are `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` and `clientY` respectively represent the absolute position of the click within the screen. | `Function` | `Android、iOS、Web-Renderer` |
| touchmove | Called when screen touch moves, minimum supported version 2.6.2, the parameters are `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` and `clientY` respectively represent the absolute position of the click within the screen. | `Function` | `Android、iOS、Web-Renderer` |
| touchend | Called when screen touch ends, minimum supported version 2.6.2, the parameters are `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` and `clientY` respectively represent the absolute position of the click within the screen. | `Function` | `Android、iOS、Web-Renderer` |
| touchcancel | Called when screen touch cancels. When a system event interrupts the touch screen when the user touches the screen, such as an incoming phone call, a component change (e.g., set to hidden), or a sliding gesture of another component, this function will receive a callback. The minimum supported version is 2.6.2. The parameters are `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` and `clientY` respectively represent the absolute position of the click on the screen. | `Function` | `Android、iOS、Web-Renderer` |
---
+1 -1
View File
@@ -51,7 +51,7 @@ import icon from './qb_icon_new.png';
| source | uri 是一个表示图片的资源标识的字符串。 现在支持的图片格式有 `png` , `jpg` , `jpeg` , `bmp` , `gif` 。 | `{ uri: string }` | `Android、iOS、hippy-react-web、Web-Renderer` |
| tintColor | 对图片进行染色(对非纯色图片进行有透明度的染色时,Android 和 iOS 的 `blendMode` 默认值有差异)。 | [color](style/color.md) | `Android、iOS、Web-Renderer`|
| onLayout | 当元素挂载或者布局改变的时候调用,参数为: `nativeEvent: { layout: { x, y, width, height } }`,其中 `x` 和 `y` 为相对父元素的坐标位置 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onLoad | 加载成功完成时调用此回调函数。 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onLoad | 加载成功完成时调用此回调函数,`2.16.0`后支持参数返回,参数为:`nativeEvent: { width: number, height: number, url: string }` | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onLoadStart | 加载开始时调用。 例如, `onLoadStart={() => this.setState({ loading: true })}` | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onLoadEnd | 加载结束后,不论成功还是失败,调用此回调函数。 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| resizeMode | 决定当组件尺寸和图片尺寸不成比例的时候如何调整图片的大小。`注意:hippy-react-web、Web-Renderer 不支持 repeat` | `enum (cover, contain, stretch, repeat, center)` | `Android、iOS、hippy-react-web、Web-Renderer` |
+11 -11
View File
@@ -194,17 +194,17 @@
## 事件
| 事件名称 | 描述 | 类型 | 支持平台 |
| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- |
| layout | 当元素挂载或者布局改变的时候调用,参数为: `nativeEvent: { layout: { x, y, width, height } }`,其中 `x` 和 `y` 为相对父元素的坐标位置 | `Function` | `Android、iOS、Web-Renderer` |
| load | 加载成功完成时调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer` |
| loadStart | 加载开始时调用。 | `Function` | `Android、iOS、Web-Renderer` |
| loadEnd | 加载结束后,不论成功还是失败,调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer` |
| error | 当加载错误的时候调用此回调函数。| `Function` | `Android、iOS、Web-Renderer` |
| progress | 在加载过程中不断调用,参数为 `nativeEvent: { loaded: number, total: number }`, `loaded` 表示加载中的图片大小, `total` 表示图片总大小 | `Function` | `iOS` |
| touchstart | 触屏开始事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer` |
| touchmove | 触屏移动事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer` |
| touchend | 触屏结束事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer` |
| 事件名称 | 描述 | 类型 | 支持平台 |
| ------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------------------------------- | -------- |
| layout | 当元素挂载或者布局改变的时候调用,参数为: `nativeEvent: { layout: { x, y, width, height } }`,其中 `x` 和 `y` 为相对父元素的坐标位置 | `Function` | `Android、iOS、Web-Renderer` |
| load | 加载成功完成时调用此回调函数,`2.16.0`后支持参数返回,参数为:`evt: { width: number, height: number, url: string }` | `Function` | `Android、iOS、Web-Renderer` |
| loadStart | 加载开始时调用。 | `Function` | `Android、iOS、Web-Renderer` |
| loadEnd | 加载结束后,不论成功还是失败,调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer` |
| error | 当加载错误的时候调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer` |
| progress | 在加载过程中不断调用,参数为 `nativeEvent: { loaded: number, total: number }`, `loaded` 表示加载中的图片大小, `total` 表示图片总大小 | `Function` | `iOS` |
| touchstart | 触屏开始事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer` |
| touchmove | 触屏移动事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer` |
| touchend | 触屏结束事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer` |
| touchcancel | 触屏取消事件,当用户触屏过程中,某个系统事件中断了触屏,例如电话呼入、组件变化(如设置为hidden)、其他组件的滑动手势,此函数会收到回调,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer` |
---
@@ -33,75 +33,94 @@ const styles = StyleSheet.create({
},
});
export default function ImageExpo() {
return (
<ScrollView style={styles.container_style}>
<Text style={styles.info_style}>Contain:</Text>
<Image
style={[styles.image_style]}
resizeMode={Image.resizeMode.contain}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
onProgress={(e) => {
console.log('onProgress', e);
}}
onLoadStart={() => {
console.log('image onloadStart');
}}
onLoad={() => {
console.log('image onLoad');
}}
onError={(e) => {
console.log('image onError', e);
}}
onLoadEnd={() => {
console.log('image onLoadEnd');
}}
/>
<Text style={styles.info_style}>Cover:</Text>
<Image
style={[styles.image_style]}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
resizeMode={Image.resizeMode.cover}
/>
<Text style={styles.info_style}>Center:</Text>
<Image
style={[styles.image_style]}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
resizeMode={Image.resizeMode.center}
/>
<Text style={styles.info_style}>CapInsets:</Text>
<Image
style={[styles.image_style]}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
capInsets={{
top: 50,
left: 50,
bottom: 50,
right: 50,
}}
resizeMode={Image.resizeMode.cover}
/>
<Text style={styles.info_style}>TintColor:</Text>
<Image
style={[styles.image_style, { tintColor: '#4c9afa99' }]}
defaultSource={defaultSource}
source={{ uri: HippyLogoImg }}
resizeMode={Image.resizeMode.center}
/>
<Text style={styles.info_style}>Cover GIF:</Text>
<Image
style={[styles.image_style]}
resizeMode={Image.resizeMode.cover}
defaultSource={defaultSource}
source={{ uri: 'https://user-images.githubusercontent.com/12878546/148736255-7193f89e-9caf-49c0-86b0-548209506bd6.gif' }}
onLoadEnd={() => {
console.log('gif onLoadEnd');
}}
/>
</ScrollView>
);
export default class ImageExpo extends React.Component {
constructor(props) {
super(props);
this.state = {
gifLoadResult: {},
};
}
render() {
const { width: gifWidth, height: gifHeight, url: gifUrl } = this.state.gifLoadResult;
return (
<ScrollView style={styles.container_style}>
<Text style={styles.info_style}>Contain:</Text>
<Image
style={[styles.image_style]}
resizeMode={Image.resizeMode.contain}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
onProgress={(e) => {
console.log('onProgress', e);
}}
onLoadStart={() => {
console.log('image onloadStart');
}}
onLoad={() => {
console.log('image onLoad');
}}
onError={(e) => {
console.log('image onError', e);
}}
onLoadEnd={() => {
console.log('image onLoadEnd');
}}
/>
<Text style={styles.info_style}>Cover:</Text>
<Image
style={[styles.image_style]}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
resizeMode={Image.resizeMode.cover}
/>
<Text style={styles.info_style}>Center:</Text>
<Image
style={[styles.image_style]}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
resizeMode={Image.resizeMode.center}
/>
<Text style={styles.info_style}>CapInsets:</Text>
<Image
style={[styles.image_style]}
defaultSource={defaultSource}
source={{ uri: imageUrl }}
capInsets={{
top: 50,
left: 50,
bottom: 50,
right: 50,
}}
resizeMode={Image.resizeMode.cover}
/>
<Text style={styles.info_style}>TintColor:</Text>
<Image
style={[styles.image_style, { tintColor: '#4c9afa99' }]}
defaultSource={defaultSource}
source={{ uri: HippyLogoImg }}
resizeMode={Image.resizeMode.center}
/>
<Text style={styles.info_style}>Cover GIF:</Text>
<Image
style={[styles.image_style]}
resizeMode={Image.resizeMode.cover}
defaultSource={defaultSource}
source={{ uri: 'https://user-images.githubusercontent.com/12878546/148736255-7193f89e-9caf-49c0-86b0-548209506bd6.gif' }}
onLoad={(result) => {
console.log(`gif onLoad result: ${result}`);
const { width, height, url } = result;
this.setState({
gifLoadResult: {
width,
height,
url,
},
});
}}
/>
<Text style={styles.info_style}>{ `gifLoadResult: { width: ${gifWidth}, height: ${gifHeight}, url: ${gifUrl} }` }</Text>
</ScrollView>
);
}
}
@@ -44,7 +44,9 @@
:placeholder="defaultImage"
src="https://user-images.githubusercontent.com/12878546/148736255-7193f89e-9caf-49c0-86b0-548209506bd6.gif"
class="image cover"
@load="onLoad"
>
<p>{{ gifLoadResult }}</p>
</div>
</div>
</template>
@@ -57,6 +59,7 @@ export default {
return {
defaultImage,
hippyLogoImage,
gifLoadResult: {},
};
},
methods: {
@@ -77,6 +80,15 @@ export default {
evt.stopPropagation();
console.log(evt);
},
onLoad(evt) {
console.log('onLoad', evt);
const { width, height, url } = evt;
this.gifLoadResult = {
width,
height,
url,
};
},
},
};
</script>
@@ -48,12 +48,14 @@
:placeholder="defaultImage"
src="https://user-images.githubusercontent.com/12878546/148736255-7193f89e-9caf-49c0-86b0-548209506bd6.gif"
class="image cover"
@load="onLoad"
>
<p>{{gifLoadResult}}</p>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from '@vue/runtime-core';
import { defineComponent, ref } from '@vue/runtime-core';
import defaultImage from '../../assets/defaultSource.jpg';
import hippyLogoImage from '../../assets/hippyLogoWhite.png';
@@ -77,13 +79,26 @@ export default defineComponent({
evt.stopPropagation();
console.log(evt);
};
const onLoad = (evt: Event) => {
console.log('onLoad', evt);
const { width, height, url } = evt;
gifLoadResult.value = {
width,
height,
url,
};
};
const gifLoadResult = ref({});
return {
defaultImage,
hippyLogoImage,
gifLoadResult,
onTouchEnd,
onTouchMove,
onTouchStart,
onLoad,
};
},
});
@@ -163,7 +163,36 @@ const img: ElementComponent = {
component: {
name: NATIVE_COMPONENT_MAP.Image,
eventNamesMap: div.component.eventNamesMap,
processEventData: div.component.processEventData,
processEventData(evtData: EventsUnionType, nativeEventParams: NeedToTyped) {
const { handler: event, __evt: nativeEventName } = evtData;
switch (nativeEventName) {
case 'onTouchDown':
case 'onTouchMove':
case 'onTouchEnd':
case 'onTouchCancel':
event.touches = {
0: {
clientX: nativeEventParams.page_x,
clientY: nativeEventParams.page_y,
},
length: 1,
};
break;
case 'onFocus':
event.isFocused = nativeEventParams.focus;
break;
case 'onLoad': {
const { width, height, url } = nativeEventParams;
event.width = width;
event.height = height;
event.url = url;
break;
}
default:
}
return event;
},
defaultNativeStyle: {
backgroundColor: 0,
},
@@ -150,6 +150,8 @@ export class HippyLoadResourceEvent extends HippyEvent {
public url?: string;
public success?: boolean;
public error?: string;
public width?: number;
public height?: number;
}
export class HippyKeyboardEvent extends HippyEvent {
@@ -179,6 +179,34 @@ const img = {
},
...accessibilityAttrMaps,
},
processEventData(event, nativeEventName, nativeEventParams) {
switch (nativeEventName) {
case 'onTouchDown':
case 'onTouchMove':
case 'onTouchEnd':
case 'onTouchCancel':
event.touches = {
0: {
clientX: nativeEventParams.page_x,
clientY: nativeEventParams.page_y,
},
length: 1,
};
break;
case 'onFocus':
event.isFocused = nativeEventName.focus;
break;
case 'onLoad': {
const { width, height, url } = nativeEventParams;
event.width = width;
event.height = height;
event.url = url;
break;
}
default:
}
return event;
},
},
};