AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / user-145552

Z S's questions

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

SwiftUI: TextField não está recebendo mudanças de foco dentro do botão

  • 5

Tenho um SwiftUI List(no macOS) onde quero exibir alguns TextFieldsem cada linha e observar como o foco muda conforme um campo de texto individual é selecionado ou desmarcado. Isso parece funcionar bem se eu apenas tiver a Listexibição pura TextFieldem cada linha, mas se eu incorporar TextFielddentro de uma Buttonvisualização, as notificações de mudança de foco param de funcionar. Quero a funcionalidade de 'botão' para que o usuário possa tocar em qualquer lugar da linha e ter o campo de texto ativado, em vez de tocar exatamente no limite do campo de texto.

Aqui está um código para demonstrar o problema. Se Listvocê tiver RowViewdescomentado (1), então as notificações de mudança de foco funcionam. Se você comentar isso e descomentar RowViewWithButton(2), então a funcionalidade do botão funciona, mas não consigo mais receber notificações de mudança de foco.

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)
}

Curiosamente, quando eu testo isso no iOS, funciona bem em ambos os casos. Mas eu preciso da solução para macOS.

ATUALIZAR:

Usar onTapGestureem vez de a Buttonmelhora as coisas, mas introduz um novo bug. Se eu tocar na linha inicialmente, inicialmente funciona bem, e tocar em qualquer lugar ativará o campo de texto. Mas depois de digitar algum texto e pressionar a tecla Enter (ou perder o foco de qualquer forma), se eu tentar tocar na parte da linha onde TextFieldestá o, ele só funciona se tocado no texto existente... não no espaço vazio na frente dele.

Adicionei .background(.red)ao HStack e .background(.blue)adicionei uma captura de tela para demonstrar o problema.

insira a descrição da imagem aqui

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

SwiftUI: use @FocusState.Binding com inicializador de visualização

  • 5

Tenho uma view com a @FocusStateque quero passar para uma subview. Para a subview, uso @FocusState.Binding. Isso funciona bem se eu não usar um inicializador personalizado... mas não consigo descobrir a sintaxe de como funciona com um inicializador de view personalizado, que preciso por outros motivos.

Aqui está o código que funciona:

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()
}

Entretanto, se eu descomentar a linha para o inicializador personalizado e, em seguida, inserir a linha TestListButtonsAndListFocusViewpara usar o inicializador personalizado, a sintaxe estará errada e eu recebo o erro:

Erro: Não é possível atribuir valor do tipo 'FocusState<ButtonState?>.Binding' ao tipo 'ButtonState?'

Não tenho certeza de como inicializar dessa @FocusState.Bindingforma. Sei que funciona se eu usar var bindedFocusButtonState: FocusState<ContactTabStyle?>.Bindingem vez disso, e então usar isso no inicializador também. Mas eu realmente gostaria de descobrir como usar o novo @FocusState.Bindingcom o inicializador personalizado, pois evita ter que acessar wrappedValuee é mais fácil de observar comonChange

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

Seleção de suporte da lista SwiftUI com diferentes tipos de modelos

  • 5

Estou tentando implementar uma lista SwiftUI para uma visualização de barra lateral que tenha pelo menos 3 tipos diferentes de pontos de dados: a) uma lista fixa de enumerações, b) uma lista de 'tags' provenientes de um @FetchRequest usando Core Data, c) uma lista semelhante de 'grupos' provenientes de um @FetchRequest diferente.

Estou com dificuldades para lidar com seleção múltipla Listnesta configuração. O usuário deve ser capaz de selecionar de diferentes seções (e recebo notificações de alteração para ajustar o tratamento). Tentei fazer o tipo 'seleção' ser UUID e definir o id para cada visualização de folha explicitamente, mas não parece funcionar (não gosto do destaque da seleção).

Esta é a lista que fiz:

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")
            }
        }
    }
}

Eu sei que se eu tivesse apenas NSManagedObjectsna lista, eu poderia definir o tipo 'selection' para ser NSManagedObjectIDe funcionaria. Mas eu precisava que ele suportasse uma lista de casos de enumeração também.

Eu tentei definir o tagfor each row view também (usando o mesmo material como idmodificador), mas isso também não funciona. Tenho certeza de que é um caso de 'tipos' incompatíveis para seleção, mas não consigo descobrir a melhor configuração para fazer isso.

EDITAR:

Código adicionado para 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 respostas
  • 43 Views
Martin Hope
Z S
Asked: 2024-04-25 06:04:44 +0800 CST

SwiftUI ViewModifier para contextMenu com genéricos

  • 6

Quero adicionar a API iOS16 para 'contextMenu forSelectionType: menu:', mas também preciso oferecer suporte ao iOS15, então preciso de uma condicional ViewModifierpara isso. Estou lutando com a sintaxe correta para isso.

Pelo que pude perceber, é assim que ViewModifierdeveria ser:

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
        }
    }
}

Mas como faço para usar isso na minha lista:

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") { }
            }
        }))

Isso me dá um erro de sintaxe:

Não é possível encontrar 'itens' no escopo

Se eu tentar passar a ligação de seleção:

.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")
        }
    }))

Eu recebo o erro:

Não é possível converter o valor do tipo 'Set<Person.ID>' (também conhecido como 'Set') para o tipo de argumento esperado '(Set<Person.ID>) -> V' (também conhecido como '(Set) -> V')

e

O parâmetro genérico 'V' não pôde ser inferido

Qual é a maneira correta de compilar condicionalmente esta API?

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

SwiftUI: a lista de dados principais não é atualizada conforme as propriedades do relacionamento são alteradas

  • 5

Eu tenho um caso de uso simples em que tenho um modelo Core Data com um Item(que possui uma propriedade 'timestamp') e um relacionamento um-para-um com Tag(que possui uma propriedade 'tagName'). Quero usar o SwiftUI para mostrar uma lista de itens e, em cada linha, mostro o carimbo de data/hora do item e o tag.tagName, se estiver disponível.

O problema que estou enfrentando é que, se eu atualizar o tagName associado a um item, ele não será atualizado automaticamente na visualização do SwiftUI. Quaisquer atualizações serão Itematualizadas automaticamente e, se eu reiniciar o aplicativo, ele também receberá as alterações... mas isso não acontece automaticamente.

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
            }
            
        }
    }
}

Adicionei botões da barra de ferramentas para testar o cenário de adicionar um novo item, uma nova tag e definir a tag do primeiro item para a primeira tag e depois um para alterar o nome da tag. As duas primeiras funções funcionam bem, mas alterar o tagName não atualiza a visualização da lista.

Parece que o SwiftUI @FetchRequestestá ouvindo apenas alterações Item. Acho que é semelhante ao NSFetchedResultsControllerque faria o mesmo, mas esperava que o SwiftUI melhorasse essa situação. Em outras questões que olhei, objectWillChange.sendparece ajudar, mas não parece resolver o meu problema.

De qualquer forma, qual é a melhor maneira de atualizar a lista completa se uma propriedade de relacionamento for alterada?

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

Use matchedGeometryEffect para criar efeito de 'slide' para borda

  • 5

Estou tentando criar um controle de seleção de 'guia' personalizado com uma linha horizontal de opções e o usuário pode selecionar uma entre N opções. A opção ‘selecionada’ terá uma ‘borda’ ao seu redor. Aqui está um protótipo que fiz:

@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
                }
            }
        }
    }
}

A visualização parece e funciona bem, mas não consigo fazer a animação 'deslizar' de uma seleção para outra. Ele apenas faz um fade-in e out normal do SwiftUI. Acredito que deveria usar matchedGeometryEffectpara obter o efeito deslizante, mas não parece estar funcionando. Também tentei adicionar o matchedGeometryEffectrótulo ao redor do botão, mas também não funcionou.

Aqui está uma prévia de como é:

insira a descrição da imagem aqui

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

SwiftUI: crie contextMenu compatível com iOS16

  • 5

Quero usar o novo modificador contextMenu com 'visualização', ao mesmo tempo que oferece suporte ao iOS15. Estou tentando criar um ViewModifierpara isso para poder fazer a verificação de disponibilidade lá, mas estou tendo dificuldades para entender a sintaxe dos parâmetros 'genéricos' aqui.

Isso é o que eu estava tentando:

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)
    }
}

}

Mas o compilador reclama:

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

Eu sei que preciso especificar um 'tipo' diferente para actionsList e actionPreview, mas o que seria exatamente?

Esta é a aparência da chamada de função para contextMenu:

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

O que exatamente é "() -> M" e "() -> P"

swift
  • 2 respostas
  • 51 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve