5

I am currently making a widget only application based on SwiftUI that allow users to show some type of informations as time, date etc.. In order to make my application functional I would like to make a preview of the widgets in the app view, also allowing users to set it up.

For now everything is working well, I can select a widget in my application and set it up so the widget updates as well. However, I am facing a problem, after some researches I can’t seem to find a way that allows you to get the widgets sizes according to the device you are using.

I tried to use UIScreen.main.bounds.size but the aspect ratio between widgets sizes and devices sizes aren’t the same.

What I would like to do is making my widget preview adapt to the widgets sizes that the device is actually using. (in other words retrieve the widgets sizes depending on which device you are on)

Is there any solutions to do it dynamically or do I need to make a view for each devices? Thanks in advance.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
Mello
  • 53
  • 1
  • 6
  • Not really, this answer is about supporting multiple widgets sizes. What I was looking for is to retrieve the widgets sizes in app but thanks. Viktor answered what I was looking for – Mello Oct 04 '20 at 12:46

4 Answers4

11

You could map UIScreen.main.bounds.size to widget sizes from Apple documentation: sizes for widgets https://developer.apple.com/design/human-interface-guidelines/widgets/overview/design/

Example for a Small widget:

switch UIScreen.main.bounds.size {
    case CGSize(width: 428, height: 926):   return 170
    case CGSize(width: 414, height: 896):   return 169
    case CGSize(width: 414, height: 736):   return 159
    case CGSize(width: 390, height: 844):   return 158
    case CGSize(width: 375, height: 812):   return 155
    case CGSize(width: 375, height: 667):   return 148
    case CGSize(width: 360, height: 780):   return 155
    case CGSize(width: 320, height: 568):   return 141
    default:                                return 155
    }
Viktor Gavrilov
  • 830
  • 1
  • 8
  • 13
8

You can use displaySize of TimelineProviderContext to get size of current Widget.

func getTimeline(in context: Context, completion: @escaping (Timeline<Item>) -> Void) {
    print(context.displaySize)
    ...
}

You can find it in your Widget Provider.

Tikhonov Aleksandr
  • 13,945
  • 6
  • 39
  • 53
  • This should be the accepted answer. Most idiomatic/correct way to do it without hardcoding screen sizes. – km11 Jun 25 '23 at 12:47
3

i added more sizes if you want.

to get the family value you can use: @SwiftUI.Environment(\.widgetFamily) var family from inside your View

    func widgetHeight(forFamily family:WidgetFamily) -> CGSize {
    // better to use getTimeline func context.displaySize before this one.
    
    switch family {
    case .systemSmall:
        switch UIScreen.main.bounds.size {
        case CGSize(width: 428, height: 926):   return CGSize(width:170, height: 170)
        case CGSize(width: 414, height: 896):   return CGSize(width:169, height: 169)
        case CGSize(width: 414, height: 736):   return CGSize(width:159, height: 159)
        case CGSize(width: 390, height: 844):   return CGSize(width:158, height: 158)
        case CGSize(width: 375, height: 812):   return CGSize(width:155, height: 155)
        case CGSize(width: 375, height: 667):   return CGSize(width:148, height: 148)
        case CGSize(width: 360, height: 780):   return CGSize(width:155, height: 155)
        case CGSize(width: 320, height: 568):   return CGSize(width:141, height: 141)
        default:                                return CGSize(width:155, height: 155)
        }
    case .systemMedium:
        switch UIScreen.main.bounds.size {
        case CGSize(width: 428, height: 926):   return CGSize(width:364, height: 170)
        case CGSize(width: 414, height: 896):   return CGSize(width:360, height: 169)
        case CGSize(width: 414, height: 736):   return CGSize(width:348, height: 159)
        case CGSize(width: 390, height: 844):   return CGSize(width:338, height: 158)
        case CGSize(width: 375, height: 812):   return CGSize(width:329, height: 155)
        case CGSize(width: 375, height: 667):   return CGSize(width:321, height: 148)
        case CGSize(width: 360, height: 780):   return CGSize(width:329, height: 155)
        case CGSize(width: 320, height: 568):   return CGSize(width:292, height: 141)
        default:                                return CGSize(width:329, height: 155)
        }
    case .systemLarge:
        switch UIScreen.main.bounds.size {
        case CGSize(width: 428, height: 926):   return CGSize(width:364, height: 382)
        case CGSize(width: 414, height: 896):   return CGSize(width:360, height: 379)
        case CGSize(width: 414, height: 736):   return CGSize(width:348, height: 357)
        case CGSize(width: 390, height: 844):   return CGSize(width:338, height: 354)
        case CGSize(width: 375, height: 812):   return CGSize(width:329, height: 345)
        case CGSize(width: 375, height: 667):   return CGSize(width:321, height: 324)
        case CGSize(width: 360, height: 780):   return CGSize(width:329, height: 345)
        case CGSize(width: 320, height: 568):   return CGSize(width:292, height: 311)
        default:                                return CGSize(width:329, height: 345)
        }
        
    default:                                return CGSize(width:329, height: 345)
    }
}
Asi Givati
  • 1,348
  • 1
  • 15
  • 31
2

If you're using swift UI you can use a Geometry Reader or use the Environment property wrapper like so and you can compare it against the three sizes .systemSmall, Medium, Large

@Environment(\.widgetFamily) var widgetFamily

Stu P.
  • 1,365
  • 1
  • 14
  • 31
  • This should be the accepted answer. Hardcoded screen sizes makes little sense especially in widgets that are created by the system, for the device. Instead, accept the family of widgets and inspect using geo and create your view within those boundaries. –  Jun 17 '23 at 11:11
  • @TallDane I agree that hardcoded sizes make little sense, but the answer by Tikhonov seems to be better in this regard: https://stackoverflow.com/a/67402707/16168841 – km11 Jun 25 '23 at 12:46