HarmonyOS NEXT实战电话拨打

一、介绍
基于鸿蒙Next模拟电话通讯录,可以拨打电话,删除电话等
二、场景需求
客户服务、业务咨询、回访处理、沟通交流、信息交流等等

三、业务步骤
第一步:点击拨打点电话,先判断设备是否具备通讯能力。
第二步:如果具备通讯能力,将跳转至拨号页面
第三步:拨打电话即可
四、效果展示

五:代码展示:
`import promptAction from '@ohos.promptAction'
import router from '@ohos.router'
import call from '@ohos.telephony.call';
import observer from '@ohos.telephony.observer';
import { listData,dataType} from "../common/phoneNumData"

@Entry
@Component
struct contactsPage {
@State listArr: dataType[] = listData //联系人数据
@State isObserver: boolean = false // 是否拨打电话

aboutToAppear(){

}

@Builder setMenu() {
Menu() {
MenuItem({ startIcon: $r("app.media.ic_public_delete"), content: "删除全部" })
.onClick(()=>this.delListData())
}
}

//删除全部电话数据
delListData():void {
promptAction.showDialog({
message:"数据不可恢复,确认全部删除?",
buttons:[
{
text:"否",
color:"#191919"
},
{
text:"是",
color:"red"
}
]
}).then((idx)=>{
if (idx.index == 1) {
listData.length = 0
this.listArr = []
return
}
return
})
}

//拨打电话
callPhone(currentNum:string):void {
let isP = call.hasVoiceCapability();
console.log(hasVoiceCapability: ${JSON.stringify(isP)});
if (isP){
this.isObserver = true
call.makeCall(currentNum, err => {
console.log(makeCall callback: err->${JSON.stringify(err)});
});
}else {
promptAction.showToast({
message:"当前设备不支持通话"
})
}
}

//监听通话状态
listenTel(){
// 订阅通话业务状态变化
if (this.isObserver) {
observer.on("callStateChange", (data) => {
if (data.state == 0||data.state == -1) {
this.isObserver = false
this.listenOff() //取消订阅状态
}
console.log("call state change, data is:" + JSON.stringify(data.state));
});
}
}

listenOff(){
observer.off('callStateChange');
}

build() {
Column() {
Row() {
Text(this.listArr.length.toString() + "个联系人").fontSize(20)
.fontColor(0x0091FF)
.height(26)
Blank()
Image($r('app.media.ic_public_add')).width(24).height(24)
.margin({right:10})
.onClick(() => {
router.pushUrl({
url: "viewPhone/addContactPage"
})
})

    Image($r('app.media.ic_public_more')).width(24).height(24)
      .bindMenu(this.setMenu)

  }.width("100%")
  .height(40)
  .padding({ left: 15, right: 10 })

  List() {
    if (this.listArr.length != 0) {
      ForEach(this.listArr, (item: dataType, index: number) => {
        ListItem() {
          Row() {
            Row(){
              if (item.phoneName.length ==11) {
                Image($r('app.media.ic_public_contacts_filled')).width(32).height(32)
                  .margin({ left: 15, right: 10 })
              }else {
                Column(){
                  Text(item.phoneName.charAt(0)).fontColor(0xffffff)
                }.width(36).height(36)
                .borderRadius(20)
                .backgroundColor(0x999999)
                .margin({ left: 15, right: 10 })
                .justifyContent(FlexAlign.Center)
              }

              Text(item.phoneName)
                .height(60).fontSize(20)
                .textAlign(TextAlign.Center)
            }.width("74%")
            .stateStyles({
              pressed: {.backgroundColor(0xdfdfdf)
              },
              normal: {.backgroundColor(0xFFFFFF)
              }
            })
            Blank()
            Row(){
              Text("|").height(30)
                .fontSize(18)
                .textAlign(TextAlign.Center)
                .borderRadius(4)
              Text("拨打").height(30)
                .textAlign(TextAlign.Center)
                .borderRadius(4)
                .margin({  left: 5 })
              Image($r('app.media.ic_contacts_set_aside_filled')).width(16).height(16)
                .margin({  right: 15,left:4 })
            }
            .height(60)
            .justifyContent(FlexAlign.Center)
            .onClick(()=>this.callPhone(item.phoneNum))
            .stateStyles({
              pressed: {.backgroundColor(0xdfdfdf)
              },
              normal: {.backgroundColor(0xFFFFFF)
              }
            })

          }.width('100%')
          .backgroundColor(0xFFFFFF)
          .onClick(() => {
            router.pushUrl({
              url:"viewPhone/contactDetailsPage",
              params:{
                phoneName:item.phoneName,
                phoneNum:item.phoneNum,
                notesInfo:item.notesInfo,
                companyName:item.companyName,
                idx:index
              }
            })
          })
          // .gesture(
          //   LongPressGesture({repeat:false,fingers:1,duration:1000})
          //     .onAction(()=>{
          //       this.delMenu()
          //     })
          // )
        }
      }, (item:string) => item)

    }else {
      ListItem(){
        Column(){
          Text("暂无联系人").fontColor(24)
        }.width("100%")
        .height("50%")
        .justifyContent(FlexAlign.Center)
        .alignItems(HorizontalAlign.Center)
      }
    }
  }
  .padding({ top: 15 })
  .listDirection(Axis.Vertical) // 排列方向
  .divider({ strokeWidth: 2, color: 0xeeeeee, startMargin: 0, endMargin: 0 }) // 每行之间的分界线
  .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
  .onScrollIndex((firstIndex: number, lastIndex: number) => {
    console.info('first' + firstIndex)
    console.info('last' + lastIndex)
  })
  .width('100%')

}
.width('100%')
.height('100%')
.backgroundColor(0xeeeeee)
.padding({ top: 5 })

}
}`
六、代码结构及原理:
1.整体结构:
使用了ArkTS的装饰器语法,如@Entry和@Component组件。使用了ArkTS的渲染语法if/else等
2.状态管理:
组件使用@State装饰器定义了几个响应式状态变量,
使用了如@Builder 装饰器自定义了组件

3.样式和布局:
整个界面使用Column布局,将各个元素垂直排列。
使用Row布局来组织水平方向的元素,如拨打按钮。
应用了一些通用样式,如字体大小、颜色、边距等,以确保界面的一致性和美观性。
使用.backgroundColor(0xeeeeee)作为整个面板的背景色

  1. 导入声明:
    代码开始部分导入了必要的常量、类型和函数。这包括背景颜色常量、文档大小相关类型、
posted @ 2024-09-29 15:26  李洋蛟龙腾飞  阅读(25)  评论(0编辑  收藏  举报