【每日学点鸿蒙知识】长按动画、Canvas与底部导航重叠、Grid拖动、Web宽度自适应
1、HarmonyOS 实现按钮长按动画效果?
怎么实现一个按钮长按+动画效果
类似效果可以参考以下代码
// ets
@Entry
@Component
struct Progress_Ring {
@State progressValue: number = 0
@State animationId: number | null = null
build() {
Column({ space: 15 }) {
Stack(){
Progress({ value: 0, total: 100, type: ProgressType.Ring })
.color("red")
.value(this.progressValue)
.width(120)
.style({ strokeWidth: 5, scaleCount: 20, scaleWidth: 5, enableSmoothEffect: true })
.backgroundColor('#00000000')
Button('test').gesture(
LongPressGesture({ repeat: true,duration:10 })
.onAction((event: GestureEvent|undefined) => {
if(event && this.progressValue<=100){
clearInterval(this.animationId)
this.animationId = null
this.progressValue ++
}
})
.onActionEnd(() => {
this.animationId = setInterval(()=>{
this.progressValue --
if(this.progressValue <=0){
clearInterval(this.animationId)
}
},10)
})
)
}
}.width('100%').padding({ top: 5 })
}
}
2、HarmonyOS 手机竖屏->横屏->竖屏,Canvas底部与导航条重叠的区域出现拖影问题?
在Canvas组件是全屏绘制的情况下,先旋转一次屏幕,再旋转回来。在Canvas的上下滚动刷新绘制过程中,会出现底部导航条区域渲染不及时,出现拖影的问题。
Canvas组件不是全屏的,却又进行全屏绘制。将Canvas组件调整成全屏的
3、HarmonyOS grid 触发拖拽的中途, 怎么才可以做到禁止修改第1个和最后一个item的位置?
参考代码
import curves from '@ohos.curves'
@Entry
@Component
struct GridItemExample {
@State numbers: number[] = []
@State dragItem: number = -1
@State scaleItem: number = -1
@State item: number = -1
private dragRefOffsetx: number = 0
private dragRefOffsety: number = 0
@State offsetX: number = 0
@State offsetY: number = 0
private FIX_VP_X: number = 108
private FIX_VP_Y: number = 120
aboutToAppear() {
for (let i = 1; i <= 11; i++) {
this.numbers.push(i)
}
}
itemMove(index: number, newIndex: number): void {
console.info('index:' + index + ' newIndex:' + newIndex)
if (!this.isDraggable(newIndex)) {
return
}
let tmp = this.numbers.splice(index, 1)
this.numbers.splice(newIndex, 0, tmp[0])
}
//向下滑
down(index: number): void {
// 指定固定GridItem不响应事件
if (!this.isDraggable(index + 3)) {
return
}
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 3)
}
//向下滑(右下角为空)
down2(index: number): void {
if (!this.isDraggable(index + 3)) {
return
}
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 3)
}
//向上滑
up(index: number): void {
if (!this.isDraggable(index - 3)) {
return
}
this.offsetY += this.FIX_VP_Y
this.dragRefOffsety -= this.FIX_VP_Y
this.itemMove(index, index - 3)
}
//向左滑
left(index: number): void {
if (!this.isDraggable(index - 1)) {
return
}
this.offsetX += this.FIX_VP_X
this.dragRefOffsetx -= this.FIX_VP_X
this.itemMove(index, index - 1)
}
//向右滑
right(index: number): void {
if (!this.isDraggable(index + 1)) {
return
}
this.offsetX -= this.FIX_VP_X
this.dragRefOffsetx += this.FIX_VP_X
this.itemMove(index, index + 1)
}
//向右下滑
lowerRight(index: number): void {
if (!this.isDraggable(index + 4)) {
return
}
this.offsetX -= this.FIX_VP_X
this.dragRefOffsetx += this.FIX_VP_X
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 4)
}
//向右上滑
upperRight(index: number): void {
if (!this.isDraggable(index - 2)) {
return
}
this.offsetX -= this.FIX_VP_X
this.dragRefOffsetx += this.FIX_VP_X
this.offsetY += this.FIX_VP_Y
this.dragRefOffsety -= this.FIX_VP_Y
this.itemMove(index, index - 2)
}
//向左下滑
lowerLeft(index: number): void {
if (!this.isDraggable(index + 2)) {
return
}
this.offsetX += this.FIX_VP_X
this.dragRefOffsetx -= this.FIX_VP_X
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 2)
}
//向左上滑
upperLeft(index: number): void {
if (!this.isDraggable(index - 4)) {
return
}
this.offsetX += this.FIX_VP_X
this.dragRefOffsetx -= this.FIX_VP_X
this.offsetY += this.FIX_VP_Y
this.dragRefOffsety -= this.FIX_VP_Y
this.itemMove(index, index - 4)
}
isDraggable(index: number): boolean {
console.info('index:' + index)
return index > 0 && index!= this.numbers.length -1;
}
build() {
Column({space:10}) {
Column({space:5}) {
Text("Grid拖拽排序动效")
Text("第一个和最后一个组件不可拖拽")
}
Grid() {
ForEach(this.numbers, (item: number) => {
GridItem() {
Text(item + '')
.fontSize(16)
.width('100%')
.textAlign(TextAlign.Center)
.height(100)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
.shadow(this.scaleItem == item ? {
radius: 70,
color: '#15000000',
offsetX: 0,
offsetY: 0
} :
{
radius: 0,
color: '#15000000',
offsetX: 0,
offsetY: 0
})
.animation({ curve: Curve.Sharp, duration: 300 })
}
// 指定固定GridItem不响应事件
.hitTestBehavior(this.isDraggable(this.numbers.indexOf(item)) ? HitTestMode.Default : HitTestMode.None)
.scale({ x: this.scaleItem == item ? 1.05 : 1, y: this.scaleItem == item ? 1.05 : 1 })
.zIndex(this.dragItem == item ? 1 : 0)
.translate(this.dragItem == item ? { x: this.offsetX, y: this.offsetY } : { x: 0, y: 0 })
.padding(10)
.gesture(
// 以下组合手势为顺序识别,当长按手势事件未正常触发时则不会触发拖动手势事件
GestureGroup(GestureMode.Sequence,
LongPressGesture({ repeat: true })
.onAction((event?: GestureEvent) => {
animateTo({ curve: Curve.Friction, duration: 300 }, () => {
this.scaleItem = item
})
})
.onActionEnd(() => {
animateTo({ curve: Curve.Friction, duration: 300 }, () => {
this.scaleItem = -1
})
}),
PanGesture({ fingers: 1, direction: null, distance: 0 })
.onActionStart(() => {
this.dragItem = item
this.dragRefOffsetx = 0
this.dragRefOffsety = 0
})
.onActionUpdate((event: GestureEvent) => {
this.offsetY = event.offsetY - this.dragRefOffsety
this.offsetX = event.offsetX - this.dragRefOffsetx
animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
let index = this.numbers.indexOf(this.dragItem)
if (this.offsetY >= this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44)
&& ![8, 9, 10].includes(index)) {
//向下滑
this.down(index)
} else if (this.offsetY <= -this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44)
&& ![0, 1, 2].includes(index)) {
//向上滑
this.up(index)
} else if (this.offsetX >= this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50)
&& ![2, 5, 8, 10].includes(index)) {
//向右滑
this.right(index)
} else if (this.offsetX <= -this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50)
&& ![0, 3, 6, 9].includes(index)) {
//向左滑
this.left(index)
} else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2
&& ![2, 5, 7, 8, 9, 10].includes(index)) {
//向右下滑
this.lowerRight(index)
} else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2
&& ![0, 1, 2, 5, 8].includes(index)) {
//向右上滑
this.upperRight(index)
} else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2
&& ![0, 3, 6, 9, 10].includes(index)) {
//向左下滑
this.lowerLeft(index)
} else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2
&& ![0, 1, 2, 3, 6, 9].includes(index)) {
//向左上滑
this.upperLeft(index)
} else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2
&& [7].includes(index)) {
//向右下滑(右下角为空)
this.down2(index)
}
})
})
.onActionEnd(() => {
animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
this.dragItem = -1
})
animateTo({
curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
}, () => {
this.scaleItem = -1
})
})
)
.onCancel(() => {
animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
this.dragItem = -1
})
animateTo({
curve: curves.interpolatingSpring(14, 1, 170, 17)
}, () => {
this.scaleItem = -1
})
})
)
}, (item: number) => item.toString())
}
.width('90%')
.editMode(true)
.scrollBar(BarState.Off)
.columnsTemplate("1fr 1fr 1fr")
}.width('100%').height('100%').backgroundColor('#0D182431').padding({ top: 5 })
}
}
4、HarmonyOS 使用Webview加载huawei首页出现操作条,且宽度不能自适应?
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController();
@State userAgent: string =
'Mozilla/5.0 (Phone; OpenHarmony 4.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 ArkWeb/4.1.6.1 Mobile automobile/792'
aboutToAppear() {
web_webview.WebviewController.setWebDebuggingAccess(true);
}
build() {
Column() {
Web({ src: "", controller: this.controller })
.javaScriptAccess(true)
.domStorageAccess(true)
.width("100%")
.height("100%")
.onControllerAttached(() => {
this.controller.setCustomUserAgent(this.userAgent);
this.controller.loadUrl("www.huawei.com")
})
}
}
}
5、HarmonyOS Grid拖拽,让部分item不响应拖拽?
整个页面都是使用Grid来布局,其中拖拽过程中如何让部分item不响应,例如下面的布局: 1 2 3 4 5 6 7 8 9 第1个元素占据一整行,其余元素4个一行,拖动第8个元素,预期能够和2,3,4,5,6,7,8进行交换,即使拖动元素到1的位置,第1个元素也不响应交换动画
参考如下Demo:
@Entry
@Component
struct GridExample {
@State numbers: string[] = []
scroller: Scroller = new Scroller()
layoutOptions1: GridLayoutOptions = {
regularSize: [1, 1], // 只支持[1, 1]
irregularIndexes: [0], // 索引为0的GridItem占用一行
}
@State text: string = 'drag'
@Builder pixelMapBuilder() { //拖拽过程样式
Column() {
Text(this.text)
.fontSize(16)
.backgroundColor(0xF9CF93)
.width(80)
.height(80)
.textAlign(TextAlign.Center)
}
}
aboutToAppear() {
for (let i = 1;i <= 9; i++) {
this.numbers.push(i + '')
}
}
changeIndex(index1:number, index2:number) { //交换数组中的位置
const temp = this.numbers[index1];
if (index1 > index2) {
this.numbers.splice(index2, 0, temp);
this.numbers.splice(index1 + 1, 1);
} else {
this.numbers.splice(index2 + 1, 0, temp);
this.numbers.splice(index1, 1);
}
}
build() {
Column({ space: 5 }) {
Grid(this.scroller, this.layoutOptions1) {
ForEach(this.numbers, (day: string) => {
GridItem() {
if (day == "1") {
Text(day)
.fontSize(16)
.backgroundColor(0xF9CF93)
.width("100%")
.height(80)
.textAlign(TextAlign.Center)
} else {
Text(day)
.fontSize(16)
.backgroundColor(0xF9CF93)
.width(80)
.height(80)
.textAlign(TextAlign.Center)
}
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.onScrollIndex((first: number) => {
console.info(first.toString())
})
.width('100%')
.backgroundColor(0xFAEEE0)
.height(300)
.editMode(true) //设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem
.onItemDragStart((event: ItemDragInfo, itemIndex: number) => { //第一次拖拽此事件绑定的组件时,触发回调。
if (itemIndex == 0) {
return;
}
this.text = this.numbers[itemIndex]
return this.pixelMapBuilder() //设置拖拽过程中显示的图片。
})
.onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => { //绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。
// isSuccess=false时,说明drop的位置在grid外部;insertIndex > length时,说明有新增元素的事件发生
if (!isSuccess || insertIndex >= this.numbers.length || insertIndex == 0) {
return
}
console.info('tag' + itemIndex + '', insertIndex + '') //itemIndex拖拽起始位置,insertIndex拖拽插入位置
this.changeIndex(itemIndex, insertIndex)
})
}.width('100%').margin({ top: 5 })
}
}