设备类型判断(手机_平板_车机):差异化业务逻辑实现

鸿蒙生态的设备种类越来越多:手机、平板、折叠屏、车机、智慧屏。同一个应用跑在不同设备上,交互方式、屏幕尺寸、使用场景完全不一样。比如音乐APP,手机上是竖屏列表,平板上要做横屏多栏布局,车机上要做大字体、少操作的驾驶模式。如果不做设备判断,一套布局走天下,车机上按钮太小点不准,平板上两边全是空白,体验都很差。本文基于最新鸿蒙API,讲清楚怎么判断当前设备类型、怎么根据设备做差异化业务逻辑,代码可以直接复制到项目里用。

01 为什么要判断设备类型

很多人第一反应是:做响应式布局不就行了,根据屏幕宽度自动调整。大部分场景响应式确实够用,但有些业务逻辑层面的差异,光靠布局适配解决不了。

**交互方式不同。**手机是手指触控,平板是手指加触控笔,车机是旋钮加语音,智慧屏是遥控器。同样的按钮,手机上做小一点没事,车机上按钮小了驾驶的时候根本点不准。

**功能裁剪不同。**车机上不需要相册、不需要拍照,这些功能直接隐藏。智慧屏上没有传感器,定位、加速度这些能力直接关掉。

**默认布局不同。**平板默认横屏使用,布局要按横屏设计;手机默认竖屏;车机固定横屏,宽度很宽高度很窄。

**性能和资源不同。**车机芯片性能普遍弱一些,动画效果、高清图片要降级处理,不然卡顿。

所以实际项目里,一般是响应式布局加设备类型判断双管齐下:布局靠断点自适应,功能和交互逻辑靠设备类型判断。

02 设备类型判断API

鸿蒙提供了deviceInfo模块,在@kit.BasicServicesKit里,直接能拿到当前设备的类型信息。

typescript 复制代码
import { deviceInfo } from '@kit.BasicServicesKit';

// 获取设备类型
async function getDeviceType() {
  const deviceType = deviceInfo.deviceType;
  console.info('当前设备类型:', deviceType);
  return deviceType;
}

deviceType返回的是字符串,常见的取值:

  • phone:手机

  • tablet:平板

  • car:车机

  • tv:智慧屏

  • wearable:手表

  • 2in1:二合一笔记本

这个是系统直接返回的,不用自己猜。比根据屏幕宽度判断准确多了------同样宽度的平板和折叠屏展开态,系统能明确告诉你哪个是平板哪个是手机。

除了设备类型,还能拿到更多设备信息:

typescript 复制代码
import { deviceInfo } from '@kit.BasicServicesKit';

function getDeviceInfo() {
  console.info('设备类型:', deviceInfo.deviceType);
  console.info('设备名称:', deviceInfo.deviceName);
  console.info('品牌:', deviceInfo.brand);
  console.info('产品型号:', deviceInfo.productModel);
  console.info('系统版本:', deviceInfo.osFullName);
  console.info('是否仿真器:', deviceInfo.isDebug);
}

deviceName和productModel可以用来做更精细的判断,比如某一款车机屏幕特别窄,单独做适配。但一般业务场景下,用deviceType就够了。

03 设备屏幕信息获取

除了设备类型,还要拿到屏幕的物理尺寸、分辨率,这样才能做精准的布局判断。用display模块。

typescript 复制代码
import { display } from '@kit.ArkUI';

function getScreenInfo() {
  const displayInfo = display.getDefaultDisplaySync();

  console.info('屏幕宽度(px):', displayInfo.width);
  console.info('屏幕高度(px):', displayInfo.height);
  console.info('屏幕密度:', displayInfo.densityDPI);
  console.info('字体比例:', displayInfo.fontSizeScale);

  // 转换成vp单位
  const density = displayInfo.densityDPI / 160;
  const widthVp = displayInfo.width / density;
  const heightVp = displayInfo.height / density;

  console.info('屏幕宽度(vp):', widthVp);
  console.info('屏幕高度(vp):', heightVp);
}

屏幕尺寸用来做什么?判断是横屏还是竖屏,判断是大屏还是小屏。车机一般是宽高比很大的横屏,高度比较矮。手机竖屏是高宽比大。

typescript 复制代码
function getScreenOrientation(): string {
  const displayInfo = display.getDefaultDisplaySync();
  if (displayInfo.width > displayInfo.height) {
    return 'landscape'; // 横屏
  } else {
    return 'portrait'; // 竖屏
  }
}

04 差异化业务逻辑实现

知道设备类型之后,怎么落地差异化逻辑?核心思路是:公共逻辑写一套,设备特有的逻辑单独分支。

typescript 复制代码
import { deviceInfo } from '@kit.BasicServicesKit';

class DeviceConfig {
  private static instance: DeviceConfig;
  private deviceType: string = 'phone';

  static getInstance(): DeviceConfig {
    if (!DeviceConfig.instance) {
      DeviceConfig.instance = new DeviceConfig();
    }
    return DeviceConfig.instance;
  }

  init() {
    this.deviceType = deviceInfo.deviceType;
    console.info('当前设备:', this.deviceType);
  }

  isPhone(): boolean {
    return this.deviceType === 'phone';
  }

  isTablet(): boolean {
    return this.deviceType === 'tablet';
  }

  isCar(): boolean {
    return this.deviceType === 'car';
  }

  isTV(): boolean {
    return this.deviceType === 'tv';
  }

  // 不同设备的按钮大小
  getButtonSize(): number {
    if (this.isCar()) return 80;   // 车机按钮大一点
    if (this.isTablet()) return 56; // 平板中等
    return 44; // 手机标准
  }

  // 不同设备的列表列数
  getGridColumns(): number {
    if (this.isTablet()) return 3;  // 平板3列
    if (this.isCar()) return 4;     // 车机4列
    return 2; // 手机2列
  }

  // 不同设备默认横竖屏
  getDefaultOrientation(): string {
    if (this.isCar()) return 'landscape'; // 车机横屏
    if (this.isTablet()) return 'landscape'; // 平板横屏
    return 'portrait'; // 手机竖屏
  }
}

export const deviceConfig = DeviceConfig.getInstance();

在EntryAbility启动的时候初始化一次:

typescript 复制代码
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { deviceConfig } from '../utils/DeviceConfig';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, param: AbilityConstant.LaunchParam): void {
    // 启动时初始化设备信息
    deviceConfig.init();
  }
}

页面里用的时候直接调:

typescript 复制代码
@Entry
@Component
struct MusicPage {
  build() {
    Column() {
      // 车机模式:大字体大按钮,少操作
      if (deviceConfig.isCar()) {
        Text('驾驶模式')
          .fontSize(32)
        Button('下一首')
          .width(200)
          .height(80)
          .fontSize(28)
      } else {
        // 手机/平板:正常布局
        Text('音乐列表')
          .fontSize(20)
        Button('播放')
          .width(120)
          .height(44)
      }
    }
  }
}

这样代码里到处都是if判断也不好看,可以把不同设备的页面组件分开,根据设备类型直接加载不同的组件:

typescript 复制代码
@Entry
@Component
struct HomePage {
  build() {
    if (deviceConfig.isCar()) {
      CarHomeComponent()
    } else if (deviceConfig.isTablet()) {
      TabletHomeComponent()
    } else {
      PhoneHomeComponent()
    }
  }
}

@Component
struct CarHomeComponent {
  build() {
    // 车机专属首页
    Column() {
      Text('车机首页')
    }
  }
}

@Component
struct TabletHomeComponent {
  build() {
    // 平板专属首页
    Row() {
      Text('平板首页')
    }
  }
}

@Component
struct PhoneHomeComponent {
  build() {
    // 手机专属首页
    Column() {
      Text('手机首页')
    }
  }
}

设备差异特别大的页面,直接拆成三个组件,互不影响,好维护。设备差异小的,就在同一个组件里用if判断样式参数就行。

05 车机特殊适配

车机是最特殊的设备,和手机逻辑差很多,单独拿出来说。

**第一,驾驶模式要大字体、大按钮。**开车的时候视线不能离开路面太久,按钮要大,字要大,操作步骤要少。一个功能最好一两个按钮就能完成。

**第二,高频功能前置,低频功能藏起来。**音乐、导航、电话这些开车常用的,放首页显眼位置。设置、账号这些低频的,放到二级页面去。

**第三,默认横屏,不能旋转。**车机屏幕是固定装在车上的,方向不能变。在module.json5里把orientation设成landscape,强制横屏。

**第四,简化动画和效果。**车机芯片性能一般,复杂的动画、模糊效果、阴影都要简化,不然会卡。

typescript 复制代码
// 车机专属配置
const carConfig = {
  fontSize: 28,        // 字体大一点
  buttonHeight: 80,    // 按钮高一点
  animationEnabled: false, // 关动画
  listColumns: 3,      // 列表少几列
  showAds: false       // 不展示广告
};

// 手机配置
const phoneConfig = {
  fontSize: 16,
  buttonHeight: 44,
  animationEnabled: true,
  listColumns: 2,
  showAds: true
};

06 完整工具类封装

把设备类型、屏幕信息、配置参数都整合到一个工具类里,项目里直接用。

typescript 复制代码
import { deviceInfo } from '@kit.BasicServicesKit';
import { display } from '@kit.ArkUI';

class DeviceUtil {
  private static instance: DeviceUtil;
  private deviceType: string = 'phone';
  private screenWidth: number = 0;
  private screenHeight: number = 0;

  static getInstance(): DeviceUtil {
    if (!DeviceUtil.instance) {
      DeviceUtil.instance = new DeviceUtil();
    }
    return DeviceUtil.instance;
  }

  init() {
    this.deviceType = deviceInfo.deviceType;
    const d = display.getDefaultDisplaySync();
    const density = d.densityDPI / 160;
    this.screenWidth = d.width / density;
    this.screenHeight = d.height / density;
  }

  getType(): string {
    return this.deviceType;
  }

  isPhone(): boolean {
    return this.deviceType === 'phone';
  }

  isTablet(): boolean {
    return this.deviceType === 'tablet';
  }

  isCar(): boolean {
    return this.deviceType === 'car';
  }

  isTV(): boolean {
    return this.deviceType === 'tv';
  }

  // 是否大屏
  isLargeScreen(): boolean {
    return this.screenWidth >= 600;
  }

  // 是否横屏
  isLandscape(): boolean {
    return this.screenWidth > this.screenHeight;
  }

  // 根据设备返回主题配置
  getThemeConfig() {
    if (this.isCar()) {
      return { fontSize: 28, padding: 24, radius: 16, animation: false };
    } else if (this.isTablet()) {
      return { fontSize: 18, padding: 16, radius: 12, animation: true };
    } else {
      return { fontSize: 14, padding: 12, radius: 8, animation: true };
    }
  }
}

export const deviceUtil = DeviceUtil.getInstance();

在Ability启动时调用一次init(),之后页面里直接deviceUtil.isCar()、deviceUtil.getThemeConfig()就行,不用重复获取设备信息。

落地注意事项

**不要只靠屏幕宽度判断设备。**折叠屏展开之后宽度和平板差不多,但本质还是手机。用deviceType判断才准确,宽度只用来做响应式布局。

**设备差异不要散落在各个页面。**所有设备相关的配置都集中在DeviceUtil里,统一管理。不然这里写一个if、那里写一个else,以后改配置要翻遍整个项目。

**新设备类型要预留扩展。**以后可能出手表、智慧屏、智能冰箱,工具类里加个新的判断方法就行,不用到处改代码。

**车机和手机不要共用太多页面。**差异太大的页面,直接拆成两个组件。硬套一套逻辑,加一堆if判断,最后代码自己都看不懂。

小结

设备类型判断的核心不是写多少个if分支,而是把设备相关的配置统一管理。启动的时候初始化一次设备信息,页面里直接调用工具类的方法获取配置,不用重复获取。实际项目中,手机和平板差异不大,用响应式布局加少量设备判断就够了。车机差异大,单独做一套页面和交互。这样一套代码跑多种设备,开发量不会增加太多,用户体验却好很多。

相关推荐
豪气的程序猿11 小时前
Windows 练字时空格键偶尔没反应?先排查焦点和键盘,再用键盘小鹿练习
计算机外设·电脑
mg66815 小时前
安卓玩机工具----开源的国产安卓手机去广告工具:不用 Root、不刷机
智能手机·去除广告
派大猩猩_17 小时前
两台电脑怎么自动同步文件?坚果云跨设备同步使用指南
电脑·企业网盘·文件同步·网盘·同步文件
雾喔21 小时前
从零理解大语言模型:AI、LLM、训练成本与手机助手的底层逻辑
人工智能·语言模型·智能手机
云飞云共享云桌面21 小时前
非标自动化工厂研发部门怎么实现一台服务器带10个SolidWorks设计并发
运维·服务器·人工智能·3d·自动化·电脑·制造
阿乔外贸日记21 小时前
外贸风控|美国市场7大类欺诈模式解析与风控框架
大数据·人工智能·物联网·microsoft·智能手机
老李IT笔记1 天前
抹除和升系统可以合成一条命令了:强制更新夹在抹除里怎么用,什么情况下不该用
ios·智能手机
软擎1 天前
轻虾数据恢复软件:客户下周来验厂,电脑开不了机怎么扫描硬盘
电脑·数据恢复·轻虾数据恢复软件
꧁坚持很酷꧂1 天前
Windows10电脑通过Xftp传输文件给Windows平板
windows·电脑