HarmonyOS 鸿蒙Next hitTestMode 问题

发布于 1周前 作者 gougou168 来自 鸿蒙OS

HarmonyOS 鸿蒙Next hitTestMode 问题

以下测试代码,当下拉使得offsety>0时,再反向上拉这个时候hitTestMode 应该是block,为什么list也会跟着往上滚动?

import { LogUtils } from ‘ds_components/Index’
import { MATCH_PARENT } from ‘…/contants/Size’
import { curves } from ‘@kit.ArkUI’

@Component @Preview export struct DSText { datas: number[] = [] scroller: Scroller = new Scroller()

aboutToAppear(): void { for (let i = 0; i < 30; i++) { this.datas.push(i) } }

build() { DSRefresh({ scroller: this.scroller }) { List({ scroller: this.scroller }) { ForEach(this.datas, (data: number, index) => { ListItem() { Text(data.toString()).width(MATCH_PARENT).height(60) } }, (data: number, index) => index.toString()) }.width(MATCH_PARENT).height(MATCH_PARENT).edgeEffect(EdgeEffect.None) } } }

@Component @Preview export struct DSRefresh { scroller: Scroller = new Scroller() @BuilderParam itemLayout: () => void @State offsetY: number = 0 @State scrollUp: Boolean = false @State hitTestMode: HitTestMode = HitTestMode.Default refreshEnable: boolean = true maxOffsetY = vp2px(300) downY: number = 0 lastX: number = 0 lastY: number = 0 damping: number = 0.5 @State state: DSRefreshState = DSRefreshState.None @State headerHeight: number = 0 @State footerHeight: number = 0 onRefresh ?: () => void onLoadMore ?: () => void

aboutToAppear(): void { if (this.damping < 0) { this.damping = 0.5 } else if (this.damping > 1) { this.damping = 1 } }

advancedDamping(offset: number, maxOffset: number = this.maxOffsetY): number { const dampingCoefficient = this.damping / 1000; // 阻尼系数,调整阻尼增长速率 const dampingEffect = maxOffset * (1 - Math.exp(-dampingCoefficient * offset)); return dampingEffect; }

build() { Column() { Row() { Image($r(‘app.media.ic_header_loading’)) .width(30) .aspectRatio(1) .margin({ bottom: 10, top: 50 }) .rotate({ angle: this.state == DSRefreshState.Refresh ? 360 : 0 }) .animation({ iterations: -1, curve: Curve.Linear }) }.alignItems(VerticalAlign.Bottom).margin({ top: -this.headerHeight }) .onAreaChange((oldValue, newValue) => { this.headerHeight = Number(newValue.height) }) this.itemLayout() // .width(MATCH_PARENT).height(MATCH_PARENT).backgroundColor(Color.Blue).textAlign(TextAlign.Center)

  Text(<span class="hljs-string">'footer'</span>)
    .width(MATCH_PARENT)
    .height(<span class="hljs-number">100</span>)
    .backgroundColor(Color.Red)
    .textAlign(TextAlign.Center)
    .onAreaChange((oldValue, newValue) =&gt; {
      <span class="hljs-keyword">this</span>.footerHeight = <span class="hljs-built_in">Number</span>(newValue.height)
    })
}
.hitTestBehavior(<span class="hljs-keyword">this</span>.hitTestMode)
.onTouch((event) =&gt; {
  <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.refreshEnable || <span class="hljs-keyword">this</span>.state != DSRefreshState.None) {
    <span class="hljs-keyword">return</span>
  }

  <span class="hljs-keyword">const</span> touch = event.touches[<span class="hljs-number">0</span>]
  <span class="hljs-keyword">let</span> diff = <span class="hljs-keyword">this</span>.advancedDamping(touch.y - <span class="hljs-keyword">this</span>.downY)
  <span class="hljs-comment">// if ((diff &gt; 0 &amp;&amp; this.scroller.currentOffset()</span>
  <span class="hljs-comment">//&nbsp;&nbsp; .yOffset &gt; 0 || diff &lt; 0 &amp;&amp; !this.scroller.isAtEnd()) &amp;&amp; this.offsetY == 0) {</span>
  <span class="hljs-comment">//&nbsp;&nbsp; return</span>
  <span class="hljs-comment">// }</span>
  
  <span class="hljs-keyword">switch</span> (event.type) {
    <span class="hljs-keyword">case</span> TouchType.Down: {
      <span class="hljs-keyword">this</span>.downY = touch.y
      LogUtils.e(<span class="hljs-string">"touch"</span>, `down:${<span class="hljs-keyword">this</span>.downY} `)
      <span class="hljs-keyword">break</span>
    }

    <span class="hljs-keyword">case</span> TouchType.Move: {
      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.offsetY != <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">this</span>.hitTestMode = HitTestMode.Block
        LogUtils.e(<span class="hljs-string">"touch"</span>, <span class="hljs-string">"block"</span>)
      }
      <span class="hljs-comment">// else if (!this.scroller.isAtEnd() &amp;&amp; this.scroller.currentOffset().yOffset &gt; 0) {</span>
      <span class="hljs-comment">//&nbsp;&nbsp; this.hitTestMode = HitTestMode.None</span>
      <span class="hljs-comment">//&nbsp;&nbsp; LogUtils.e("touch", "none")</span>
      <span class="hljs-comment">//&nbsp;&nbsp; return</span>
      <span class="hljs-comment">// } else {</span>
      <span class="hljs-comment">//&nbsp;&nbsp; this.hitTestMode = HitTestMode.Default</span>
      <span class="hljs-comment">//&nbsp;&nbsp; LogUtils.e("touch", "default")</span>
      <span class="hljs-comment">// }</span>
      <span class="hljs-keyword">this</span>.scrollUp = <span class="hljs-keyword">this</span>.lastY &gt; touch.y
      <span class="hljs-comment">// LogUtils.e("touch", `move:${touch.y - this.downY}--${1 - Math.exp(-0.5 * (touch.y - this.downY))} `)</span>

      <span class="hljs-keyword">if</span> (diff &gt; <span class="hljs-keyword">this</span>.maxOffsetY || diff &lt; -<span class="hljs-keyword">this</span>.maxOffsetY) {
        <span class="hljs-keyword">return</span>
      }
      <span class="hljs-keyword">this</span>.offsetY = diff
      <span class="hljs-keyword">break</span>
    }

    <span class="hljs-keyword">case</span> TouchType.Up:

    <span class="hljs-keyword">case</span> TouchType.Cancel: {
      <span class="hljs-comment">// if(!this.scroller.isAtEnd() &amp;&amp; this.scroller.currentOffset().yOffset&gt;0){</span>
      <span class="hljs-comment">//&nbsp;&nbsp; this.hitTestMode = HitTestMode.None</span>
      <span class="hljs-comment">// }else if(this.offsetY &gt;0 ){</span>
      <span class="hljs-comment">//&nbsp;&nbsp; this.hitTestMode = HitTestMode.Block</span>
      <span class="hljs-comment">// }else{</span>
      <span class="hljs-keyword">this</span>.hitTestMode = HitTestMode.Default
      <span class="hljs-comment">// }</span>
      <span class="hljs-comment">// if (this.scrollUp &amp;&amp; !this.scroller.isAtEnd() || !this.scrollUp &amp;&amp; this.scroller.currentOffset()</span>
      <span class="hljs-comment">//&nbsp;&nbsp; .yOffset &gt; 0) {</span>
      <span class="hljs-comment">//&nbsp;&nbsp; this.hitTestMode = HitTestMode.Default</span>
      <span class="hljs-comment">// } else {</span>
      <span class="hljs-comment">//&nbsp;&nbsp; this.hitTestMode = HitTestMode.Block</span>
      <span class="hljs-comment">// }</span>

      <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.abs(diff) &gt; <span class="hljs-number">0</span>) {
        animateTo({ curve: curves.springMotion() }, () =&gt; {
          <span class="hljs-keyword">if</span> (diff &gt; <span class="hljs-keyword">this</span>.headerHeight) {
            <span class="hljs-keyword">this</span>.state = DSRefreshState.Refresh
            <span class="hljs-keyword">this</span>.offsetY = <span class="hljs-keyword">this</span>.headerHeight
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.onRefresh != <span class="hljs-literal">undefined</span>) {
              <span class="hljs-keyword">this</span>.onRefresh()
            }
            setTimeout(() =&gt; {
              <span class="hljs-keyword">this</span>.refreshFinish()
            }, <span class="hljs-number">3000</span>)
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (diff &lt; -<span class="hljs-keyword">this</span>.footerHeight) {
            <span class="hljs-keyword">this</span>.state = DSRefreshState.Load
            <span class="hljs-keyword">this</span>.offsetY = -<span class="hljs-keyword">this</span>.footerHeight
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.onLoadMore != <span class="hljs-literal">undefined</span>) {
              <span class="hljs-keyword">this</span>.onLoadMore()
            }
            setTimeout(() =&gt; {
              <span class="hljs-keyword">this</span>.refreshFinish()
            }, <span class="hljs-number">1000</span>)
          } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">this</span>.offsetY = <span class="hljs-number">0</span>
          }
        })
      }
      <span class="hljs-keyword">break</span>
    }
  }
  <span class="hljs-keyword">this</span>.lastX = touch.x
  <span class="hljs-keyword">this</span>.lastY = touch.y
})
.width(MATCH_PARENT)
.height(MATCH_PARENT)
.offset({ y: <span class="hljs-keyword">this</span>.offsetY })
.animation({
  curve: curves.springMotion(), onFinish: () =&gt; {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.state != DSRefreshState.Finish) {
      <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">this</span>.state = DSRefreshState.None
  }
})
.height(MATCH_PARENT)

}

private refreshFinish() { this.state = DSRefreshState.Finish this.offsetY = 0 } }

export enum DSRefreshState { None, Refresh, Load, Finish }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>


更多关于HarmonyOS 鸿蒙Next hitTestMode 问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next hitTestMode 问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对HarmonyOS 鸿蒙Next中的hitTestMode问题,以下是一些专业解答:

在HarmonyOS 鸿蒙Next中,hitTestBehavior属性用于设置组件的触摸测试类型,该属性影响组件的触摸测试收集结果,进而决定后续的触屏事件分发。hitTestBehavior属性的可选值包括:

  • Default:默认触摸测试效果,自身和子节点都响应触摸测试,但会阻塞兄弟节点的触摸测试。
  • Block:自身响应触摸测试,阻塞子节点和兄弟节点的触摸测试。
  • Transparent:自身和子节点都响应触摸测试,不会阻塞兄弟节点的触摸测试。
  • None:自身不响应触摸测试,不会阻塞子节点和兄弟节点的触摸测试。

开发者可以根据实际需求,为组件设置合适的hitTestBehavior值,以实现期望的触摸事件处理逻辑。

如果在使用hitTestBehavior时遇到问题,建议检查以下几点:

  • 确保API版本支持该属性(从API Version 9开始支持)。
  • 检查组件的嵌套关系和触摸区域是否有重叠。
  • 确认是否有其他触摸事件监听器影响了事件的分发。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部