Can we check the device to be smartphone or tablet in Flutter?

58.3k Views Asked by At

I am actually trying to figure out if the app is running on a smartphone or tablet in my flutter app but the package device_info can only tell about the device but not whether the device is a smartphone or tablet. Is there a way we can do this by checking the size of the device?

Many thanks Mahi

12

There are 12 best solutions below

1
On BEST ANSWER

Despite iOS has a clear separation between phone and tablet, this doesn't happen in Android. You need to base the choice based on screen width.

Check this article to see an example on how to discriminate: https://flutter.rocks/2018/01/28/implementing-adaptive-master-detail-layouts/

0
On

Usually the Aspect ratio ( width : height) of Android Tablet and iPad is in the range of from 0.75 ~ 1.4, following is the fastest way to check. We can adjust the UI according to the Aspect ratio.

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;
}
1
On

For Android as @Chandler said you should check the smallest size of the screen, but for iOS, you can identify if it's iPad with 100% accuracy using device_info package:

add in 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;
    }
  }
2
On

One of the ways is calculated diagonal for screen resolution.

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;
  }
}
3
On
// 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.
final bool useMobileLayout = shortestSide < 600;

Copied from https://flutter.rocks/2018/01/28/implementing-adaptive-master-detail-layouts/

Thanks @Sergi

2
On

You can use DeviceType.tablet from the sizer package. You would do:

SizerUtil.deviceType == DeviceType.tablet

The field is set using this logic, which is the same as the most accepted answer here. I already use sizer to make my app responsive, so using it to determine whether the device is a tablet is convenient.

0
On

Create a dart file "size_config.dart"

import 'dart:io';
import 'package:flutter/widgets.dart';
import 'dart:async';
import 'package:device_info_plus/device_info_plus.dart';

class SizeConfig {
  static late MediaQueryData _mediaQueryData;
  static late double screenWidth;
  static late double screenHeight;
  static late double blockSizeHorizontal;
  static late double blockSizeVertical;
  static late double safeBlockHorizontal;
  static late double safeBlockVertical;
  static bool isIpad = false;

  void init(BuildContext context) async {
    _mediaQueryData = MediaQuery.of(context);
    screenWidth = _mediaQueryData.size.width;
    screenHeight = _mediaQueryData.size.height;
    blockSizeHorizontal = screenWidth / 100;
    blockSizeVertical = screenHeight / 100;
    isIpad = await isTablet(context);
  }

  static Future<bool> isTablet(BuildContext context) async {
    bool isTab = false;
    if (Platform.isIOS) {
      DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
      IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
      if (iosInfo.model.toLowerCase() == "ipad") {
        isTab = true;
      } else {
        isTab = false;
      }
      return isTab;
    } else {
      var shortestSide = MediaQuery.of(context).size.shortestSide;
      if (shortestSide > 600) {
        isTab = true;
      } else {
        isTab = false;
      }
      return isTab;
    }
  }
}

Calling

@override
  Widget build(BuildContext context) {
    SizeConfig().init(context);

    var height = SizeConfig.screenHeight;
    var width = SizeConfig.screenWidth;

    bool isIpad = SizeConfig.isIpad;
2
On

You can use this if you don't have an access to BuildContext. I took it out from sdk/flutter/packages/flutter/lib/src/widgets/app.dart:1252.

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

You can use device_info_plus package from flutter https://pub.dev/packages/device_info_plus

static Future<bool> isTablet(BuildContext context) async {
bool isTab=false;
if (Platform.isIOS) {
  DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
  IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
  if(iosInfo.model?.toLowerCase() == "ipad"){
    isTab=true;
  }else{
    isTab=false;
  }
  return isTab;
} else {
  var shortestSide = MediaQuery.of(context).size.shortestSide;
  if(shortestSide > 600){
    isTab=true;
  }else{
    isTab=false;
  }
  return isTab;
}}

Calling..

Future checkDeviceType() async {

bool iPad = await isTablet(context);
    
    if(iPad){
       //write your logic here..
     }
}
0
On

I wrote this context extension depending on the other answers, it works for me:

extension ContextExt on BuildContext {
    bool get isPhone => MediaQuery.of(this).size.width < 600.0;
    bool get isTablet => MediaQuery.of(this).size.width >= 600.0;
}

Usage:

final iconSize = context.isTablet ? 50.0 : 30.0;
0
On

2023, Dart 3 solution inspired from @bakua's answer, and also this answer

bool get isTablet {
  final firstView = WidgetsBinding.instance.platformDispatcher.views.first;
  final logicalShortestSide = firstView.physicalSize.shortestSide / firstView.devicePixelRatio;
  return logicalShortestSide > 600;
}

3
On

Here's the same than in other aswers, but returning an enum instead of a bool or a String. As it's more closed, it's easier to use it.

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;
}

Thanks to @Chandler and @bakua for the inspiration :·)