Swift UI细节删除 [英] Swift UI detail remove

查看:170
本文介绍了Swift UI细节删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个SwiftUI列表,当点击一个单元格时,它会在导航中显示详细视图/推送:

I have a SwiftUI list which presents a detail view/pushes to the navigation when a cell is tapped:

import SwiftUI

struct DevicesInRangeList: View {
    @ObservedObject var central = Central()

    var body: some View {
        NavigationView {
            List(central.peripheralsInRange) { peripheral in
                NavigationLink(destination: DeviceView(peripheral: peripheral).onAppear {
                    self.central.connect(peripheral: peripheral)
                }.onDisappear {
                    self.central.disconnect(peripheral: peripheral)
                }) {
                    DeviceRow(deviceID: peripheral.deviceID, name: peripheral.name)
                }
            }.onAppear {
                self.central.scanning = true
            }.onDisappear {
                self.central.scanning = false
            }.navigationBarTitle("Devices in range")
        }
    }
}

如果我点击一行,将显示详细信息.如果外围设备断开连接,则将从外围设备InRange阵列中删除该外围设备,并删除该行-但仍显示详细信息.删除关联的行后如何删除细节?

If I tap a row, the detail is displayed. If the peripheral disconnects it is removed from the peripheralsInRange array and the row is removed – but the detail is still displayed. How can the detail be removed when the associated row is removed?

在Asperi回答之后,我有以下内容,但仍然无法使用:

After Asperi's answer I have the following, which still doesn't work:

struct DevicesInRangeList: View {
    @ObservedObject var central = Central()

    @State private var localPeripherals: [Peripheral] = []

    @State private var activeDetails = false
    var body: some View {
        NavigationView {
            List(localPeripherals, id: \.self) { peripheral in
                NavigationLink(destination:
                    DeviceView(peripheral: peripheral)
                        .onReceive(self.central.$peripheralsInRange) { peripherals in
                            if !peripherals.contains(peripheral) {
                                self.activeDetails = false
                            }
                        }
                        .onAppear {
                            self.central.connect(peripheral: peripheral)
                        }
                        .onDisappear {
                            self.central.disconnect(peripheral: peripheral)
                        }
                , isActive: self.$activeDetails) {
                    DeviceRow(deviceID: peripheral.deviceID, name: peripheral.name)
                }
            }.onReceive(central.$peripheralsInRange) { peripherals in
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    self.localPeripherals = peripherals
                }
            }.onAppear {
                self.central.scanning = true
                self.localPeripherals = self.central.peripheralsInRange
            }.onDisappear {
                self.central.scanning = false
            }.navigationBarTitle("Devices in range")
        }
    }
}

推荐答案

嗯...会有点长,但是值得...我已经在简化模型上重现了缺陷行为...这是问题原因

Well... will be a bit long, but it worth... I've reproduced the defect behaviour on simplified model... and here is the reason of issue

2020-01-22 19:53:41.008064 + 0200测试[5539:983123] [TableView]警告 仅一次:通知UITableView布置其可见单元格和其他 不属于视图层次结构(表视图或以下之一)的内容 其超级视图尚未添加到窗口中).这可能会导致错误 强制表格视图内的视图加载和执行布局而无需 准确的信息(例如表格视图范围,特征收集,布局 边距,安全区域插图等),并且还会导致不必要的 由于额外的布局传递而导致的性能开销.象征性地 UITableViewAlertForLayoutOutsideViewHierarchy的断点以捕获 在调试器中查看此情况,并查看导致此情况发生的原因,因此您可以 如果可能的话,请完全避免执行此操作,或者将其推迟到表格中 视图已添加到窗口.表格检视: < _TtC7SwiftUIP33_BFB370BA5F1BADDC9D83021565761A4925UpdateCoalescingTableView: 0x7fd095042600; baseClass = UITableView;框架=(0 0; 375667); clipsToBounds = YES;自动调整大小= W + H; gestureRecognizers =;层=; contentOffset:{0, -116}; contentSize:{375,400.5}; AdjustedContentInset:{116,0,0,0};数据源: < _TtGC7SwiftUIP13 $ 7fff2c6b223419ListCoreCoordinatorGVS_20SystemListDataSourceOs5Never_GOS_19SelectionManagerBoxS2 ___: 0x7fd093f62b60 >>

2020-01-22 19:53:41.008064+0200 Test[5539:983123] [TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window. Table view: <_TtC7SwiftUIP33_BFB370BA5F1BADDC9D83021565761A4925UpdateCoalescingTableView: 0x7fd095042600; baseClass = UITableView; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = ; layer = ; contentOffset: {0, -116}; contentSize: {375, 400.5}; adjustedContentInset: {116, 0, 0, 0}; dataSource: <_TtGC7SwiftUIP13$7fff2c6b223419ListCoreCoordinatorGVS_20SystemListDataSourceOs5Never_GOS_19SelectionManagerBoxS2___: 0x7fd093f62b60>>

此异常中断了导航堆栈,因此不会单独或通过isActive状态强制关闭详细信息视图.

This exception breaks navigation stack so details view is not closed either by itself or forcefully by isActive state.

因此,这是重现该问题的初始代码(一旦开始,只需导航任意行并等待20秒)即可.

So here is initial code that reproduces the issue (once started just navigate any row and wait for 20 secs)

// view model holding some sequence of data to be shown in List
class TestedModel: ObservableObject {
    @Published var originalRange = [1, 2, 3, 4, 5, 6, 7, 8, 9]
}

// simple detail view 
struct DetachedDetailView: View {
    let item: Int
    var body: some View {
        Text("Details of item \(item)")
    }
}

// Issue demo view
struct TestNavigationLinkDestruction_Issue: View {
    @ObservedObject var model = TestedModel()

    var body: some View {
        NavigationView {
            List(model.originalRange, id: \.self) { item in
                NavigationLink("Item \(item)", destination:
                    DetachedDetailView(item: item))
            }
        }
        .onAppear {
            // >> by this simulated async update of List while in Details
            DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
                self.model.originalRange = [10, 20, 30, 40, 50, 60, 70, 80, 90]
            }
        }
    }
}

这是一个解决方案...这个想法在列表内容的时间更新和决定是否需要关闭细节的时刻上是分开的

And here is a solution... the idea is separate in time update of List content and moment of making decision is it needed to close details

struct TestNavigationLinkDestruction_Fixed: View {
    @ObservedObject var model = TestedModel()

    @State private var selected: Int? = nil
    @State private var localStorage: [Int] = []


    var body: some View {
        NavigationView {
            // List locally stored items
            List(localStorage, id: \.self) { item in
                NavigationLink("Item \(item)", destination:
                    DetachedDetailView(item: item)
                        .onReceive(self.model.$originalRange) { items  in
                            if !items.contains(item) {
                                self.selected = nil // !!! unwind at once
                            }
                        }
                , tag:item, selection: self.$selected)
            }
            .onReceive(self.model.$originalRange) { items  in
                DispatchQueue.main.async {
                    self.localStorage = items // !!! postpone local data update
                }
            }
        }
        .onAppear {
            self.localStorage = self.model.originalRange // ! initial load from model

            // >>> simulate async data update
            DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
                self.model.originalRange = [10, 20, 30, 40, 50, 60, 70, 80, 90]
            }
        }
    }
}

所以..您需要的是在代码中采用上面的代码,我敢肯定这是可行的.

So.. all you need is to adopt above to your code, I'm sure it's feasible.

这篇关于Swift UI细节删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆