3

質問はかなり簡単ですが、多くの UISegmentedControl 投稿で実際に私のニーズに答えるものは何もありません。

環境: UISegmentedControl に表示される一連のディレクトリがあります。これはディレクトリがほとんどないフラットな階層であるため、これがそれらを表示する最良の方法です。

セグメントを選択すると、下の UITableView がそのディレクトリの内容で満たされます。

必要に応じて適切なセグメントを選択できるように、特定のセグメントをプログラムで選択できます。

よく働く。

問題:

ディレクトリの 1 つは「デフォルト」ディレクトリで、既存のアイテムと新しいアイテムが混在しています。

セグメントにバッジを付けて、新しいものがいくつ含まれているかを示すインジケータを付けて、まだ選択されていない場合は選択するように人々に知らせたいと思います。

つまり、UISegmentedControl 内の実際のサブビューなどにアクセスする必要があります。

それほど簡単ではありません。バッジの作成は子供の遊びです。バッジをどこに置くかを考えるのは大人の仕事です。

Apple は意図的にセグメントへの直接アクセスを隠しているようです。コントロール全体にのみ影響を与えることができます。

1 つのセグメントだけを変更する方法や、そのセグメントがどこにあるかを調べる方法について、誰か提案はありますか?

widthForSegmentAtIndex : . 関数が有用な情報を提供するかどうかは恣意的であるため、価値がないように見えます。

4

3 に答える 3

3

いいえ、によって返される値は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に拡張要求を提出してください。個々のサブビューにアクセスすることはできませんが、少なくともセグメントの実際のサイズを教えてくれるかもしれません。

于 2013-10-01T22:55:47.293 に答える
1

更新:さらに調整を行いましたが、まだ完璧ではありませんが、これは適切な近似値を提供しているようで、ピクセルを与えるか取るかです。

コントロールが小さい限り、上記はうまく機能しますが、いくつかのエラーがあります。おそらく、数ピクセル分のサイズをどこかに取り込んでいないためです。

テスト アプリで行ったことは次のとおりです(注:プロジェクトは更新され、より多くのテスト コントロールが追加されています)。

最初に、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

iOS7

于 2013-10-03T19:52:45.690 に答える