2017-08-06 72 views
1

我正在尝试查找最近的可能子视图。在我的应用程序中,有7个UIButton s和一个UILabel s居中以下20的余量。它不是子视图。在Swift中找到最近的UIView的最佳方法

我想要什么?用较小的努力找出离按钮最近的标签。

我现在在做什么?我在函数中传递UIButton并计算从该按钮到所有标签的可能距离。然后对距离进行排序会导致上升并选取第一个对象以获得最小距离,这应该是我最近的标签。

internal func findNearByLabel(withRespectToButton button: UIButton) -> UILabel? { 

    var distance = Array<CGFloat>() 
    var labels: Array<UILabel> = self.view.subViews(type: UILabel.self) 

    labels.forEach { (label) in 
     distance.append(self.distance(label.frame.origin, button.frame.origin)) 
    } 

    if !distance.isEmpty { 
     let sortedDistance = Array.init(distance).sorted() 
     let minDistance = sortedDistance.first! 
     let indexOfMinDistance = distance.index(of: minDistance)! 
     return labels[indexOfMinDistance] 
    } 

    return nil 
} 

internal func distance(_ a: CGPoint, _ b: CGPoint) -> CGFloat { 
    let xDistance = a.x - b.x 
    let yDistance = a.y - b.y 
    return CGFloat(sqrt((xDistance * xDistance) + (yDistance * yDistance))) 
} 

extension UIView { 
    func subViews<T : UIView>(type : T.Type) -> [T]{ 
     var all = [T]() 
     for view in self.subviews { 
      if let aView = view as? T{ 
       all.append(aView) 
      } 
     } 
     return all 
    } 
} 

什么是问题?没问题,它的工作原理,但我想检查这是最好的解决方案还是可以改进的?

+1

同意@Sulthan,其实我只是用'flatMap'和'filter'思维https://codereview.stackexchange.com/ ... –

+1

我大概可以减少一半的代码。您应该更喜欢'[CGFloat]'在'Array '上,并且尽可能使用'let'而不是'var'。距离可以使用'CGPoint.distance(to:)'上的扩展来定义,它应该可以使用'hypot'函数。 – Sulthan

回答

3

只是使用功能模式的一些改进。

// generic method, can be in a category 
extension CGPoint { 
    func distance(to point: CGPoint) -> CGFloat { 
     // there is already a function for sqrt(x * x + y * y) 
     return hypot(self.x - point.x, self.y - point.y) 
    } 
} 

internal func findNearByLabel(withRespectToButton button: UIButton) -> UILabel? { 
    // you don't really need the subViews method 
    let labels = self.view.subviews.flatMap { $0 as? UILabel } 
    // don't forget we got "map" 
    let distances = labels.map { $0.frame.origin.distance(to: button.frame.origin) } 

    // we zip both sequences into one, that way we don't have to worry about sorting two arrays 
    let labelDistances = zip(labels, distances) 
    // we don't need sorting just to get the minimum 
    let closestLabel = labelDistances.min { $0.1 < $1.1 } 

    return closestLabel?.0 
} 
+0

这是StackOverflow的好处,我不知道这个内置的函数,这使得代码重构得当。谢谢,苏丹。 – Hemang

+1

@HemangShah我用过的函数比较常见,甚至Java现在有'map' :) – Sulthan

+0

是的,苏丹,我在上面的问题中遇到了一个小问题,我正在考虑准备一个单独的问题或者问你一个问题直接在这里?你会建议什么? **问题**:对于其中一个按钮,标签不正确,其余部分是正确的。没有任何改变,没有问题,我可以找到按钮,所有的按钮都是相同的,这代码和平的代码适用于其他按钮,所以不应该是一个例子。 – Hemang