Hiding Picker's focus border on watchOS in SwiftUI
Asked Answered
T

4

2

I need to use a Picker view but I don't see any options to hide the green focus border.

Code:

@State private var selectedIndex = 0
var values: [String] = (0 ... 12).map { String($0) }

var body: some View {
    Picker(selection: $selectedIndex, label: Text("")) {
        ForEach(0 ..< values.count) {
            Text(values[$0])
        }
    }
    .labelsHidden()
}

Screenshot of the Picker

Turbinate answered 18/12, 2020 at 17:14 Comment(0)
W
4

The following extension puts a black overlay over the picker border.

Result

Screenshot of the result

Code

extension Picker {
    func focusBorderHidden() -> some View {
        let isWatchOS7: Bool = {
            if #available(watchOS 7, *) {
                return true
            }

            return false
        }()

        let padding: EdgeInsets = {
            if isWatchOS7 {
                return .init(top: 17, leading: 0, bottom: 0, trailing: 0)
            }

            return .init(top: 8.5, leading: 0.5, bottom: 8.5, trailing: 0.5)
        }()

        return self
            .overlay(
                RoundedRectangle(cornerRadius: isWatchOS7 ? 8 : 7)
                    .stroke(Color.black, lineWidth: isWatchOS7 ? 4 : 3.5)
                    .offset(y: isWatchOS7 ? 0 : 8)
                    .padding(padding)
            )
    }
}

Usage

Make sure .focusBorderHidden() is the first modifier.

Picker( [...] ) {
    [...]
}
.focusBorderHidden()
[...]
Wilser answered 25/12, 2020 at 1:14 Comment(0)
B
2

On the Picker, something like this can be added to cover up the green border.

@ScaledMetric var borderWidth: CGFloat = 5 // or it can be 3

Picker {
...
}.border(Color.black, width: borderWidth)
Bimonthly answered 5/3, 2022 at 22:26 Comment(0)
P
0

Adding a mask of cornerRadius of whatever required but with a padding of 2 or over (so as to mask the outer edge of the view) as the green border width on the watch tends to be around 2... will do the trick

.mask(RoundedRectangle(cornerRadius: 12).padding(2))

I like the border method from Ray Hunter too but to keep things tidy and simple I rather stay away from having lots and lots of @... variables

Protochordate answered 6/2, 2023 at 5:28 Comment(0)
G
0

Instead of using a picker, you can use whatever view you want (with or without a custom border) along with the .digitalCrownRotation() modifier.

See here for instructions: https://www.hackingwithswift.com/quick-start/swiftui/how-to-read-the-digital-crown-on-watchos-using-digitalcrownrotation

Note that it only works on a Double value, but you can make it appear integer using text formatting and by setting appropriate parameters (e.g., the step value).

The main functional difference I've found is that you can't "swipe" to change the value (but I think this is actually a bonus if you need to put it in a ScrollView...).

Lastly, be aware that for getting focus on a tap, it'll only work if they tap on non "clear space" inside your view (not the space between a border and any text/images inside). After some research I found that applying a .contentShape(Rectangle()) to the view acting as a picker fixed this. I think it needs to be before the .digitalCrownRotation() modifier, but I don't remember for sure.

Glabrous answered 2/4, 2023 at 3:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.