UISegmentedControlのボタンの色を任意に変える


下記の例では「Month」と「All」、「Timeline」と「Tag」をそれぞれ排他的に選択させたいが、UISegmentedControlでは複数のグループには分割できない。それぞれのボタンに色をつけることでそれを擬似的に表現したい。

NewImage

初期状態では「Month」「Timeline」がそれぞれ選択されている。

NewImage

「All」をタッチすると、「Month」の色が消えて、「All」に色がつく。「Timeline」と「Tag」に変化はない。

NewImage

さらに「Tag」をタッチすると、同様にボタンの色が変化する。

以下、コード。

 

- (void)viewWillAppear:(BOOL)animated {
	
    navigationSegment = [[UISegmentedControl alloc] initWithItems:nil];
    navigationSegment.segmentedControlStyle = UISegmentedControlStyleBar;
    navigationSegment.momentary = YES;
    
    //initialize UISegmentedControl
    //UISegmentedControlの初期化
    [navigationSegment insertSegmentWithTitle:NSLocalizedString(@"month", @"Month")  atIndex:0 animated:NO];
    [navigationSegment insertSegmentWithTitle:NSLocalizedString(@"all", @"All")  atIndex:1 animated:NO];
    [navigationSegment insertSegmentWithTitle:NSLocalizedString(@"sorttime",@"Timeline")  atIndex:2 animated:NO];
    [navigationSegment insertSegmentWithTitle:NSLocalizedString(@"sorttag",@"Tag")  atIndex:3 animated:NO];
    [navigationSegment insertSegmentWithImage:[UIImage imageNamed: @"mail2.png"] atIndex:4 animated:NO];
    
    //call controlPressed when UISegmentedControl is pushed
    //UISegmentedControlが押されたら、controlPressedメソッドを呼ぶ
    [navigationSegment addTarget:self action:@selector(controlPressed:) forControlEvents:UIControlEventValueChanged];

    //Initial value: Month and Timeline is ON.
    //初期値はMonthがON,TimelineがON
    tagOrTime = TIMELINE_FLAG_ON;
    allOrMonth = MONTH_FLAG_ON;
    
    //When view is displayed, objectAtIndex(es) are 0, 1, 2, 3, and 4 from the left.
    //viewが表示されたときは、objectAtIndexは左から0,1,2,3,4。
    [[[navigationSegment subviews] objectAtIndex:0] setTintColor:[UIColor colorWithRed: 0/255.0 green:32/255.0 blue:128/255.0 alpha:0.2]];
    [[[navigationSegment subviews] objectAtIndex:1] setTintColor:nil];
    [[[navigationSegment subviews] objectAtIndex:2] setTintColor:[UIColor colorWithRed: 0/255.0 green:32/255.0 blue:128/255.0 alpha:0.2]];
    [[[navigationSegment subviews] objectAtIndex:3] setTintColor:nil];

    
    
}


- (void)controlPressed:(id)sender{
    int index = navigationSegment.selectedSegmentIndex;
    
    if(index == 2){
        tagOrTime = TIMELINE_FLAG_ON;
    }else if(index == 3){
        tagOrTime = TAG_FLAG_ON;
    }else if(index == 0){
        allOrMonth = MONTH_FLAG_ON;
    }else if(index == 1){
        allOrMonth = ALL_FLAG_ON;
    }else if(index == 4){
    	....
    }
    
    //Since the turn of Subview of UISegmentedControl changes irregularly, it rearranges from the left.
    //UISegmentedControlのSubviewの順番がなぜかコロコロ変わってしまうので、左から並び替える。
    NSArray *sortedViews = [navigationSegment.subviews sortedArrayUsingFunction:compareViewsByOrigin context:NULL];

    //A flag is changed according to the button pushed now.
    //現在押されているボタンに従って、フラグを変更する。
    if (tagOrTime == TAG_FLAG_ON) {
        [[sortedViews  objectAtIndex:2] setTintColor:nil];
        [[sortedViews  objectAtIndex:3] setTintColor:[UIColor colorWithRed: 0/255.0 green:32/255.0 blue:128/255.0 alpha:0.2]];
    } else {
        [[sortedViews objectAtIndex:3] setTintColor:nil];
        [[sortedViews objectAtIndex:2] setTintColor:[UIColor colorWithRed: 0/255.0 green:32/255.0 blue:128/255.0 alpha:0.2]];
        
    }
    
    if (allOrMonth == ALL_FLAG_ON) {
        [[sortedViews objectAtIndex:0] setTintColor:nil];
        [[sortedViews objectAtIndex:1] setTintColor:[UIColor colorWithRed: 0/255.0 green:32/255.0 blue:128/255.0 alpha:0.2]];
    } else {
        [[sortedViews objectAtIndex:1] setTintColor:nil];
        [[sortedViews objectAtIndex:0] setTintColor:[UIColor colorWithRed: 0/255.0 green:32/255.0 blue:128/255.0 alpha:0.2]];
    }

    // Remove all original segments from the control
    // 一旦Subviewをすべて削除
    for (id view in navigationSegment.subviews) {
        [view removeFromSuperview];
    }
    
    // Append sorted and colored segments to the control
    // 色を変えたsubviewを付け替える
    for (id view in sortedViews) {
        [navigationSegment addSubview:view];
    }

}
         
//subviews sort function
//ソート関数
NSInteger static compareViewsByOrigin(id sp1, id sp2, void *context)
{
    // UISegmentedControl segments use UISegment objects (private API). But we can safely cast them to UIView objects.
    float v1 = ((UIView *)sp1).frame.origin.x;
    float v2 = ((UIView *)sp2).frame.origin.x;
    if (v1 < v2)
        return NSOrderedAscending;
    else if (v1 > v2)
        return NSOrderedDescending;
    else
        return NSOrderedSame;
}

Thank you, https://goddess-gate.com/dc2/index.php/post/454

Calolog FREE 公開開始


ご好評いただいているCalolog(カロログ)の無料配布版を本日,公開しました.

機能的な制限はありませんが,広告が出ます.

今後ともsamurai-appsをよろしくお願い申し上げます.

Calolog FREE (iTunes)

iPhoneアプリをInterface Builderを使わずに開発する

iPhoneアプリケーションを開発する際,おそらく一番の難関の一つがInterface Builder(IB)です.

これは,Viewのレイアウトをするのには非常に便利なツールです.しかし,IBを用いると,MVCモデルでいう,VやCがブラックボックス化してしまう可能性があります.よって,より難しい構成のアプリケーションを作る場合は,このブラックボックス化している部分を理解していないことが足かせとなることがあります.

例えば,動的に,あるいは大量にUILabelを作る場合,UILabelを生成する部分はfor文で書きたい…といった場合は,プログラマブルに書いた方がずっと楽に書けることが多くあります.公開中のアプリケーションであるcalologでは,食品と,そのカロリーを書いたUILabelが大量に並んでいます.これは,データはXMLで持っておき,それをfor文で呼び出しつつ,UILabelをXMLに応じて動的に生成しています.

だいたいの入門書はIBを使ったものですが,この本に関してはIBをつかわないプログラミング手法が,多数の例をもって紹介されています.掲載されているプログラムも,ところどころ省略されているものではなく,すべてが掲載されているので非常に読みやすい.おすすめです.

ただ,UIViewとUIViewControllerの使い分け,がよくわからない.MVCモデルでいう,VがUIView,CがUIViewControllerだという認識だけど,UIViewControllerに描画部分も書けてしまう.無理に分けなくてもいいんでしょうが…

© 2017 samurai-apps. All rights reserved. Powered by WordPress Entries RSS Comments RSS