当前需求:
       一个在初始在页面固定位置的悬浮按钮容器, 可拖拽移动,X轴位置总是靠右(左),页面滚动时,可隐藏,滚动条停止后,等待1秒再出现
封装:
       一个Column, 监听onTouch事件实现拖拽,暴露Controller.trigger() 来触发隐藏动画
注意: 
       由于ArkUI目前没有和CSS一样的全局绝对定位,组件必须放在@Entry 或稍外层的容器(和Scroll组件同级即可)

放最后,省却设置zIndex,否则会被遮挡
先看调用方法:

import { BuiFloatArea, BuiFloatAreaController } from '../../components/bui/BuiFloatArea';

 Column() {
      BuiPage({
        defaultPadding:false,
        slot:()=>{ this.buildContent()},
        onScroll:()=>{
          this.buiFloatAreaController.trigger(); //滚动条滚动时,触发浮动面板隐藏
        }
      })
      //浮动面板
      BuiFloatArea({controller:this.buiFloatAreaController,slot:()=>{this.buildFloatArea()}});
    }.layoutWeight(1)



 @Builder buildFloatArea(){
    Column() {
      Text("我是浮动面板").fontSize(12).fontColor(Color.Blue)
    }.width(80).height(80).backgroundColor("#cccccc90").borderRadius(40).alignSelf(ItemAlign.Center)
    .justifyContent(FlexAlign.Center)
  }

组件代码:
 

export interface BuiFloatAreaController{
  /**
   * 触发 隐藏
   */
  trigger:()=>void
}
@Builder function empty(){}
/**
 * 一个靠右(当前默认是右下角)
 * 需要放到Entry上
 */
@Component
export struct BuiFloatArea{
  controller:BuiFloatAreaController={} as BuiFloatAreaController

  /**
   * 内容区域,外部自定义
   */
  @BuilderParam slot:()=>void =empty

  /**
   * 初始x坐标 不要超过350,你懂得
   */
  @State x:number = 250
  /**
   * 初始y坐标 这里可以计算当前屏幕高度来动态设置
   */
  @State y:number = 600
  /**
   * 可拖拽的最大高度,外部传吧,可传屏幕高度
   */
  @State maxTop:number = 660
  //以下是内部封装属性 都是需要页面响应的,所以都需要@State修饰
  @State private initX:number = this.x;
  @State private startX:number = 0
  @State private startY:number = 0
  @State private timer:number = 0
  @State private duration:number = 100
  @State private myWidth:number = 50

  build(){
    Column(){
        this.slot();
    }.position({
      x: this.x,
      y:this.y
    }).constraintSize({
      minWidth:50,
      minHeight:50
    })
    .animation({
      duration: this.duration,
      curve:Curve.Linear
    })
    .onTouch((e:TouchEvent)=>{
      if(!e)return;
      e.stopPropagation()
      let touch = e.changedTouches?.[0]
      if(!touch)return;
        if(e.type == TouchType.Down){ //按下
          this.startX = touch.windowX
          this.startY = touch.windowY
          this.duration = 0 //动画速度归零,否则拖拽时感觉不跟手
        }else if(e.type == TouchType.Up){ //抬起
          this.startX=0;
          this.startY=0;
          this.x = this.initX; //让横坐标复位
          this.duration = 100 //动画速度,否则复位时闪现
        }else if(e.type == TouchType.Move){ //移动
          let t = e.target;
          let pos:Position =t.area.globalPosition;
          let x = touch.windowX
          let y = touch.windowY
          this.x+= x-this.startX
          this.y+= y-this.startY
          let posX = pos.x as number
          let posY = pos.y as number
          let tW = t.area.width as number
          let tH = t.area.height as number
          if(posX<-1){ // 左边界
            this.x=0
          }
          if(posX+tW>360){ //右边界
            this.x=360-tW
          }
          if(posY<-1){ //上边界
            this.y=0
          }
          if(posY+tH>this.maxTop-2){ //下边界,这里660显然不是屏幕高度, 可以根据需要设置
            this.y=this.maxTop-tH
          }

          this.startX=x;
          this.startY=y;
          console.log("",this.startX,this.startY)
        }
    }).onAreaChange((o:Area,n:Area)=>{
      this.myWidth = n.width as number
    })


  }

  aboutToAppear(){
    this.controller.trigger = ()=>{
      this.x = 365+this.myWidth; //让横坐标复位
      if(this.timer)clearTimeout(this.timer)
      this.timer = setTimeout(()=>{
        this.duration = 300
        this.x = this.initX
      },1000)
    }

  }

}

本章代码地址: https://gitee.com/jifsu_167/open-harmony-demo

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐