AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / user-145552

Z S's questions

Martin Hope
Z S
Asked: 2025-03-07 03:17:04 +0800 CST

SwiftUI:TextField 没有在按钮内获得焦点变化

  • 5

我有一个 SwiftUI List(在 macOS 上),我想在每一行显示一些内容TextFields,并观察焦点在选择或取消选择单个文本字段时如何变化。如果我只在每一行List显示一个纯文本TextField,这似乎可以正常工作,但如果我将其嵌入视图TextField内部Button,焦点更改通知将停止工作。我想要“按钮”功能,以便用户可以点击行上的任意位置并激活文本字段,而不是精确点击文本字段边界。

以下是一些代码来演示问题。List如果您RowView取消注释 (1),则焦点更改通知会起作用。如果您注释掉 (1) 并取消注释RowViewWithButton(2),则按钮功能会起作用,但我无法再收到焦点更改通知。

import SwiftUI

// test on macOS target
struct ContentView: View {
    @State private var textFields = Array(repeating: "", count: 4)
    @FocusState private var focusedField: Int?

    var body: some View {
        List(0..<4, id: \.self) { index in
            
            // 1. works with focus notification changes
            RowView(index: index, text: $textFields[index], focusedField: $focusedField)
            
            // 2. button works, but no focus notifications on text field
            //RowViewWithButton(index: index, text: $textFields[index], focusedField: $focusedField)
        }
    }
}

struct RowView: View {
    let index: Int
    @Binding var text: String
    @FocusState.Binding var focusedField: Int?

    var body: some View {
        HStack {
            Text("Row \(index + 1):")
            TextField("", text: $text)
                .multilineTextAlignment(.leading)
                .focused($focusedField, equals: index)
        }
        .onChange(of: focusedField) { newFocus in
            if newFocus == index {
                print("TextField \(index) is in focus")
            } else {
                print("TextField \(index) lost focus")
            }
        }
        .padding(.vertical, 4)
    }
}


struct RowViewWithButton: View {
    let index: Int
    @Binding var text: String
    @FocusState.Binding var focusedField: Int?

    var body: some View {
        Button (action: {
            print("RowView - button selected at index \(index)")
            focusedField = index
        }) {
            HStack {
                Text("Row \(index + 1):")
                TextField("", text: $text)
                    .multilineTextAlignment(.leading)
                    .focused($focusedField, equals: index)
            }
            .onChange(of: focusedField) { newFocus in
                if newFocus == index {
                    print("TextField \(index) is in focus")
                } else {
                    print("TextField \(index) lost focus")
                }
            }
            .foregroundColor(.primary)
        }
        .buttonStyle(BorderlessButtonStyle())
        .padding(.vertical, 4)
    }
}

#Preview {
    ContentView()
        .frame(width: 320, height: 250)
}

有趣的是,当我在 iOS 上测试时,两种情况下都可以正常工作。但我需要适用于 macOS 的解决方案。

更新:

使用onTapGesture而不是Button确实可以改善情况,但会引入一个新错误。如果我最初点击该行,它最初可以正常工作,点击任意位置都会激活文本字段。但是在输入一些文本并按下回车键(或以任何方式失去焦点)后,如果我尝试点击 所在的行部分TextField,它只有在点击现有文本时才有效......而不是点击它前面的空白处。

我将其添加.background(.red)到了 HStack,并.background(.blue)添加了一个屏幕截图来演示该问题。

在此处输入图片描述

swiftui
  • 2 个回答
  • 49 Views
Martin Hope
Z S
Asked: 2025-02-07 03:41:20 +0800 CST

SwiftUI:将 @FocusState.Binding 与视图初始化程序结合使用

  • 5

我有一个带有 的视图@FocusState,我想将其传递到子视图中。对于子视图,我使用@FocusState.Binding。如果我不使用自定义初始化程序,这可以正常工作……但我无法弄清楚它如何与自定义视图初始化程序一起工作的语法,出于其他原因我需要它。

这是有效的代码:

struct TestListButtonsAndListFocusView: View {
    
    @FocusState var buttonFocusState: ButtonState?
    @ObservedObject var viewModel: ViewModel = ViewModel()
    
    var body: some View {
        TestListView(viewModel: viewModel, bindedFocusButtonState: $buttonFocusState) // for custom init, replace with following line
        //TestListView(viewModel: viewModel, focusButtonState: $buttonFocusState) // 1. Uncomment this for custom initializer
    }
}

struct TestListView: View {
    @State private var items1: [TimedItem] = [
        TimedItem(number: 1, timestamp: "2024-11-20 10:00"),
        TimedItem(number: 2, timestamp: "2024-11-20 11:00"),
        TimedItem(number: 3, timestamp: "2024-11-20 12:00")
    ]
    
    @ObservedObject var viewModel: ViewModel
    @FocusState.Binding var bindedFocusButtonState: ButtonState?
    
    @State var selectedItem: TimedItem.ID?
    
    var body: some View {
        List(items1, selection: $selectedItem) { item in
            ContentListItemView(item: item)
        }
        .onChange(of: bindedFocusButtonState) {
            if let bindedFocusButtonState {
                print("TestListView - bindedListFocusState has changed to \(bindedFocusButtonState)")
                if bindedFocusButtonState == .one && selectedItem == nil {
                    selectedItem = items1.first?.id
                }
            } else {
                print("ListOneView - bindedListFocusState has changed to nil")
            }
        }
    }
    
    // 2. Uncomment this
    /*init(viewModel: ViewModel, focusButtonState: FocusState<ButtonState?>.Binding) {
        // how to pass in @FocusState.Binding?
        self.viewModel = viewModel
        self.bindedFocusButtonState = focusButtonState
        // Error: Cannot assign value of type 'FocusState<ButtonState?>.Binding' to type 'ButtonState?'
    }*/
}

public class ViewModel: NSObject, ObservableObject {
    
    @Published public var selectedButton: ButtonState? = ButtonState.one
}

public enum ButtonState: Int, CaseIterable, Hashable, Identifiable {
    
    public var id: Self {
        return self
    }
    case one, two, three
}

    
#Preview {
    TestListButtonsAndListFocusView()
}

但是,如果我取消注释自定义初始化程序的行,然后取消注释TestListButtonsAndListFocusView使用自定义初始化程序的行,则语法错误,并且会出现错误:

错误:无法将“FocusState<ButtonState?>.Binding”类型的值分配给“ButtonState?”类型

我不确定如何以@FocusState.Binding这种方式初始化。我知道如果我使用var bindedFocusButtonState: FocusState<ContactTabStyle?>.Binding,然后在初始化程序中使用它,它会起作用。但我真的很想弄清楚如何将 new@FocusState.Binding与自定义初始化程序一起使用,因为它避免了必须访问wrappedValue并且更容易观察onChange

swift
  • 1 个回答
  • 19 Views
Martin Hope
Z S
Asked: 2024-12-12 15:06:58 +0800 CST

SwiftUI List 支持选择不同的模型类型

  • 5

我正在尝试为侧边栏视图实现一个 SwiftUI 列表,该列表至少具有 3 种不同类型的数据点:a) 一个固定的枚举列表,b) 一个来自使用 Core Data 的 @FetchRequest 的“标签”列表,c) 一个类似的来自不同@FetchRequest 的“组”列表。

我不知道如何List在此设置中处理多项选择。用户应该能够从不同的部分中进行选择(我会收到更改通知以微调处理)。我尝试将“选择”类型设为 UUID,并明确设置每个叶视图的 ID,但似乎不起作用(我没有选择突出显示)。

这是我列出的清单:

struct CombinedListView: View {
    @FetchRequest(
        entity: CJTag.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \CJTag.displayOrder, ascending: true)]
    )
    var tags: FetchedResults<CJTag>

    @FetchRequest(
        entity: PrivateGroups.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \PrivateGroups.displayOrder, ascending: true)]
    )
    var groups: FetchedResults<PrivateGroups>

    @State private var selectedItems = Set<UUID>()
    
    var body: some View {
        NavigationView {
            VStack {
                List(selection: $selectedItems) {
                    
                    // section for Tabs
                    Section(header: Text("Main Tabs")) {
                        ForEach(MainTab.allCases, id: \.rawValue) { tab in
                            Text(tab.rawValue)
                                .id(tab.id)
                        }
                    }
                    
                    // Section for Tags
                    if !tags.isEmpty {
                        Section(header: Text("Tags")) {
                            ForEach(tags) { tag in
                                Text(tag.tagName ?? "Tag")
                                    .id(tag.objectID.uriRepresentation().absoluteString) // Directly tag with UUID
                                    .contentShape(Rectangle())
                            }
                        }
                    }
                    // Section for Groups
                    if !groups.isEmpty {
                        Section(header: Text("Groups")) {
                            ForEach(groups) { group in
                                Text(group.groupName ?? "Group")
                                    .id(group.objectID.uriRepresentation().absoluteString)
                                    .contentShape(Rectangle())
                            }
                        }
                    }
                }
                .listStyle(SidebarListStyle())
                .navigationTitle("Selectable List")
            }
        }
    }
}

我知道,如果我只有NSManagedObjects列表,我可以将“选择”类型设置为NSManagedObjectID,这样它就可以工作了。但我也需要它支持枚举案例列表。

我也尝试过为每一行视图设置tag(使用与修饰符相同的内容id),但那也不起作用。我确信这是选择“类型”不匹配的情况,但我找不到实现此目的的最佳设置。

编辑:

为 MainTab 添加代码:

// Enum for Main Tabs
enum MainTab: String, CaseIterable, Identifiable {
    case home = "Home"
    case favorites = "Favorites"
    case settings = "Settings"
    case profile = "Profile"
    case help = "Help"

    var id: String { rawValue }
    var iconName: String { rawValue.lowercased() }
}
swiftui
  • 2 个回答
  • 43 Views
Martin Hope
Z S
Asked: 2024-04-25 06:04:44 +0800 CST

具有泛型的 contextMenu 的 SwiftUI ViewModifier

  • 6

我想为“contextMenu forSelectionType: menu:”添加 iOS16 API,但我还需要支持 iOS15,因此我需要一个条件ViewModifier。我正在努力寻找正确的语法。

据我所知,我的ViewModifier应该是这样的:

struct CompatibilityListContextMenuModifier<V>: ViewModifier where V: View {

    let menu: (Set<Person.ID>) -> V
    
    func body(content: Content) -> some View {
      if #available(iOS 16.0, macOS 13.0, *) {
          content
              .contextMenu(forSelectionType: Person.ID.self, menu: menu)
        } else {
            content
        }
    }
}

但我如何在我的列表中使用它:

List (selection: $contactsListOptions.multiSelectedContacts){
   // ...
}
.modifier(CompatibilityListContextMenuModifier(menu: items in {
            if items.isEmpty { // Empty area menu.
                Button("New Item") { }

            } else if items.count == 1 { // Single item menu.
                Button("Copy") { }
                Button("Delete", role: .destructive) { }
            }
            else {
                Button("MultipleSelection Items") { }
            }
        }))

这给了我一个语法错误:

在范围内找不到“项目”

如果我尝试传递选择绑定:

.modifier(CompatibilityListContextMenuModifier(menu: contactsListOptions.multiSelectedContacts in {
        if contactsListOptions.multiSelectedContacts.isEmpty { // Empty area menu.
            Button("New Item") { }

        } else if contactsListOptions.multiSelectedContacts.count == 1 { // Single item menu.
            Button("Copy") { }
            Button("Delete", role: .destructive) { }
        }
        else {
            Text("MultipleSelection Items")
        }
    }))

我收到错误:

无法将类型“Set<Person.ID>”(又名“Set”)的值转换为预期参数类型“(Set<Person.ID>) -> V”(又名“(Set) -> V”)

和

无法推断通用参数“V”

有条件地编译此 API 的正确方法是什么?

swiftui
  • 1 个回答
  • 13 Views
Martin Hope
Z S
Asked: 2024-02-08 06:51:00 +0800 CST

SwiftUI:核心数据列表不会随着关系属性的更改而更新

  • 5

我有一个简单的用例,其中我有一个核心数据模型,其中具有(具有“时间戳”属性)和与(具有“tagName”属性)的Item一对一关系。Tag我想使用 SwiftUI 显示项目列表,并在每一行中显示项目的时间戳和 tag.tagName(如果可用)。

我遇到的问题是,如果我更新与某个项目关联的 tagName,它不会在 SwiftUI 视图中自动刷新。任何更新都会Item自动刷新,如果我重新启动应用程序,它也会获取更改......但它不会自动发生。

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>

    var body: some View {
        NavigationView {
            
            List {
                Section {
                    ForEach(items) { item in
                            
                        VStack (alignment: .leading){
                            Text(item.timestamp!, formatter: itemFormatter)
                            
                            if let tag = item.tag, let name = tag.tagName {
                                Text("Tag: \(name)")
                            }
                        }
                    }
                    .onDelete(perform: deleteItems)
                } header: {
                    Text("Items")
                }
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
                
                ToolbarItem (placement: .navigationBarLeading) {
                    Button(action: addTagItem) {
                        Label("Add Tag", systemImage: "tag")
                    }
                }
                ToolbarItem(placement: .navigationBarLeading) {
                    Button(action: editTagItem) {
                        Label("Change Tag Name", systemImage: "phone")
                    }
                }
            }
        }
   }

    private func addItem() {
        withAnimation {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()
            
            try? viewContext.save()
        }
    }

    private func addTagItem() {
        withAnimation {
            let newItem = Tag(context: viewContext)
            newItem.tagName = "Design"

            if let item = items.first {
                item.tag = newItem
            }
            try? viewContext.save()
        }
    }
    private func editTagItem() {
        withAnimation {
            if let item = items.first, let tag = item.tag  {
                tag.tagName = "changed"
            }
            
            try? viewContext.save() // <-- should update the List, but doesn't
            
            if let item = items.first, let tag = item.tag {
                tag.objectWillChange.send() // tried this, doesn't work
            }
            
        }
    }
}

我添加了工具栏按钮来测试添加新项目、新标签并将第一个项目的标签设置为第一个标签,然后设置一个更改标签名称的场景。前两个函数工作正常,但更改 tagName 不会更新列表视图。

看起来 SwiftUI只@FetchRequest监听更改Item。我想这与 which 会做同样的事情类似NSFetchedResultsController,但我希望 SwiftUI 能够改善这种情况。在我查看的其他问题中,objectWillChange.send似乎有帮助,但似乎并没有解决我的问题。

无论如何,如果关系属性发生更改,刷新完整列表的最佳方法是什么?

swiftui
  • 1 个回答
  • 12 Views
Martin Hope
Z S
Asked: 2024-02-06 04:15:11 +0800 CST

使用matchedGeometryEffect为边框创建“滑动”效果

  • 5

我正在尝试创建一个带有水平行选项的自定义“选项卡”选择控件,用户可以选择 N 个选项之一。“选定”选项周围将有一个“边框”。这是我制作的原型:

@objc public enum ContactTabStyle: Int, CaseIterable {
    case one, two, three, four
    
    public var segmentTitle: String {
        switch self {
            case .one: return "Hello"
            case .two: return "World"
            case .three: return "Three"
            case .four: return "Four"
        }
    }
}

struct SwiftUIView: View {
    let segments: [ContactTabStyle] = [.one, .two, .three, .four]
    @State var selectedTab: ContactTabStyle = .one
    
    @Namespace var tabName
    
    var body: some View {
        HStack {
            ForEach(segments, id: \.self) { segment in
                Button {
                    selectedTab = segment
                } label: {
                    Text(segment.segmentTitle)
                        .padding(12.0)
                        .border(selectedTab == segment ? Color.blue : Color.clear, width: 3.0)
                        .cornerRadius(4.0)
                        .matchedGeometryEffect(id: segment.segmentTitle, in: tabName) // doesn't work
                }
            }
        }
    }
}

该视图看起来和工作正常,但我无法让动画从一个选择“滑动”到另一个选择。它只是执行正常的 SwiftUI 淡入淡出。我相信我应该使用matchedGeometryEffect来获得滑动效果,但它似乎不起作用。我也尝试将 添加matchedGeometryEffect到按钮周围的标签,但它也不起作用。

这是它的预览:

在此输入图像描述

swiftui
  • 2 个回答
  • 22 Views
Martin Hope
Z S
Asked: 2024-02-04 11:38:29 +0800 CST

SwiftUI:创建兼容 iOS16 的 contextMenu

  • 5

我想使用新的 contextMenu 修饰符和“预览”,同时还支持 iOS15。我正在尝试为此创建一个ViewModifier,以便我可以在那里进行可用性检查,但我很难在这里掌握“通用”参数的语法。

这就是我正在尝试的:

struct CompatiblityContextMenuModifier: ViewModifier {

@ViewBuilder let actionsList: Group<Any>
@ViewBuilder let actionsPreview: any View

func body(content: Content) -> some View {
    if #available(iOS 16.0, *){
        content
            .contextMenu(menuItems: actionsList, preview: actionsPreview)
    } else {
        content
            .contextMenu(menuItems: actionsList)
    }
}

}

但编译器抱怨:

Cannot convert value of type 'any View' to expected argument type '() -> P'
Cannot convert value of type 'Group<Any>' to expected argument type '() -> M'
Generic parameter 'M' could not be inferred
Generic parameter 'P' could not be inferred

我知道我需要为 actionsList 和 actionPreview 指定不同的“类型”,但那到底是什么?

contextMenu 的函数调用如下所示:

func contextMenu<M, P>(
    @ViewBuilder menuItems: () -> M,
    @ViewBuilder preview: () -> P
) -> some View where M : View, P : View

“() -> M”和“() -> P”到底是什么

swift
  • 2 个回答
  • 51 Views

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve