Получить кадр из определенного индекса UISegmentedControl? - PullRequest
5 голосов
/ 19 марта 2012

В моем приложении я использую UIPopoverController и использую API presentPopoverFromRect.То, что я делаю сейчас, это просто устанавливаю его в рамку всего моего UISegmentedControl.Однако я хочу быть более точным, чем это.Есть ли способ получить кадр определенного индекса в UISegmentedControl?

Спасибо!

Ответы [ 4 ]

10 голосов
/ 27 февраля 2013

Для нашего проекта нам нужны были фактические кадры каждого сегмента, разделение кадров было недостаточно.Вот функция, которую я написал, которая вычисляет точную рамку для каждого сегмента.Имейте в виду, что он получает доступ к фактическим подпредставлениям сегментированного элемента управления, поэтому он может сломаться при любом обновлении 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];
}
5 голосов
/ 19 марта 2012

Если сегменты равны, почему бы просто не разделить ширину элемента управления на номер выбранного сегмента (+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. Поскольку каждый сегмент имеет ширину 20 пикселей, ширина 60 на шесть дает правильный ответ 10.

0 голосов
/ 06 августа 2017

Если кто-то ищет решение для 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
    }

}
0 голосов
/ 05 мая 2015

Это можно сделать намного проще, не сопоставляя имена классов, при условии, что вы не используете пользовательский сегментированный элемент управления (версия 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
    }
}
...