在Flutter中,我们能否检查设备是智能手机还是平板电脑?

64

我正在尝试在我的Flutter应用程序中判断应用是否运行在智能手机或平板电脑上,但是device_info包只能告诉我们设备信息,不能判断设备是否为智能手机或平板电脑。是否有一种方法可以通过检查设备的大小来实现这一点?

非常感谢。 Mahi


你如何精确定义智能手机和平板电脑之间的区别?这与设备是否能够打电话有关吗? - Günter Zöchbauer
嗨,@GünterZöchbauer,是的,我指的是一种可以打电话的设备,因为我在我的应用程序中有一个与联系人通话的选项,但如果设备不能打电话,我想隐藏此选项。 - Mahi
1
谢谢@GünterZöchbauer,我会尝试一下看看是否有效,我不确定iOS是否可以,但我会像答案中提到的那样检查一下,感谢您的帮助。 - Mahi
为什么要排除像Skype这样的VOIP电话呢?仅仅因为它没有电话号码并不意味着它不能打电话。 - Randal Schwartz
感谢@RandalSchwartz,是的,这正是我的应用程序中发生的事情,但我使用的电话选项是专门用于电话呼叫的,所以我只想要电话呼叫。无论如何,我会尝试建议的答案并在此发布详细信息。感谢大家的帮助。 - Mahi
显示剩余2条评论
13个回答

55

1
注意:使用屏幕宽度作为判断平板电脑/手机的基础是官方 Android 处理此问题的方法,因此对于 Flutter 也应该很好用。 - Kirill Karmazin
4
这让我在我的Galaxy A平板电脑和Nexus 7平板电脑模拟器上得到了552分。 - cahyowhy
2
是的!我改变了我的答案,但是由于我使用了你的解决方案,你也遇到了我曾经遇到的问题。我的答案现在使用 550 而不是 600 作为魔数。这是因为该值取决于设备的方向而发生变化。我猜这是因为它只考虑了窗口空间,所以当设备处于横向方向时,状态栏和导航栏从最短的一侧获得了一些空间。因此,600 适用于普通平板电脑,但是当你转向像 Nexus 7 2012 这样的较小设备时,它会将其视为手机。 - Roc Boronat

55

如果您无法访问BuildContext,则可以使用此选项。我从中删除了它。

  String getDeviceType() {
    final data = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
    return data.size.shortestSide < 600 ? 'phone' :'tablet';
  }

3
是的!我改变了我的答案,但是由于我使用了你的解决方案,你遇到了和我一样的问题。我的答案现在使用 550 作为魔术数字,而不是 600。这是因为这个值取决于设备的方向。我猜这是因为它只考虑了窗口空间,所以当设备处于横向方向时,状态栏和导航栏会从最短的一边占用一些空间。所以,600 在常见的平板电脑上有效,但是当你使用像 Nexus 7 2012 这样的较小设备时,它会将其视为手机。 - Roc Boronat

19

一种计算屏幕分辨率对角线的方法。

import 'package:flutter/widgets.dart';
import 'dart:math';

class TabletDetector {

  // iPhone 6S 
  // |_ [portrait]
  //    |_ size: 375.0x667.0, pixelRatio: 2.0, pixels: 750.0x1334.0
  //       |_ diagonal: 765.1888655750291
  // |_ [horizontal]
  //    |_ size: 667.0x375.0, pixelRatio: 2.0, pixels: 1334.0x750.0
  //       |_ diagonal: 765.1888655750291

  // iPhone X 
  // |_ [portrait]
  //    |_ size: 375.0x812.0, pixelRatio: 3.0, pixels: 1125.0x2436.0
  //       |_ diagonal: 894.4098613052072
  // |_ [horizontal]
  //    |_ size: 812.0x375.0, pixelRatio: 3.0, pixels: 2436.0x1125.0
  //       |_ diagonal: 894.4098613052072

  // iPhone XS Max 
  // |_ [portrait]
  //    |_ size: 414.0x896.0, pixelRatio: 3.0, pixels: 1242.0x2688.0
  //       |_ diagonal: 987.0217829409845
  // |_ [horizontal]
  //    |_ size: 896.0x414.0, pixelRatio: 3.0, pixels: 2688.0x1242.0
  //       |_ diagonal: 987.0217829409845

  // iPad Pro (9.7-inch) 
  // |_ [portrait]
  //    |_ size: 768.0x1024.0, pixelRatio: 2.0, pixels: 1536.0x2048.0
  //       |_ diagonal: 1280.0
  // |_ [horizontal]
  //    |_ size: 1024.0x768.0, pixelRatio: 2.0, pixels: 2048.0x1536.0
  //       |_ diagonal: 1280.0

  // iPad Pro (10.5-inch) 
  // |_ [portrait]
  //    |_ size: 834.0x1112.0, pixelRatio: 2.0, pixels: 1668.0x2224.0
  //       |_ diagonal: 1390.0
  // |_ [horizontal]
  //    |_ size: 1112.0x834.0, pixelRatio: 2.0, pixels: 2224.0x1668.0
  //       |_ diagonal: 1390.0

  // iPad Pro (12.9-inch) 
  // |_ [portrait]
  //    |_ size: 1024.0x1366.0, pixelRatio: 2.0, pixels: 2048.0x2732.0
  //       |_ diagonal: 1707.2000468603555
  // |_ [horizontal]
  //    |_ size: 1366.0x1024.0, pixelRatio: 2.0, pixels: 2732.0x2048.0
  //       |_ diagonal: 1707.2000468603555

  static bool isTablet(MediaQueryData query) {
    var size = query.size;
    var diagonal = sqrt(
      (size.width * size.width) + 
      (size.height * size.height)
    );

    /*
    print(
      'size: ${size.width}x${size.height}\n'
      'pixelRatio: ${query.devicePixelRatio}\n'
      'pixels: ${size.width * query.devicePixelRatio}x${size.height * query.devicePixelRatio}\n'
      'diagonal: $diagonal'
    );
    */

    var isTablet = diagonal > 1100.0;
    return isTablet;
  }
}

1
我稍微修改了一下,通过将函数改为没有参数的内部函数_internal _isTablet。然后在其中使用MediaQueryData.fromWindow(WidgetsBinding.instance!.window)公开了一个无参数方法。在这里学到了一些东西。我是从Swift领域转过来,在Dart池中试水。 - Nick N
让我们考虑三星S21,分辨率为1080x2265,像素比为2.8125。根据你的计算,这些统计数据将导致isTablet = true!我们应该如何处理? - Ahmed Almahdie

15

嗨,谢谢你的回复。我会尝试这个例子,看看是否有帮助。非常感谢。 - Mahi

15

这里与其他答案相同,但返回enum而不是boolString。由于它更封闭,使用起来更容易。

import 'package:flutter/widgets.dart';

enum DeviceType { Phone, Tablet }

DeviceType getDeviceType() {
  final data = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
  return data.size.shortestSide < 550 ? DeviceType.Phone : DeviceType.Tablet;
}

感谢 @Chandler 和 @bakua 的启发 :·)


2
编辑!现在魔数是550而不是600。这是因为该值取决于设备的方向而发生变化。我猜这是因为它只考虑了窗口空间,所以当设备处于横向时,状态栏和导航栏从最短的一侧获得了一些空间。因此,600适用于普通平板电脑,但当您转向像Nexus 7 2012这样的较小设备时,它会将其视为手机。在这种情况下,当设备处于横向时,最短的一侧为552。因此,550成为新的魔数! - Roc Boronat
我喜欢这个解决方案,但我觉得将其转换为K getter可以进一步改进它,这样它就像其他Flutter系统常量(如kIsWeb)一样。DeviceType get kDeviceType { ... } - Jason Perfetto
@JasonPerfetto 这也是个好主意:·) - Roc Boronat

9

针对 Android,正如 @Chandler 所说,你应该检查屏幕的最小尺寸,但是对于 iOS,你可以使用 device_info 包来100%准确地识别是否为 iPad:

pubspec.yaml中添加:

device_info: ^0.4.2+4

  static Future<bool> isTablet(BuildContext context) async {

    if (Platform.isIOS) {
      DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
      IosDeviceInfo iosInfo = await deviceInfo.iosInfo;

      return iosInfo.model.toLowerCase() == "ipad";
    } else {
      // The equivalent of the "smallestWidth" qualifier on Android.
      var shortestSide = MediaQuery.of(context).size.shortestSide;

      // Determine if we should use mobile layout or not, 600 here is
      // a common breakpoint for a typical 7-inch tablet.
      return shortestSide > 600;
    }
  }

这种方法可能更可靠,但它是异步的,并且需要上下文,因此在启动时初始化配置不是非常有用。 - Apoleo

4
2023年,Dart 3解决方案受到@bakua答案的启发,还有这个答案
bool get isTablet {
  final firstView = WidgetsBinding.instance.platformDispatcher.views.first;
  final logicalShortestSide = firstView.physicalSize.shortestSide / firstView.devicePixelRatio;
  return logicalShortestSide > 600;
}


1
您可以使用sizer包中的DeviceType.tablet。您需要执行以下操作:
SizerUtil.deviceType == DeviceType.tablet

该字段使用this logic进行设置,这与此处最受欢迎的答案相同。我已经使用了sizer使我的应用程序具有响应性,因此使用它来确定设备是否为平板电脑非常方便。

你好,这个软件包的最后发布日期是2021年9月15日(14个月前)。这个软件包适合使用吗? - My Car
代码和功能非常简单(<200行),因此在功能/错误修复方面没有太多要添加的。我仍然在Android/iOS上使用它,没有任何问题。 - user2233706

1
通常 Android 平板电脑和 iPad 的宽高比(宽度:高度)在 0.75 ~ 1.4 的范围内,以下是最快的检查方法。我们可以根据宽高比调整用户界面。
bool isTablet;
double ratio = MediaQuery.of(context).size.width / MediaQuery.of(context).size.height;
if( (ratio >= 0.74) && (ratio < 1.5) )
{
  isTablet = true;
} else{
  isTablet = false;
}

0
请在您的项目中添加以下实用程序类并使用它。
class DeviceUtil {
  static String get _getDeviceType {
    final data = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
    return data.size.shortestSide < 550 ? 'phone' : 'tablet';
  }

  static bool get isTablet {
    return _getDeviceType == 'tablet';
  }
}

使用方法:

DeviceUtil.isTablet; //true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接