MainView.ets 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. import curves from '@ohos.curves'
  2. import { AddFormMenuItem } from '@kit.ArkUI'
  3. import { formBindingData } from '@kit.FormKit'
  4. import { getCount, IBestToast } from 'basic'
  5. @Component
  6. export struct MainView {
  7. @Prop displayArr: getCount[] = []
  8. columnsTemplate: string = '1fr 1fr'
  9. @BuilderParam item: () => void
  10. private columnsCount: number = 0
  11. @State private dragItemId: number = -1
  12. @State private scaleItemId: number = -1
  13. @State private offsetX: number = 0
  14. @State private offsetY: number = 0
  15. private dragRefOffsetx: number = 0
  16. private dragRefOffsety: number = 0
  17. private FIX_VP_X: number = 108
  18. private FIX_VP_Y: number = 120
  19. aboutToAppear() {
  20. const temArr: number[] = Array.from({ length: 11 })
  21. temArr.forEach((item, index) => {
  22. this.displayArr.push({ id: index })
  23. })
  24. this.columnsCount = this.columnsTemplate.split(' ').length
  25. }
  26. itemMove(index: number, newIndex: number): void {
  27. if (!this.isDraggable(newIndex)) {
  28. return;
  29. }
  30. // 创建临时数组
  31. const newNumbers = [...this.displayArr];
  32. const movedItem = newNumbers.splice(index, 1)[0]; // 直接获取数组第一个元素
  33. newNumbers.splice(newIndex, 0, movedItem);
  34. this.displayArr = newNumbers;
  35. }
  36. //向下滑
  37. down(index: number): void {
  38. // 指定固定GridItem不响应事件
  39. if (!this.isDraggable(index + this.columnsCount)) {
  40. return
  41. }
  42. this.offsetY -= this.FIX_VP_Y
  43. this.dragRefOffsety += this.FIX_VP_Y
  44. this.itemMove(index, index + this.columnsCount)
  45. }
  46. //向下滑(右下角为空)
  47. // down2(index: number): void {
  48. // if (!this.isDraggable(index + this.columnsCount)) {
  49. // return
  50. // }
  51. // this.offsetY -= this.FIX_VP_Y
  52. // this.dragRefOffsety += this.FIX_VP_Y
  53. // this.itemMove(index, index + this.columnsCount)
  54. // }
  55. //向上滑
  56. up(index: number): void {
  57. if (!this.isDraggable(index - this.columnsCount)) {
  58. return
  59. }
  60. this.offsetY += this.FIX_VP_Y
  61. this.dragRefOffsety -= this.FIX_VP_Y
  62. this.itemMove(index, index - this.columnsCount)
  63. }
  64. //向左滑
  65. left(index: number): void {
  66. if (!this.isDraggable(index - 1)) {
  67. return
  68. }
  69. this.offsetX += this.FIX_VP_X
  70. this.dragRefOffsetx -= this.FIX_VP_X
  71. this.itemMove(index, index - 1)
  72. }
  73. //向右滑
  74. right(index: number): void {
  75. if (!this.isDraggable(index + 1)) {
  76. return
  77. }
  78. this.offsetX -= this.FIX_VP_X
  79. this.dragRefOffsetx += this.FIX_VP_X
  80. this.itemMove(index, index + 1)
  81. }
  82. //向右下滑
  83. lowerRight(index: number): void {
  84. if (!this.isDraggable(index + this.columnsCount + 1)) {
  85. return
  86. }
  87. this.offsetX -= this.FIX_VP_X
  88. this.dragRefOffsetx += this.FIX_VP_X
  89. this.offsetY -= this.FIX_VP_Y
  90. this.dragRefOffsety += this.FIX_VP_Y
  91. this.itemMove(index, index + this.columnsCount + 1)
  92. }
  93. //向右上滑
  94. upperRight(index: number): void {
  95. if (!this.isDraggable(index - this.columnsCount + 1)) {
  96. return
  97. }
  98. this.offsetX -= this.FIX_VP_X
  99. this.dragRefOffsetx += this.FIX_VP_X
  100. this.offsetY += this.FIX_VP_Y
  101. this.dragRefOffsety -= this.FIX_VP_Y
  102. this.itemMove(index, index - this.columnsCount + 1)
  103. }
  104. //向左下滑
  105. lowerLeft(index: number): void {
  106. if (!this.isDraggable(index + 2)) {
  107. return
  108. }
  109. this.offsetX += this.FIX_VP_X
  110. this.dragRefOffsetx -= this.FIX_VP_X
  111. this.offsetY -= this.FIX_VP_Y
  112. this.dragRefOffsety += this.FIX_VP_Y
  113. this.itemMove(index, index + this.columnsCount - 1)
  114. }
  115. //向左上滑
  116. upperLeft(index: number): void {
  117. if (!this.isDraggable(index - this.columnsCount - 1)) {
  118. return
  119. }
  120. this.offsetX += this.FIX_VP_X
  121. this.dragRefOffsetx -= this.FIX_VP_X
  122. this.offsetY += this.FIX_VP_Y
  123. this.dragRefOffsety -= this.FIX_VP_Y
  124. this.itemMove(index, index - this.columnsCount - 1)
  125. }
  126. isDraggable(index: number): boolean {
  127. return index >= 0 && index < this.displayArr.length
  128. }
  129. build() {
  130. Column() {
  131. Grid() {
  132. ForEach(this.displayArr, (item: getCount, index) => {
  133. GridItem() {
  134. Text(item + '')
  135. .fontSize(16)
  136. .width('100%')
  137. .height('100%')
  138. .bindContextMenu(
  139. this.menu_4,
  140. ResponseType.LongPress, {
  141. placement: Placement.TopLeft,
  142. })
  143. .textAlign(TextAlign.Center)
  144. .borderRadius(10)
  145. .backgroundColor(0xF9CF93)
  146. .shadow(this.scaleItemId == item.id ? {
  147. radius: 70,
  148. color: '#15000000',
  149. offsetX: 0,
  150. offsetY: 0
  151. } :
  152. {
  153. radius: 0,
  154. color: '#15000000',
  155. offsetX: 0,
  156. offsetY: 0
  157. })
  158. .animation({ curve: Curve.Sharp, duration: 300 })
  159. // this.item()
  160. }
  161. .aspectRatio(1)
  162. // 指定固定GridItem不响应事件
  163. .hitTestBehavior(this.isDraggable(this.displayArr.indexOf(item)) ? HitTestMode.Default : HitTestMode.None)
  164. .scale({ x: this.scaleItemId == item.id ? 1.05 : 1, y: this.scaleItemId == item.id ? 1.05 : 1 })
  165. .zIndex(this.dragItemId === item.id ? 1 : 0)
  166. .translate(this.dragItemId === item.id ? { x: this.offsetX, y: this.offsetY } : { x: 0, y: 0 })
  167. .onAreaChange((_, newArea) => {
  168. if (index == 0) {
  169. this.FIX_VP_X = newArea.width as number
  170. this.FIX_VP_Y = newArea.height as number
  171. }
  172. })
  173. .gesture(
  174. // 以下组合手势为顺序识别,当长按手势事件未正常触发时则不会触发拖动手势事件
  175. GestureGroup(GestureMode.Sequence,
  176. LongPressGesture({ repeat: true })
  177. .onAction((event?: GestureEvent) => {
  178. animateTo({ curve: Curve.Friction, duration: 300 }, () => {
  179. this.scaleItemId = item.id
  180. })
  181. })
  182. .onActionEnd(() => {
  183. animateTo({ curve: Curve.Friction, duration: 300 }, () => {
  184. this.scaleItemId = -1
  185. })
  186. }),
  187. PanGesture({ fingers: 1, direction: null, distance: 0 })
  188. .onActionStart(() => {
  189. this.dragItemId = item.id
  190. this.dragRefOffsetx = 0
  191. this.dragRefOffsety = 0
  192. })
  193. .onActionUpdate((event: GestureEvent) => {
  194. this.offsetY = event.offsetY - this.dragRefOffsety
  195. this.offsetX = event.offsetX - this.dragRefOffsetx
  196. let index = this.displayArr.findIndex(item => item.id == this.dragItemId)
  197. if (this.offsetY >= this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44) &&
  198. !this.isLastRow(index)) {
  199. //向下滑
  200. this.down(index)
  201. } else if (this.offsetY <= -this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44) &&
  202. !this.isFirstRow(index)) {
  203. //向上滑
  204. this.up(index)
  205. } else if (this.offsetX >= this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50) &&
  206. !this.isLastColumn(index)) {
  207. //向右滑
  208. this.right(index)
  209. } else if (this.offsetX <= -this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50) &&
  210. !this.isFirstColumn(index)) {
  211. //向左滑
  212. this.left(index)
  213. } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 &&
  214. !this.isLastRow(index) && !this.isLastColumn(index)) {
  215. //向右下滑
  216. this.lowerRight(index)
  217. } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2 &&
  218. !this.isFirstRow(index) && !this.isLastColumn(index)) {
  219. //向右上滑
  220. this.upperRight(index)
  221. } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 &&
  222. !this.isLastRow(index) && !this.isFirstColumn(index)) {
  223. //向左下滑
  224. this.lowerLeft(index)
  225. } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2 &&
  226. !this.isFirstRow(index) && !this.isFirstColumn(index)) {
  227. //向左上滑
  228. this.upperLeft(index)
  229. } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 &&
  230. this.isLastRow(index) && this.isFirstColumn(index)) {
  231. //右下角为空的情况
  232. this.down(index)
  233. }
  234. })
  235. .onActionEnd(() => {
  236. animateTo({ curve: Curve.Linear, duration: 150 }, () => { // 缩短时间并简化曲线
  237. this.dragItemId = -1;
  238. });
  239. })
  240. )
  241. .onCancel(() => {
  242. animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
  243. this.dragItemId = -1;
  244. })
  245. animateTo({
  246. curve: curves.interpolatingSpring(14, 1, 170, 17)
  247. }, () => {
  248. this.scaleItemId = -1
  249. })
  250. })
  251. )
  252. })
  253. }
  254. .width('100%')
  255. .editMode(true)
  256. .columnsGap(20)
  257. .rowsGap(20)
  258. .scrollBar(BarState.Off)
  259. .columnsTemplate(this.columnsTemplate)
  260. }.width('100%').height('100%').backgroundColor('#0D182431').padding({ top: 5 })
  261. }
  262. @Builder
  263. menu_4() {
  264. this.basicMenu('card_4', 4, 'fuWidget')
  265. }
  266. @Builder
  267. basicMenu(compId: string, form_dimension: number, form_name: string) {
  268. Menu() {
  269. AddFormMenuItem(
  270. {
  271. bundleName: 'com.ytpm.xjlrl', // 包名
  272. abilityName: 'EntryFormAbility', // 模块ability名称
  273. parameters: {
  274. 'ohos.extra.param.key.form_dimension': form_dimension, // 卡片尺寸,1代表1*2卡片,2代表2*2卡片,3代表2*4卡片,4代表4*4卡片,7代表6*4卡片,6代表1*1卡片
  275. 'ohos.extra.param.key.form_name': form_name, // 卡片名称
  276. 'ohos.extra.param.key.module_name': 'entry' // 卡片所属的模块名称
  277. },
  278. },
  279. compId,
  280. {
  281. formBindingData: formBindingData.createFormBindingData({ data: 'share' }),
  282. // formBindingData: formBindingData.createFormBindingData({ data: 'share' }),
  283. callback: (error, formId) => {
  284. if (!error) {
  285. IBestToast.show("添加成功")
  286. }
  287. },
  288. style: {
  289. options: {
  290. // startIcon: $r("app.media.icon"), // 菜单图标,可以自己提供。系统默认采用"sys.media.ic_public_add"
  291. content: "添加到桌面", // 菜单内容,可以自己提供。默认使用"sys.string.ohos_add_form_to_desktop"
  292. // endIcon: $r("app.media.icon") // 菜单图标,可以自己提供
  293. }
  294. }
  295. }
  296. )
  297. }
  298. }
  299. // 新增辅助方法:检查当前项是否在最后一行
  300. private isLastRow(index: number): boolean {
  301. const rowIndex = Math.floor(index / this.columnsCount);
  302. const totalRows = Math.ceil(this.displayArr.length / this.columnsCount);
  303. return rowIndex === totalRows - 1;
  304. }
  305. // 检查是否在第一行
  306. private isFirstRow(index: number): boolean {
  307. return Math.floor(index / this.columnsCount) === 0;
  308. }
  309. // 检查是否在最后一列
  310. private isLastColumn(index: number): boolean {
  311. return index % this.columnsCount === this.columnsCount - 1;
  312. }
  313. // 检查是否在第一列
  314. private isFirstColumn(index: number): boolean {
  315. return index % this.columnsCount === 0;
  316. }
  317. }