从某些UISegmentedControl索引获取帧?

时间:2012-03-19 03:51:05

标签: ios ipad frame uisegmentedcontrol

在我的应用中,我使用了UIPopoverController并使用了presentPopoverFromRect API。我现在正在做的只是将它设置为我整个UISegmentedControl的框架。但是我希望比这更精确。有没有办法在UISegmentedControl中获取特定索引的框架?

谢谢!

5 个答案:

答案 0 :(得分:10)

对于我们的项目,我们需要每个段的实际帧,帧划分是不够的。这是我写的一个函数,它计算每个段的确切帧。请注意,它会访问分段控件实际子视图,因此可能会在任何iOS更新中中断。

- (CGRect)segmentFrameForIndex:(NSInteger)index inSegmentedControl:(UISegmentedControl *)control
{
    // WARNING: This function gets frame from UISegment objects, undocumented subviews of UISegmentedControl.
    // May break in iOS updates.

    NSMutableArray *segments = [NSMutableArray arrayWithCapacity:self.numberOfSegments];
    for (UIView *view in control.subviews) {
        if ([NSStringFromClass([view class]) isEqualToString:@"UISegment"]) {
            [segments addObject:view];
        }
    }

    NSArray *sorted = [segments sortedArrayUsingComparator:^NSComparisonResult(UIView *a, UIView *b) {
        if (a.frame.origin.x < b.frame.origin.x) {
            return NSOrderedAscending;
        } else if (a.frame.origin.x > b.frame.origin.x) {
            return NSOrderedDescending;
        }
        return NSOrderedSame;
    }];

    return [[sorted objectAtIndex:index] frame];
}

答案 1 :(得分:5)

如果段相等,为什么不将控件的宽度除以所选段的数量(+1因为编号从0开始)? 编辑:像这样

-(void)showPopover:(id)sender {
    if ((UISegmentedControl*)sender.selectedSegmentIndex == 0)
        [self.popover presentPopoverFromRect:CGRectMake(self.segmentedControl.frame.size.width/6, self.segmentedControl.frame.origin.y, aWidth, aHeight)]
}

超过6(我假设有一个3段实现),因为你必须得到段的中心,3将把它放在线上。如果你在这里做一些简单的数学运算(让我们假设整个控制是60像素宽),那么60/3 yeilds 20.因为每个段的宽度为20 px,60的宽度超过6会产生正确答案10。

答案 2 :(得分:0)

如果不使用自定义分段控件(Swift版本),可以在不使用类名的情况下更容易地完成此操作

extension NSSegmentedControl {

    func frameForSegment(segment: Int) -> NSRect {
        var left : CGFloat = 0
        for i in 0..<segmentCount {
            let w = widthForSegment(i)
            if i == segment {
                let off = CGFloat(i) + 2 // Account for separators and border.
                return NSRect(x: left + off, y: bounds.minY, width: w, height: bounds.height)
            }
            left += w
        }
        return NSZeroRect
    }
}

答案 3 :(得分:0)

如果有人正在寻找NSSegmentedControl的解决方案,我稍微修改了@ erik-aigner的答案。对于UISegmentedControl,它的工作方式应该相同。

此版本通常改进了间距和代码的几何计算。免责声明:它仅针对放置在工具栏中的分段控件进行了测试。

import AppKit

public extension NSSegmentedControl {

    /// The width of a single horizontal border.
    public static let horizontalBorderWidth: CGFloat = 3

    /// The height of a single vertical border.
    public static let verticalBorderWidth: CGFloat = 2

    /// The horizontal spacing between segments.
    public static let horizontalSegmentSpacing: CGFloat = 1

    /// Returns the frame of the specified segment.
    ///
    /// - Parameter segment: The index of the segment whose frame should be computed.
    /// - Returns: The frame of the segment or `.zero` if an invalid segment index is passed in.
    public func frame(forSegment segment: Int) -> NSRect {
        let y = bounds.minY - NSSegmentedControl.verticalBorderWidth
        let height = bounds.height
        var left = NSSegmentedControl.horizontalBorderWidth

        for index in 0..<segmentCount {
            let width = self.width(forSegment: index)
            if index == segment {
                return NSRect(x: left, y: y, width: width, height: height)
            }
            left += NSSegmentedControl.horizontalSegmentSpacing
            left += width
        }

        return .zero
    }

}

答案 4 :(得分:0)

@CodaFi的答案的5.3版本:

func showPopover(_ sender: Any?) {
    if sender?.selectedSegmentIndex as? UISegmentedControl == 0 {
        popover.presentPopover(fromRect: CGRect(x: segmentedControl.frame.size.width / 6, y: segmentedControl.frame.origin.y, width: aWidth, height: aHeight))
    }
}