【问题标题】:Creating custom UIView, or child VCs创建自定义 UIView 或子 VC
【发布时间】:2020-07-03 22:42:24
【问题描述】:

所以,我有以下情况。我有一个自定义选项卡布局,即带有分页的水平 UIScollview。在每个页面中都有一些控件和一个 UITablevie,“捆绑”在一个自定义 UIView 中。

我创建了一个具有滚动视图的 ContainerVC,然后我初始化了两个 UIView 并将它们作为子视图添加到 ContainerVC 中。为此,我创建了一个自定义 UIView 类并将此 UIView 设置为 .xib 文件的所有者。我还将 .xib 类添加为我的自定义 UIView。

虽然这可行,但至少在 UI 方面,我有一些功能问题,如下所示。 在每个 UIView 的 init 方法中,我用

初始化视图

Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)

然后将 UITableViewDelegate 和 UITableViewDateSource 设置为 self。

但是,当提供表格的数据到达视图时,我重新加载 tableview,没有任何反应(重新加载方法在主线程中运行),直到我滚动 UITableview。

这是正确的做法吗?

VC

 func createUsageHistoryTabs() -> [Consumption] {
    var tabs = [Consumption]()

    let v1 = Consumption(pageIndex: 0, viewModel: viewModel)
    let v2 = Consumption(pageIndex: 1, viewModel: viewModel)

    tabs.append(v1)
    tabs.append(v2)
    return tabs
}

func setupScrollView() {

    if(!hasBeenCreated) {
        let tabs = createUsageHistoryTabs()
        scrollview.frame = CGRect(x: 0, y: 0, width: container.frame.width, height: container.frame.height)
        scrollview.contentSize = CGSize(width: view.frame.width * CGFloat(tabs.count), height: 1.0)
        scrollview.isPagingEnabled = true

        for i in 0 ..< tabs.count {
            let slideView = tabs[i]
            slideView.frame = CGRect(x: view.frame.width * CGFloat(i), y: scrollview.frame.origin.y, width: scrollview.frame.width, height: scrollview.frame.height)
            scrollview.addSubview(slideView)
        }

        hasBeenCreated.toggle()
    }


}

UIView:

override init(frame: CGRect) {
    super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

convenience init(pageIndex: Int, viewModel: UsageHistoryViewModel) {
    self.init(frame: CGRect.zero)
    self.pageIndex = pageIndex
    self.viewModel = viewModel

    commonInit()
}

func commonInit() {
    Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)
    contentView.fixInView(self)
    setupView()

    footer.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleFooterTap)))

    viewModel?.cdrDelegate = self

    tableView.register(EmptyCell.self, forCellReuseIdentifier: "EmptyCell")
    tableView.register(UINib(nibName: "TVCell", bundle: nil), forCellReuseIdentifier: "TVCell")

    tableView.allowsSelection = false
    tableView.delegate = self
    tableView.dataSource = self


}

【问题讨论】:

  • 你需要展示一些代码。常见的错误是将自定义视图实例化为 func 中的本地对象...当该 func 退出时,可能已添加 view,但该对象(带有代码)消失了。确保您有一个类级别的变量来保存该对象。
  • 添加了一些代码!

标签: ios uitableview uiview uiviewcontroller xib


【解决方案1】:

在这个函数中:

func setupScrollView() {

    if(!hasBeenCreated) {

        // this line creates a LOCAL array
        let tabs = createUsageHistoryTabs()

        scrollview.frame = CGRect(x: 0, y: 0, width: container.frame.width, height: container.frame.height)
        scrollview.contentSize = CGSize(width: view.frame.width * CGFloat(tabs.count), height: 1.0)
        scrollview.isPagingEnabled = true

        for i in 0 ..< tabs.count {
            let slideView = tabs[i]
            slideView.frame = CGRect(x: view.frame.width * CGFloat(i), y: scrollview.frame.origin.y, width: scrollview.frame.width, height: scrollview.frame.height)
            scrollview.addSubview(slideView)
        }

        hasBeenCreated.toggle()
    }


}

您正在创建一个由Consumption 对象组成的本地 数组。从每个对象中,您将其 view 添加到您的 scrollView。一旦该函数退出,tabs 就不再存在......它“超出范围”。

你想创建一个类级别的变量:

var tabsArray: [Consumption]?

然后修改该 var 而不是创建本地实例:

func setupScrollView() {

    if(!hasBeenCreated) {

        // this line creates a LOCAL array
        tabsArray = createUsageHistoryTabs()

        ...

然后您的自定义类应该可用,直到您删除它们(或 tabsArray 超出范围)。

您可能需要进行一些其他更改,但这至少应该是一个开始。


编辑 评论讨论后...

如果表格视图正在工作,但在滚动之前没有“更新” - 你说正在主线程上调用重新加载 - 你可以尝试这些选项中的任何一个(或两者都......实验):

    tableView.reloadData()
    tableView.setNeedsLayout()
    tableView.layoutIfNeeded()

    tableView.reloadData()
    tableView.beginUpdates()
    tableView.endUpdates()

【讨论】:

  • 当然,我明白了,我会试一试,但是 viewmodelDelegate 是如何工作的? viewModel?.cdrDelegate = self cdrDelegate 与具有功能的协议相关联。视图实现了该协议,并且正确调用了回调。
  • 嗯...我可能误解了您的原始帖子 - 如果是这样,对不起。因此,使用您当前的实现(按照我的建议没有更改),您的 tableViews 加载并显示正确的数据,但只有在您向上/向下拖动以滚动之后?所以 dataSource 方法 - numberOfRowscellForRowAt 在您调用 .reloadData()被调用,但是当您开始滚动表格时它们调用?跨度>
  • @VictorBenetatos - 请参阅我答案底部的编辑。希望这能解决问题。
  • 已经尝试过 layoutIfNeeded,但没有成功,但我尝试了整个捆绑包。
  • 仍然没有,当然感谢您的帮助!我认为可能接线错误,因为我自己手动完成了,这意味着我手动创建了一个 UIView(.swift) 和一个 .xib 文件并将它们连接起来。正如你所知道的那样,我不擅长 UIKit 的东西:P 有没有一种很好的方法来开始一个新的自定义 UIView?我的意思是有没有一个选项可以让你获得 swift 文件和相关的 .xib,就像在 android 中创建片段并免费获得 .xml 文件一样?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多