How to tell if current running Apple Watch size/dimension is 38mm or 42mm?
Asked Answered
C

12

16

We know that there are two screen sizes for Apple Watch: 38mm and 42mm. The WKInterfaceDevice class provides a readable property named screenBounds. I wrote an extension for WKInterfaceDevice, trying to add a method to detect current device type.

import WatchKit

enum WatchResolution {

    case Watch38mm, Watch42mm
}

extension WKInterfaceDevice {

    class func currentResolution() -> WatchResolution {

        let watch38mmRect = CGRectMake(0.0, 0.0, 136.0, 170.0)
        let watch42mmRect = CGRectMake(0.0, 0.0, 156.0, 195.0)

        let currentBounds = WKInterfaceDevice.currentDevice().screenBounds

        if CGRectEqualToRect(currentBounds, watch38mmRect) {

            return WatchResolution.Watch38mm
        } else {

            return WatchResolution.Watch42mm
        }
    }
}

Is that the correct method to detect Apple Watch size? Is there another method I am missing in the Apple docs?

Calci answered 9/4, 2015 at 2:38 Comment(1)
May I ask what the point of this is? Why does one need to know the model size? Layout decisions should be based on the view bounds, not the model.Digitalis
G
4

This is what I am doing:

enum WatchModel {
    case w38, w40, w42, w44, unknown
}

extension WKInterfaceDevice {

    static var currentWatchModel: WatchModel {
        switch WKInterfaceDevice.current().screenBounds.size {
        case CGSize(width: 136, height: 170):
            return .w38
        case CGSize(width: 162, height: 197):
            return .w40
        case CGSize(width: 156, height: 195):
            return .w42
        case CGSize(width: 184, height: 224):
            return .w44
        default:
            return .unknown
    }
  }
}
Giverin answered 7/2, 2020 at 20:46 Comment(0)
M
25

Your code looks good, but has a few minor issues:

  • You don't have a case for an "unknown" screen size (possibly released in the future)
  • You're using CGRectMake but in Swift you should use a CGRect initializer
  • You're using CGRectEqualToRect but in Swift you can just use == or switch
  • You're explicitly returning WatchResolution enums, but you don't need to be explicit - Swift will figure it out from your method signature
  • You're declaring watch42mmRect but not using it for anything

I would rewrite it like this:

enum WatchResolution {
    case Watch38mm, Watch42mm, Unknown
}

extension WKInterfaceDevice {
    class func currentResolution() -> WatchResolution {
        let watch38mmRect = CGRect(x: 0, y: 0, width: 136, height: 170)
        let watch42mmRect = CGRect(x: 0, y: 0, width: 156, height: 195)

        let currentBounds = WKInterfaceDevice.currentDevice().screenBounds

        switch currentBounds {
        case watch38mmRect:
            return .Watch38mm
        case watch42mmRect:
            return .Watch42mm
        default:
            return .Unknown
        }
    }
}
Misshape answered 9/4, 2015 at 2:39 Comment(2)
This is amazing! Thanks!Strake
It's standard practice for enum case values to begin with lowercase letters, not uppercase.Digitalis
C
9

Update Swift 4:

It includes new launch of Watch resolutions:

enum WatchResolution {
    case Watch38mm, Watch40mm,Watch42mm,Watch44mm, Unknown  
}

extension WKInterfaceDevice {
class func currentResolution() -> WatchResolution {
    let watch38mmRect = CGRect(x: 0, y: 0, width: 136, height: 170)
    let watch40mmRect = CGRect(x: 0, y: 0, width: 162, height: 197)
    let watch42mmRect = CGRect(x: 0, y: 0, width: 156, height: 195)
    let watch44mmRect = CGRect(x: 0, y: 0, width: 184, height: 224)

    let currentBounds = WKInterfaceDevice.current().screenBounds

    switch currentBounds {
    case watch38mmRect:
        return .Watch38mm
    case watch40mmRect:
        return .Watch40mm
    case watch42mmRect:
        return .Watch42mm
    case watch44mmRect:
        return .Watch44mm
    default:
        return .Unknown
    }
  } 
}

Usage

let resol = WKInterfaceDevice.currentResolution()
    switch resol {
    case .Watch38mm, .Watch42mm:
        // Do Something
    case .Watch40mm, .Watch44mm:
        // Do Something
    default:
        // Do Something
    }

Reference Link: Apple Developer Watch Interface Link

Hope that helps....

Thanks

Carmen answered 16/9, 2018 at 17:38 Comment(0)
G
4

This is what I am doing:

enum WatchModel {
    case w38, w40, w42, w44, unknown
}

extension WKInterfaceDevice {

    static var currentWatchModel: WatchModel {
        switch WKInterfaceDevice.current().screenBounds.size {
        case CGSize(width: 136, height: 170):
            return .w38
        case CGSize(width: 162, height: 197):
            return .w40
        case CGSize(width: 156, height: 195):
            return .w42
        case CGSize(width: 184, height: 224):
            return .w44
        default:
            return .unknown
    }
  }
}
Giverin answered 7/2, 2020 at 20:46 Comment(0)
T
3

Your method looks fine and nothing is wrong with it. Another solution is to use contentFrame property of the WKInterfaceController. If the width is 312(156) pixels then its 42mm else is 38mm.

enter image description here

Tipstaff answered 9/4, 2015 at 5:13 Comment(2)
See where it says "This rectangle may be different than the screen bounds."? But the OP is trying to get the screen bounds.Misshape
Because of the height I guess. It may vary because of the content. So that's why I said width.Tipstaff
B
3
CGRect rect = [WKInterfaceDevice currentDevice].screenBounds;
if (rect.size.height == 195.0) {
    // Apple Watch 42mm
}else if (rect.size.height == 170.0){
    // Apple Watch 38mm 
}
Backing answered 9/4, 2015 at 5:38 Comment(1)
Please always add a little more detail to your answer.Severity
S
3

Modified answer based on others from here. Think that looks more proper, plus including new Watch Series 7:

#if os(watchOS)
import WatchKit

public enum WatchCase {
    case watch38mm
    case watch40mm
    case watch41mm
    case watch42mm
    case watch44mm
    case watch45mm
    case unknown
}

extension WKInterfaceDevice {
    public var screenCase: WatchCase {
        switch WKInterfaceDevice.current().screenBounds.size {
        case CGSize(width: 136, height: 170):
            return .watch38mm
        case CGSize(width: 162, height: 197):
            return .watch40mm
        case CGSize(width: 176, height: 215):
            return .watch41mm
        case CGSize(width: 156, height: 195):
            return .watch42mm
        case CGSize(width: 184, height: 224):
            return .watch44mm
        case CGSize(width: 198, height: 242):
            return .watch45mm
        default:
            return .unknown
        }
    }
}
#endif

USAGE:

WKInterfaceDevice.current().screenCase
Skippie answered 4/5, 2022 at 11:41 Comment(0)
C
2

Checking screenBounds seems not working anymore on xCode 7 with iOS 9 with a real device, the watch size returned by Watch 38mm is always 156x195.

My (bad) alternative is to check the viewcontroller contentFrame width or height depending of the view structure

Cardiovascular answered 21/9, 2015 at 17:50 Comment(1)
Found the same issue. Seems like an Apple bug.Malkamalkah
T
1

All the above solutions works fine. Along with screenBounds ([[WKInterfaceDevice currentDevice] screenBounds]), it will be good to check the screenScale ([[WKInterfaceDevice currentDevice] screenScale]) as well. Actual size will be screenBounds * screenScale in that sense.

More reference: https://developer.apple.com/watch/human-interface-guidelines/specifications/

Thibaud answered 13/5, 2015 at 0:2 Comment(0)
P
1

For a Swift 4 shorter example:

enum WatchType {
    case watch38mm, watch42mm
}

extension WKInterfaceDevice {

    class var currentResolution: WatchType {
        // Apple Watch 38mm 136x170 - 42mm 156x195
        return WKInterfaceDevice.current().screenBounds.width == 136 ? .watch38mm : .watch42mm
    }

}
Postorbital answered 30/11, 2017 at 9:16 Comment(0)
M
1

Swift 5 version of @Aaron Brager answer(+ support for new Apple Watches).

enum WatchResolution {
case Watch38mm, Watch40mm, Watch42mm, Watch44mm, Unknown
}

extension WKInterfaceDevice {

class func currentResolution() -> WatchResolution {

    let watch38mmRect = CGRect(x: 0, y: 0, width: 136, height: 170)
    let watch40mmRect = CGRect(x: 0, y: 0, width: 162, height: 197)
    let watch42mmRect = CGRect(x: 0, y: 0, width: 156, height: 195)
    let watch44mmRect = CGRect(x: 0, y: 0, width: 184, height: 224)

    let currentBounds = WKInterfaceDevice.current().screenBounds

    switch currentBounds {
    case watch38mmRect:
        return .Watch38mm
    case watch40mmRect:
        return .Watch40mm
    case watch42mmRect:
        return .Watch42mm
    case watch44mmRect:
        return .Watch44mm
    default:
        return .Unknown
    }
}
}


/*
 all resolutions
 40mm: 394×324
 44mm: 448×368
 38mm: 340×272
 42mm: 390×312
 */
Meadows answered 20/8, 2019 at 5:9 Comment(0)
I
1

I do this to avoid depending too much on current sizes and future proof myself

public enum WatchSizeClass {
    case small, regular
}

public extension WKInterfaceDevice {
    static var currentWatchSizeClass: WatchSizeClass {
        if WKInterfaceDevice.current().screenBounds.size.width < 150 {
            return .small
        } else {
            return .regular
        }
    }
}

Right now, .small is only returned for 38mm.

Irresponsive answered 26/5, 2020 at 1:22 Comment(0)
A
0

Incase somebody else also stumbles on this, here are the current 2024 sizes: 41mm, 45mm and 49mm and these are their dimensions:

enum WatchSize {
  case mm41, mm45, mm49

  static var current: WatchSize {
    let bounds = WKInterfaceDevice.current().screenBounds

    if bounds.width >= 205 && bounds.height >= 251 {
      return .mm49
    } else if bounds.width >= 198 && bounds.height >= 242 {
      return .mm45
    } else if bounds.width >= 176 && bounds.height >= 215 {
      return .mm41
    } else {
      return .mm41
    }
  }
}
Apostatize answered 17/1 at 0:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.