簡體   English   中英

iOS:如何在UISegmentedControl中訪問單個段?

[英]iOS: How Do I Access Individual Segments in A UISegmentedControl?

問題相當簡單,但在許多UISegmentedControl帖子中我沒有看到任何實際滿足我需求的內容:

環境:我有一組顯示在UISegmentedControl中的目錄。 它是一個平面層次結構,只有很少的目錄,因此這是顯示它們的最佳方式。

選擇一個段將使用該目錄的內容填充下面的UITableView。

我可以通過編程方式選擇一個給定的段,以便我可以根據需要選擇適當的段。

效果很好。

問題:

其中一個目錄是“默認”目錄,它將包含已存在的項目和新項目的混合。

我想標記該段,以便有一個指示器中有多少新的,以便人們知道選擇它,如果它還沒有被選中。

這意味着我需要訪問UISegmentedControl中的實際子視圖和諸如此類的東西。

不那么容易。 制作徽章是孩子的游戲。 找出放置徽章的位置是成年人的東西。

看起來蘋果故意隱藏對細分市場的直接訪問。 您只能影響整個控件。

有沒有人有任何關於如何修改一個片段,甚至找出該片段在哪里的建議?

widthForSegmentAtIndex : . 函數似乎毫無價值,因為它是否會給你任何有用的信息是任意的。

不, widthForSegmentAtIndex:返回的值不是任意的。 正如您在文檔中看到的那樣,它返回段的寬度或0.0,這意味着段是自動調整的。

有一種方法可以獲得每個細分的框架。

  1. 獲取UISegmentedControl的寬度
  2. 詢問每個細分的寬度
    • 如果返回0.0,則增加一個計數器
    • 否則從總寬度中刪除段的寬度
  3. 將剩余寬度除以自動調整大小的細分數,並獲得每個自動調整細分的大小。
  4. 您現在可以使用此信息來計算每個細分的框架。

或者在代碼中:

據我所知,在iOS7上,各段之間的“邊界”不是段寬度的一部分。

CGFloat autosizedWidth = CGRectGetWidth(self.segment.bounds);
// iOS7 only?!
autosizedWidth -= (self.segment.numberOfSegments - 1); // ignore the 1pt. borders between segments


NSInteger numberOfAutosizedSegmentes = 0;
NSMutableArray *segmentWidths = [NSMutableArray arrayWithCapacity:self.segment.numberOfSegments];
for (NSInteger i = 0; i < self.segment.numberOfSegments; i++) {
    CGFloat width = [self.segment widthForSegmentAtIndex:i];
    if (width == 0.0f) {
        // auto sized
        numberOfAutosizedSegmentes++;
        [segmentWidths addObject:[NSNull null]];
    }
    else {
        // manually sized
        autosizedWidth -= width;
        [segmentWidths addObject:@(width)];
    }
}

CGFloat autoWidth = floorf(autosizedWidth/(float)numberOfAutosizedSegmentes);
for (NSInteger i = 0; i < [segmentWidths count]; i++) {
    id width = segmentWidths[i];
    if (width == [NSNull null]) {
        [segmentWidths replaceObjectAtIndex:i withObject:@(autoWidth)];
    }
}

CGFloat x = CGRectGetMinX(self.segment.frame);
for (NSInteger i = 0; i < [segmentWidths count]; i++) {
    NSNumber *width = segmentWidths[i];
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(x, CGRectGetMaxY(self.segment.frame) + 1, [width floatValue], 30)];
    view.backgroundColor = [UIColor colorWithHue:i/(float)[segmentWidths count] saturation:1 brightness:1 alpha:1];
    [self.view addSubview:view];
    x = CGRectGetMaxX(view.frame)+1;
}

這產生以下結果:

在此輸入圖像描述

我建議你不要將你的徽章添加為UISegmentedControl的子視圖,你可以將它添加到segmentedControl的superView中。 你的徽章基本上應該是segmentedControl的兄弟


Apple提交增強請求 他們不會讓我們訪問各個子視圖,但他們至少可以告訴我們這些細分的實際大小。

你知道segmentedControl的大小,你知道段的數量。 只需除以得到每個段的寬度。 它們的寬度都相同。

然后將徽章放在segmentedControl頂部的適當x位置。

更新:我做了一些調整,我仍然沒有完美,但這似乎給了一個很好的近似,給或像素。

只要控件很小,那么上面的效果很好,但是有一些錯誤。 可能是因為我沒有在某個地方拍攝一些相當大的像素。

這是我在測試應用程序中所做的( 注意:項目已更新為具有更多測試控件)。

首先,我在UISegmentedControl類上聲明了一個類擴展:

@interface UISegmentedControl (Overload)
- (NSArray*)mapUISegmentedControl;
@end

然后,我實現它,就像這樣:

@implementation UISegmentedControl (Overload)
- (NSArray*)mapUISegmentedControl
{
    NSMutableArray  *segmentFrames = [NSMutableArray arrayWithCapacity:[self numberOfSegments]];
    NSInteger       numberOfAutosizedSegments = 0;
    double          ios7Coefficient = [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 ? 1 : 0;
    double          autosizedWidth = CGRectGetWidth ( [self bounds] ) - 1;

    for ( NSInteger i = 0; i < [self numberOfSegments]; i++ )
    {
        double width = [self widthForSegmentAtIndex:i];

        if ( width == 0.0f )
        {
            autosizedWidth -= 1;
            // If this is an auto-sized, we blank out the holding space for it.
            numberOfAutosizedSegments++;    // Add this to our count of auto-sized segments.
            [segmentFrames addObject:[NSNull null]];
        }
        else
        {
            // If the size has been explicitly set, we use that, and create a simple rect.
            autosizedWidth -= (width + ios7Coefficient);
            CGRect  frame = CGRectMake ( 0, 0, width, CGRectGetHeight ( [self bounds] ) );
            [segmentFrames addObject:[NSValue valueWithCGRect:frame]];
        }

    }

    // We divvy up the leftover space for the autoscales.
    double autoWidth = (autosizedWidth + ios7Coefficient) / (double)numberOfAutosizedSegments;

    double  x = 0;

    for ( NSInteger i = 0; i < [segmentFrames count]; i++ )
    {
        CGRect  frame = CGRectZero;
        double  width = 0;

        // If this is auto-sized (flagged by a null object), then make an autosized rect.
        if ( segmentFrames[i] == [NSNull null] )
        {
            width = ceil ( autoWidth - ios7Coefficient );
        }
        else    // Otherwise, use the rect they supplied.
        {
            width = CGRectGetWidth ( [(NSValue*)[segmentFrames objectAtIndex:i] CGRectValue] );
        }

        width += 1;

        frame = CGRectMake ( x, 0, width, CGRectGetHeight( [self bounds] ) );
        [segmentFrames replaceObjectAtIndex:i
                                 withObject:[NSValue valueWithCGRect:frame]
         ];

        // The x origin keeps up with the control.
        x += width;
    }

    return [NSArray arrayWithArray:segmentFrames];
}
@end

接下來,我在布局響應中調用它,如下所示:

@implementation DemoViewController

- (void)drawOverlays
{
    NSArray *segmentMap = [[self segmentedControl] mapUISegmentedControl];

    if ( ![self colorBand] )
    {
        _colorBand = [[NSMutableArray alloc] init];
    }
    else
    {
        for ( UIView *view in [self colorBand] )
        {
            [view removeFromSuperview];
        }
        [[self colorBand] removeAllObjects];
    }

    for ( NSInteger i = 0; i < [segmentMap count]; i++ )
    {
        CGRect  frame = [(NSValue*)[segmentMap objectAtIndex:i] CGRectValue];
        frame.size.height /= 2.0;
        frame.origin.y = [[self segmentedControl] frame].origin.y + [[self segmentedControl] frame].size.height;
        UIView *view = [[UIView alloc] initWithFrame:frame];
        view.backgroundColor = [UIColor colorWithHue:i/(float)[segmentMap count] saturation:1 brightness:1 alpha:0.5];
        [[self view] addSubview:view];
        [[self colorBand] addObject:view];
    }
}

- (void)viewDidLayoutSubviews
{
    [self drawOverlays];
}
@end

這適用於iOS 6和7,但似乎偶爾會出現半像素錯誤。

結果如下所示:

iOS6的

IOS 7

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM