文档管理中心

旋转验证码效果实现

问题现象

如何实现旋转验证码的效果,具体演示如下图所示:

背景知识

  • rotate是一种组件通用属性,用于设置组件的旋转,使用时传入一个RotationOptions类对象,属性说明如下:
    展开

    名称

    说明

    centerX

    表示变换中心点x轴坐标(单位:vp)

    centerY

    表示变换中心点y轴坐标(单位:vp)

    angle

    表示旋转角度(取值可为string类型,如'90deg')

  • onTouch是一种组件通用事件。当手指在组件上按下、滑动、抬起时会触发该事件。

解决方案

  1. 给Circle组件添加onTouch事件:
    • 当TouchType为Down时,获取图片初始位置startPosition。
    • 当TouchType为Move时,实时获取组件位置updatePosition,并通过calculateAngleBetweenPoints方法计算图片旋转的角度。
  2. 定义变量rotateAngle表示图片旋转的角度值,该变量的值由上述方法获得,并将之赋值给Image的rotate属性即可。

完整示例参考如下:

收起
自动换行
深色代码主题
复制
  1. import display from '@ohos.display';
  2. import { promptAction } from '@kit.ArkUI';
  3. @Entry
  4. @Component
  5. struct RotatingCodePage {
  6. @State startRotates: number = 0;
  7. @State updateRotates: number = 0;
  8. @State rotateAngle: number = -90;
  9. @State startPosition: Position = {};
  10. @State updatePosition: Position = {};
  11. // 图片中心点坐标
  12. @State circleCenterPoint: Position = {};
  13. private screenH: number = 0;
  14. private screenW: number = 0;
  15. aboutToAppear(): void {
  16. let displayClass: display.Display | null = null;
  17. displayClass = display.getDefaultDisplaySync();
  18. this.screenH = this.getUIContext().px2vp(displayClass.height);
  19. this.screenW = this.getUIContext().px2vp(displayClass.width);
  20. this.circleCenterPoint = { x: this.screenW / 2, y: this.screenH / 2 };
  21. }
  22. build() {
  23. Column({ space: 20 }) {
  24. Stack() {
  25. // 开发者可在这自定义图片
  26. Image($r('app.media.startIcon'))
  27. .width(100)
  28. .height(100)
  29. .objectFit(ImageFit.Contain)
  30. .rotate({
  31. // 设置旋转的中心点为组件的中心
  32. centerX: '50%',
  33. centerY: '50%',
  34. angle: this.rotateAngle
  35. });
  36. Circle()
  37. .width(300)
  38. .height(300)
  39. .fillOpacity(0)
  40. .strokeWidth(2)
  41. .stroke('#0A59f7')
  42. .onTouch((event: TouchEvent) => {
  43. if (event.type === TouchType.Down) {
  44. this.updateRotates = 0;
  45. this.startRotates = this.rotateAngle;
  46. this.startPosition = { x: event.touches[0].windowX, y: event.touches[0].windowY };
  47. } else if (event.type === TouchType.Move) {
  48. this.updatePosition = { x: event.touches[0].windowX, y: event.touches[0].windowY };
  49. // 手指移动时的角度
  50. this.updateRotates =
  51. calculateAngleBetweenPoints(this.circleCenterPoint, this.startPosition, this.updatePosition);
  52. }
  53. this.rotateAngle = this.updateRotates + this.startRotates;
  54. if (this.rotateAngle > -2 && this.rotateAngle < 2) {
  55. promptAction.openToast({
  56. message: '验证成功'
  57. });
  58. }
  59. });
  60. }
  61. .hitTestBehavior(HitTestMode.Transparent);
  62. Text('长按拖拽画面,使图片正立');
  63. }
  64. .alignItems(HorizontalAlign.Center)
  65. .justifyContent(FlexAlign.Center)
  66. .width('100%')
  67. .height('100%');
  68. }
  69. }
  70. function atanToDegrees(atanResult: number) {
  71. const degrees = atanResult * (180 / Math.PI);
  72. return degrees;
  73. }
  74. function calculateAngleBetweenPoints(p0: Position = { x: 0, y: 0 }, p1: Position = { x: 0, y: 0 },
  75. p2: Position = { x: 0, y: 0 }): number {
  76. const startY = Number(p1.y) - Number(p0.y);
  77. const startX = Number(p1.x) - Number(p0.x);
  78. // 通过反正切函数得到的弧度值
  79. const startRadians: number = Math.atan2(startY, startX);
  80. // 相对于正x轴,角度范围是0到360度
  81. const startDeg = atanToDegrees(startRadians);
  82. const endY = Number(p2.y) - Number(p0.y);
  83. const endX = Number(p2.x) - Number(p0.x);
  84. const endRadians: number = Math.atan2(endY, endX);
  85. const endDeg = atanToDegrees(endRadians);
  86. return endDeg - startDeg;
  87. }
在 FAQ 中进行搜索
请输入您想要搜索的关键词