【问题标题】:Get frame from certain UISegmentedControl index?从某个 UISegmentedControl 索引获取框架?
【发布时间】:2012-04-03 14:55:08
【问题描述】:

在我的应用程序中,我使用 UIPopoverController 和 presentPopoverFromRect API。我现在所做的只是将它设置为我的整个 UISegmentedControl 的框架。但是我想比这更精确。有什么方法可以获取 UISegmentedControl 中特定索引的框架?

谢谢!

【问题讨论】:

    标签: ios ipad frame uisegmentedcontrol


    【解决方案1】:

    对于我们的项目,我们需要每个片段的实际帧,帧分割是不够的。这是我编写的一个函数,它计算每个段的精确帧。请注意,它会访问分段控件的实际子视图,因此它可能会在任何 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];
    }
    

    【讨论】:

      【解决方案2】:

      如果段相等,为什么不将控件的宽度除以所选段的编号(+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。

      【讨论】:

      • 你能给我举个例子来说明你的意思,以便我更好地理解吗?
      • 我明白了,如果我有一个 2 段 UISegmentedControl 并且我试图获得第二段的中间,我会做整个 CGRectMake 并且对于 x 它将是:segmentedControl.frame.size .width/4 ?
      • 你也可以使用sender.numberOfSegments而不是硬编码6
      【解决方案3】:

      如果您不使用自定义分段控件(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
      【解决方案4】:

      如果有人正在寻找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
          }
      
      }
      

      【讨论】:

        【解决方案5】:

        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))
            }
        }
        

        【讨论】:

          【解决方案6】:

          对我来说,widthForSegment 返回 0,所以其他答案总是无法生成框架。我认为更好的解决方案是只获取子视图的框架:

          public extension UISegmentedControl {
              func frame(forSegment segment: Int) -> CGRect {
                  subviews[segment].frame
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-02-12
            • 1970-01-01
            • 2017-11-08
            • 1970-01-01
            • 1970-01-01
            • 2013-02-08
            • 2018-01-22
            相关资源
            最近更新 更多