SwiftUI - не позволяет списку сбрасывать позицию прокрутки вверх при выборе элемента - PullRequest
0 голосов
/ 26 июня 2019

Итак, мы возились с SwiftUI, и все работает, за исключением того, что список сбрасывает свою позицию прокрутки в верхнюю часть всякий раз, когда выбирается элемент.Ничто, что я делаю, не исправляет это.Код -

struct FontSettingsView : View {

    @ObjectBinding var settings: FontSettings

    var body: some View {
        NavigationView {
            ContentView(settings: settings)
                .navigationBarTitle(Text("Font"), displayMode: .inline)
        }
    }

    struct ContentView: View {

        @State var settings: FontSettings

        var body: some View {
            VStack {

                HeaderView(settings: $settings)

                FontListView(excludedFontNames: settings.excludedFontNames) { fontName in
                    self.$settings.name.value = fontName
                }
            }
        }

        struct HeaderView: View {

            @Binding var settings: FontSettings

            var body: some View {
                VStack {

                    HStack {
                        VStack (alignment: .leading) {
                            Text("Custom font size:")
                                .font(.body)
                            Text("If disabled, will use system settings")
                                .font(.caption)
                        }
                        Toggle(isOn: $settings.isCustomSize) {
                            Text("")
                        }
                    }

                    Slider(value: $settings.size, from: 10, through: 30, by: 0.1)
                        .disabled($settings.isCustomSize.value == false)

                    Text("Current font: \($settings.name.value)")
                        .customFont(using: self.settings)
                        .padding()
                        .animation(.default)

                }.padding()
            }
        }

        struct FontListView: View {

            struct FontName: Identifiable {
                var id = UUID()
                let value: String
            }

            private let fontNames: [FontName]
            private let tapped: ((String) -> ())?

            init(excludedFontNames: [String] = [], tapped: ((String) -> ())?) {
                self.fontNames = UIFont.familyNames.sorted().filter({ excludedFontNames.contains($0) == false }).map { FontName(value: $0) }
                self.tapped = tapped
            }

            var body: some View {
                List(fontNames) { fontName in
                    Button(action: {
                        self.tapped?(fontName.value)
                    }) {
                        Text(fontName.value).customFont(named: fontName.value)
                    }
                }
            }
        }
    }
}

К сожалению, вся документация и примеры связаны с переходом на новый экран при выборе элемента, что не является моим намерением.

Некоторый дополнительный код длялюбой, кто хочет запустить все это -

class FontSettings: BindableObject {

    private static let defaultSize: CGFloat = 20

    var didChange = PassthroughSubject<Void, Never>()

    var excludedFontNames: [String] = []

    var name: String = "Helvetica" {
        didSet {
            self.didChange.send()
        }
    }
    var size: CGFloat = FontSettings.defaultSize {
        didSet {
            self.didChange.send()
        }
    }
    var isCustomSize: Bool = false {
        didSet {
            if self.isCustomSize == false {
                self.size = FontSettings.defaultSize
            }
            self.didChange.send()
        }
    }
}


extension View {

    func customFont(named fontName: String, style: UIFont.TextStyle = .body) -> Self.Modified<CustomFont> {
        return self.modifier(CustomFont(fontName: fontName, textStyle: style))
    }

    func customFont(named fontName: String, size: CGFloat) -> Self.Modified<CustomFont> {
        return self.modifier(CustomFont(fontName: fontName, size: size))
    }

    func customFont(using settings: FontSettings) -> Self.Modified<CustomFont> {
        if settings.isCustomSize {
            return self.modifier(CustomFont(fontName: settings.name, size: settings.size))
        }
        return self.modifier(CustomFont(fontName: settings.name, textStyle: .body))
    }
}


struct CustomFont: ViewModifier {

    let fontName: String
    let fontSize: CGFloat?
    let textStyle: UIFont.TextStyle?

    init(fontName: String, textStyle: UIFont.TextStyle) {
        self.fontName = fontName
        self.textStyle = textStyle
        self.fontSize = nil
    }

    init(fontName: String, size: CGFloat) {
        self.fontName = fontName
        self.fontSize = size
        self.textStyle = nil
    }

    // trigger view refresh when the ContentSizeCategory changes
    @Environment(\.sizeCategory) var sizeCategory: ContentSizeCategory

    func body(content: Content) -> some View {

        if let fontSize = self.fontSize {
            return content.font(.custom(self.fontName, size: fontSize))
        }

        guard let textStyle = self.textStyle, let size = self.fontSizes[textStyle] else {
            fatalError("Unrecognized textStyle")
        }

        let fontMetrics = UIFontMetrics(forTextStyle: textStyle)
        let fontSize = fontMetrics.scaledValue(for: size)

        return content.font(.custom(self.fontName, size: fontSize))
    }

    // normal font sizes per style, as defined by Apple
    private let fontSizes: [UIFont.TextStyle: CGFloat] = [
        .largeTitle: 34,
        .title1: 28,
        .title2: 22,
        .title3: 20,
        .headline: 17,
        .body: 17,
        .callout: 16,
        .subheadline: 15,
        .footnote: 13,
        .caption1: 12,
        .caption2: 11
    ]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...