【发布时间】:2012-04-03 14:55:08
【问题描述】:
在我的应用程序中,我使用 UIPopoverController 和 presentPopoverFromRect API。我现在所做的只是将它设置为我的整个 UISegmentedControl 的框架。但是我想比这更精确。有什么方法可以获取 UISegmentedControl 中特定索引的框架?
谢谢!
【问题讨论】:
标签: ios ipad frame uisegmentedcontrol
在我的应用程序中,我使用 UIPopoverController 和 presentPopoverFromRect API。我现在所做的只是将它设置为我的整个 UISegmentedControl 的框架。但是我想比这更精确。有什么方法可以获取 UISegmentedControl 中特定索引的框架?
谢谢!
【问题讨论】:
标签: ios ipad frame uisegmentedcontrol
对于我们的项目,我们需要每个片段的实际帧,帧分割是不够的。这是我编写的一个函数,它计算每个段的精确帧。请注意,它会访问分段控件的实际子视图,因此它可能会在任何 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,因为编号从 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 px 宽),那么 60/3 得到 20。因为每个段都是 20 px 宽,所以 60 比 6 的宽度得到正确答案 10。
【讨论】:
sender.numberOfSegments而不是硬编码6。
如果您不使用自定义分段控件(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
}
}
【讨论】:
widthForSegment 假定段控件未使用自动布局进行布局。如果是,这将返回 0.0f
如果有人正在寻找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
}
}
【讨论】:
Swift 5.3 版本的@CodaFi 的回答:
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))
}
}
【讨论】:
对我来说,widthForSegment 返回 0,所以其他答案总是无法生成框架。我认为更好的解决方案是只获取子视图的框架:
public extension UISegmentedControl {
func frame(forSegment segment: Int) -> CGRect {
subviews[segment].frame
}
}
【讨论】: