如何改變 UISegmentedControl 被選中和未被選中時的背景色與文字顏色

UISegmentedControl 是 iOS 開發的一個重要元件,而我們常常利用他來做條件的選擇,如果用 XCode 中的 Interface Build 來拉出 UISegmentedControl 畫面的話,預設只有 Tint Color 和 Background Color 可以選擇,也就是當 UISegmentedControl 中的條件被選中時,就用 TintColor 來當文字顏色,用 Background Color 來當背景色; 若是 UISegmentedControl 中的條件未被選中,則用  TintColor 來當背景色,用  Background Color 來當文字顏色。這樣對於程式開發顯然不夠用,所以我們需要一點擴充。

 

UISegmentedControl-1

▲ 當用 XCode 內建的 Interface Build 來拉出 Xib 畫面時可以選擇的選項超少

 

 

要改變這這個情況,海芋是以 updateSegmentColor 的函式來實做,在實做之前,先給大家看一下實做的成果,底下是實做的成果,當 UISegmentedControl 中的條件被選中時,呈現黑底白色,未被選中時,呈現綠底紅字。

UISegmentedControl-2UISegmentedControl-3

 

而底下是的程式碼。

  1. - (void) updateSegmentColor
  2. {
  3.     UIColor* checkBackgroundColor   = [UIColor blackColor];
  4.     UIColor* unCheckBackgroundColor = [UIColor greenColor];
  5.     UIColor* checkTintColor         = [UIColor whiteColor];
  6.     UIColor* unCheckTintColor       = [UIColor redColor];
  7.  
  8.     self.m_segment.tintColor = [UIColor clearColor];
  9.     [self.m_segment setTitleTextAttributes:@{NSForegroundColorAttributeName:checkTintColor}
  10.                                   forState:UIControlStateSelected];
  11.     [self.m_segment setBackgroundImage:[self genImageWithSColor:checkBackgroundColor]
  12.                               forState:UIControlStateSelected
  13.                             barMetrics:UIBarMetricsDefault];
  14.     [self.m_segment setTitleTextAttributes:@{NSForegroundColorAttributeName:unCheckTintColor}
  15.                                   forState:UIControlStateNormal];
  16.     [self.m_segment setBackgroundImage:[self genImageWithSColor:unCheckBackgroundColor]
  17.                               forState:UIControlStateNormal
  18.                             barMetrics:UIBarMetricsDefault];
  19. }
  20. /**利用 Color 產生影像*/
  21. - (UIImage*) genImageWithSColor: (UIColor*) color
  22. {
  23.     CGRect rect=CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
  24.     UIGraphicsBeginImageContext(rect.size);
  25.     CGContextRef context = UIGraphicsGetCurrentContext();
  26.     CGContextSetFillColorWithColor(context, [color CGColor]);
  27.     CGContextFillRect(context, rect);
  28.  
  29.     UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
  30.     UIGraphicsEndImageContext();
  31.     return theImage;
  32. }

 

這段程式碼其實先定義 UISegmentedControl 被選中時和未被選中時的文字顏色和背景顏色,再使用 UISegmentedControl 內建的兩個函式來更新背景色和文字顏色

  1. - (void)setTitleTextAttributes:(nullable NSDictionary *)attributes forState:(UIControlState)state NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
  2. - (void)setBackgroundImage:(nullable UIImage *)backgroundImage forState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;

 

我們要加入切換時的動作,所以別忘了在 ViewDidLoad 加入監聽事件。

  1. - (void)viewDidLoad {
  2.     [super viewDidLoad];
  3.     // Do any additional setup after loading the view from its nib.
  4.     [self.m_segment addTarget:self
  5.                        action:@selector(onSegmentClick)
  6.              forControlEvents:UIControlEventValueChanged];
  7. }

 

以及在程式中新增一個監聽的函式。

  1. - (void) onSegmentClick
  2. {
  3.     [self updateSegmentColor];
  4. }

 

當然也別忘了在 viewDidAppear 時呼叫 updateSegmentColor 函式喔!

  1. - (void) viewDidAppear:(BOOL)animated
  2. {
  3.     [super viewDidAppear: animated];
  4.     [self updateSegmentColor];
  5. }

 

另外,有些人可能會想在 UISegmentedControl 選擇時加底線,則是可以在 viewDidLayoutSubviews 時使用下列程式碼。

  1. /** Override */
  2. - (void) viewDidLayoutSubviews
  3. {
  4.     [super viewDidLayoutSubviews];
  5.  
  6.     dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
  7.         //Background Thread
  8.         dispatch_async(dispatch_get_main_queue(), ^(void){
  9.             //更新Segment顏色
  10.             [self updateSegmentBottomColor];
  11.         });
  12.     });
  13. }

 

接著,加入以下的函式啦!

  1. - (void) updateSegmentBottomColor
  2. {
  3.     [self remoeveSegmentBottomColor];
  4.  
  5.     // Creating new layer for selection
  6.     self.m_bottomBorder             = [CALayer layer];
  7.     self.m_bottomBorder.borderColor = [UIColor redColor].CGColor;
  8.     self.m_bottomBorder.borderWidth = 2.0;
  9.  
  10.     // Calculating frame
  11.     CGFloat width            = 1.0 * self.m_Segment.frame.size.width/self.m_Segment.numberOfSegments;
  12.     CGFloat x                = 1.0 * self.m_Segment.selectedSegmentIndex * width;
  13.     CGFloat y                = 1.0 * self.m_Segment.frame.size.height - self.m_bottomBorder.borderWidth;
  14.     self.m_bottomBorder.frame= CGRectMake(x, y,width, self.m_bottomBorder.borderWidth);
  15.  
  16.     // Adding selection to segment
  17.     [self.m_Segment.layer addSublayer:self.m_bottomBorder];
  18. }
  19.  
  20. - (void) remoeveSegmentBottomColor
  21. {
  22.     if (nil == self.m_bottomBorder){
  23.         return;
  24.     }
  25.  
  26.     [self.m_bottomBorder removeFromSuperlayer];
  27.     self.m_bottomBorder = nil;
  28. }

 

同樣的,在 onSegmentClick 加入更新事件喔!

  1. - (void) onSegmentClick
  2. {
  3.     [self updateSegmentColor];
  4.     [self updateSegmentBottomColor];
  5. }

參考資料:http://stackoverflow.com/questions/6496441/creating-a-uiimage-from-a-uicolor-to-use-as-a-background-image-for-uibutton