赞
踩
本示例使用position绝对定位实现应用内悬浮窗,并且通过animateTo结合curves动画曲线实现悬浮窗拖拽跟手和松手吸附边缘的弹性动画效果。
使用说明
按住悬浮窗可以拖拽,松开后悬浮窗自动靠左或靠右,如果悬浮窗超出内容区上下边界,自动吸附在边界位置。
Stack({ alignContent: Alignment.Bottom }) { Video({ src: $rawfile('float_window_video.mp4'), controller: this.videoController }) .controls(false) .autoPlay(true) .loop(true) .muted(true) .width($r('app.string.float_window_full_size')) .onClick(() => { this.videoController.requestFullscreen(true); }) .borderRadius($r('app.string.ohos_id_corner_radius_default_l')) Text($r('app.string.float_window_live_text')) .width($r('app.string.float_window_full_size')) .fontSize($r('app.string.ohos_id_text_size_body1')) .fontColor($r('app.color.ohos_id_color_background')) .textAlign(TextAlign.Center) .backgroundColor($r('app.color.ohos_id_color_list_alert')) .borderRadius({ bottomLeft: $r('app.string.ohos_id_corner_radius_default_l'), bottomRight: $r('app.string.ohos_id_corner_radius_default_l') }) } .clip(true) .border({ width: $r('app.integer.float_window_border_width'), color: $r('app.color.ohos_id_color_background') }) .borderRadius($r('app.string.ohos_id_corner_radius_default_l')) .width(Constants.FLOAT_WINDOW_WIDTH) .height(Constants.FLOAT_WINDOW_HEIGHT) .backgroundColor($r('app.color.ohos_id_color_foreground')) .position({ x: this.positionX, y: this.positionY }) .onTouch((event: TouchEvent) => { this.onTouchEvent(event); })
try {
const properties = windowClass.getWindowProperties();
// 获取应用窗口宽高
this.windowRectWidth = px2vp(properties.windowRect.width);
this.windowRectHeight = px2vp(properties.windowRect.height)
// 窗口宽度减去悬浮窗宽度和右边距让悬浮窗初始靠右
this.positionX = this.windowRectWidth - Constants.FLOAT_WINDOW_WIDTH - Constants.PAGE_PADDING;
} catch (exception) {
logger.error(TAG, 'Failed to obtain the window properties. Cause: ' + JSON.stringify(exception));
}
try {
const avoidArea = windowClass.getWindowAvoidArea(type);
// 获取顶部状态栏高度
this.topRectHeight = px2vp(avoidArea.topRect.height);
// 获取底部导航栏高度
this.bottomRectHeight = px2vp(avoidArea.bottomRect.height);
} catch (exception) {
logger.error(TAG, 'Failed to obtain the area. Cause:' + JSON.stringify(exception));
}
case TouchType.Down: {
this.offsetX = event.touches[0].x;
this.offsetY = event.touches[0].y;
break;
}
case TouchType.Move: {
const windowX: number = event.touches[0].windowX;
const windowY: number = event.touches[0].windowY;
// TODO:知识点:跟手动画,推荐使用默认参数的弹性跟手动画曲线curves.responsiveSpringMotion。
animateTo({ curve: curves.responsiveSpringMotion() }, () => {
this.positionX = windowX - this.offsetX - Constants.PAGE_PADDING;
this.positionY = windowY - this.offsetY - this.topRectHeight - Constants.PAGE_PADDING; // 减去手指位置到悬浮窗左上角的y轴偏移和设备顶部状态栏高度
})
break;
}
case TouchType.Up: { // TODO:知识点:通过判断悬浮窗在窗口中的位置,设置悬浮窗贴边,使用curves.springMotion()弹性动画曲线,可以实现阻尼动画效果 animateTo({ curve: curves.springMotion() }, () => { // 判断悬浮窗中心在水平方向是否超过窗口宽度的一半,根据结果设置靠左或靠右 if (this.positionX > (this.windowRectWidth - Constants.FLOAT_WINDOW_WIDTH) / 2) { this.positionX = this.windowRectWidth - Constants.FLOAT_WINDOW_WIDTH - Constants.PAGE_PADDING; // 悬浮窗靠右 } else { this.positionX = Constants.PAGE_PADDING; // 悬浮窗靠左 } // 页面高度 const pageHeight: number = this.windowRectHeight - this.topRectHeight - this.bottomRectHeight; // 判断悬浮窗是否超出内容区上下边界,根据结果将悬浮窗设置在边界位置 if (this.positionY < Constants.PAGE_PADDING) { this.positionY = Constants.PAGE_PADDING; } else if (this.positionY > pageHeight - Constants.FLOAT_WINDOW_HEIGHT - Constants.PAGE_PADDING) { this.positionY = pageHeight - Constants.FLOAT_WINDOW_HEIGHT - Constants.PAGE_PADDING; } }) break; }
不涉及
floatwindow // har类型
|---/src/main/ets/common
| |---Constants.ets // 常量
|---/src/main/ets/pages
| |---FloatWindowMainPage.ets // 视图层-悬浮窗首页
@ohos.curves (插值计算)
为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr18.cn/F781PH
https://qr18.cn/F781PH
1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。