diff --git a/entry/src/main/ets/components/RecordingOverlay.ets b/entry/src/main/ets/components/RecordingOverlay.ets new file mode 100644 index 0000000..38ba130 --- /dev/null +++ b/entry/src/main/ets/components/RecordingOverlay.ets @@ -0,0 +1,75 @@ +/** + * 录音浮层(设计 §10,纯展示,仿微信"按住说话")。状态由容器手势驱动,自身不处理触摸 + * (HitTestMode.None 让触摸穿透到下方 Web,由 Web.onTouch 观察手势)。 + * - recording:跳动波形 + "手指上滑,取消发送" + * - cancel:红底 + "✕" + "松开手指,取消发送" + * - tooShort:黑底 + "!" + "说话时间太短" + */ +@Component +export struct RecordingOverlay { + /** 'recording' | 'cancel' | 'tooShort' */ + @Prop state: string; + @State private bars: number[] = [0.4, 0.7, 0.5, 0.9, 0.6, 0.8, 0.45]; + private timer: number = -1; + + aboutToAppear(): void { + this.timer = setInterval(() => { + this.bars = this.bars.map(() => 0.25 + 0.75 * Math.random()); + }, 120); + } + + aboutToDisappear(): void { + if (this.timer >= 0) { + clearInterval(this.timer); + this.timer = -1; + } + } + + private hintText(): string { + if (this.state === 'cancel') { + return '松开手指,取消发送'; + } + if (this.state === 'tooShort') { + return '说话时间太短'; + } + return '手指上滑,取消发送'; + } + + build() { + Column() { + Column({ space: 14 }) { + if (this.state === 'recording') { + Row({ space: 4 }) { + ForEach(this.bars, (h: number, i: number) => { + Column() + .width(5) + .height(48 * h) + .borderRadius(3) + .backgroundColor('#FFFFFF') + }, (h: number, i: number) => i.toString()) + } + .height(52) + .alignItems(VerticalAlign.Center) + } else { + Text(this.state === 'cancel' ? '✕' : '!') + .fontSize(42) + .fontWeight(FontWeight.Bold) + .fontColor('#FFFFFF') + } + Text(this.hintText()) + .fontSize(14) + .fontColor('#FFFFFF') + } + .width(168) + .height(168) + .justifyContent(FlexAlign.Center) + .borderRadius(18) + .backgroundColor(this.state === 'cancel' ? '#C0392B' : 'rgba(0, 0, 0, 0.78)') + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + .alignItems(HorizontalAlign.Center) + .hitTestBehavior(HitTestMode.None) + } +}