Làm cách nào để thay đổi màu của một phân đoạn trong UISegmentedControl trong iOS 13?


109

A UISegmentedControlcó giao diện mới trong iOS 13 và mã hiện có để thay đổi màu sắc của điều khiển được phân đoạn không còn hoạt động như trước nữa.

Trước iOS 13, bạn có thể đặt tintColorvà sẽ được sử dụng cho đường viền xung quanh điều khiển được phân đoạn, các đường giữa các phân đoạn và màu nền của phân đoạn đã chọn. Sau đó, bạn có thể thay đổi màu tiêu đề của từng đoạn bằng cách sử dụng thuộc tính màu nền trước với titleTextAttributes.

Trong iOS 13, tintColorkhông có gì. Bạn có thể đặt điều khiển được phân đoạn backgroundColorđể thay đổi màu tổng thể của điều khiển được phân đoạn. Nhưng tôi không thể tìm thấy bất kỳ cách nào để thay đổi màu được sử dụng làm nền của phân đoạn đã chọn. Đặt thuộc tính văn bản vẫn hoạt động. Tôi thậm chí đã thử đặt màu nền của tiêu đề nhưng điều đó chỉ ảnh hưởng đến nền của tiêu đề, không ảnh hưởng đến phần còn lại của màu nền của phân đoạn đã chọn.

Tóm lại, làm cách nào để bạn sửa đổi màu nền của phân đoạn hiện đang được chọn của a UISegmentedControltrong iOS 13? Có giải pháp thích hợp nào, sử dụng các API công khai, không yêu cầu đào sâu vào cấu trúc chế độ xem phụ riêng tư không?

Không có thuộc tính mới nào trong iOS 13 cho UISegmentedControlhoặc UIControlvà không có thay đổi UIViewnào liên quan.

Câu trả lời:


134

Kể từ iOS 13b3, hiện đã có tính năng selectedSegmentTintColorbật UISegmentedControl.

Để thay đổi màu tổng thể của điều khiển được phân đoạn, hãy sử dụng nó backgroundColor.

Để thay đổi màu của phân đoạn đã chọn, hãy sử dụng selectedSegmentTintColor.

Để thay đổi màu sắc / phông chữ của tiêu đề phân đoạn không được chọn, hãy sử dụng setTitleTextAttributesvới trạng thái .normal/ UIControlStateNormal.

Để thay đổi màu / phông chữ của tiêu đề đoạn đã chọn, hãy sử dụng setTitleTextAttributesvới trạng thái .selected/ UIControlStateSelected.

Nếu bạn tạo điều khiển được phân đoạn với hình ảnh, nếu hình ảnh được tạo dưới dạng ảnh mẫu, thì điều khiển được phân đoạn tintColorsẽ được sử dụng để tô màu cho hình ảnh. Nhưng điều này có một vấn đề. Nếu bạn đặt thành tintColorcùng màu selectedSegmentTintColorthì hình ảnh sẽ không hiển thị trong phân đoạn đã chọn. Nếu bạn đặt thành tintColorcùng màu backgroundColor, thì hình ảnh trên các phân đoạn không được chọn sẽ không hiển thị. Điều này có nghĩa là điều khiển được phân đoạn của bạn với hình ảnh phải sử dụng 3 màu khác nhau để mọi thứ hiển thị. Hoặc bạn có thể sử dụng hình ảnh không phải mẫu và không đặt tintColor.

Trong iOS 12 trở xuống, chỉ cần đặt điều khiển được phân đoạn tintColorhoặc dựa vào màu tổng thể của ứng dụng.


Làm cách nào để chúng tôi đặt bộ điều khiển phân đoạn không có đường viền? Tôi thấy không có cài đặt nào cho điều này trong iOS 13. Trước đó, cài đặt màu là đủ để có được điều khiển phân đoạn không biên giới.
Deepak Sharma

Vui lòng thêm Màu đường viền, v.v. để tất cả có thể tìm thấy tất cả các vấn đề liên quan đến Màu phân đoạn được giải quyết tại đây. nói gì? :)
Yogesh Patel

1
@YogeshPatel Còn màu viền thì sao? Không có màu đường viền trong iOS 13 và trong iOS 12, nó được đặt với màu tintColorđã được đề cập trong câu trả lời.
rmaddy

@rmaddy Tôi đã thiết lập [segmentedControl.layer setBorderColor: [[UIColor whiteColor] CGColor]]; [segmentedControl.layer setBorderWidth: 0,5]; nó mang lại cho tôi biên giới và màu đường viền trong iOS 13.
Yogesh Patel

1
Ồ, biên giới đó. Điều đó áp dụng cho bất kỳ chế độ xem nào, không chỉ một điều khiển được phân đoạn. Đó là ngoài phạm vi của câu hỏi ban đầu và câu trả lời này. Nhận xét của bạn là đủ.
rmaddy

47

Kể từ Xcode 11 beta 3

Bây giờ có selectedSegmentTintColortài sản trên UISegmentedControl.

Xem câu trả lời của rmaddy


Để lấy lại giao diện iOS 12

Tôi không thể tô màu cho phân đoạn đã chọn, hy vọng nó sẽ được sửa trong bản beta sắp tới.

Đặt hình nền của trạng thái đã chọn sẽ không hoạt động nếu không đặt hình nền của trạng thái bình thường (sẽ xóa tất cả kiểu iOS 13)

Nhưng tôi đã có thể đưa nó trở lại giao diện iOS 12 (hoặc gần đủ, tôi không thể trả bán kính góc về kích thước nhỏ hơn của nó).

Nó không phải là lý tưởng, nhưng một điều khiển phân đoạn màu trắng sáng trông hơi lạc lõng trong ứng dụng của chúng tôi.

(Không nhận ra đây UIImage(color:)là một phương thức mở rộng trong cơ sở mã của chúng tôi. Nhưng mã để triển khai nó nằm trên web)

extension UISegmentedControl {
    /// Tint color doesn't have any effect on iOS 13.
    func ensureiOS12Style() {
        if #available(iOS 13, *) {
            let tintColorImage = UIImage(color: tintColor)
            // Must set the background image for normal to something (even clear) else the rest won't work
            setBackgroundImage(UIImage(color: backgroundColor ?? .clear), for: .normal, barMetrics: .default)
            setBackgroundImage(tintColorImage, for: .selected, barMetrics: .default)
            setBackgroundImage(UIImage(color: tintColor.withAlphaComponent(0.2)), for: .highlighted, barMetrics: .default)
            setBackgroundImage(tintColorImage, for: [.highlighted, .selected], barMetrics: .default)
            setTitleTextAttributes([.foregroundColor: tintColor, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)
            setDividerImage(tintColorImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
            layer.borderWidth = 1
            layer.borderColor = tintColor.cgColor
        }
    }
}

Hình ảnh cho thấy tác dụng của đoạn mã trên


Đây có thể là một giải pháp tốt. Tôi chưa có cơ hội thử điều này nhưng điều này cũng yêu cầu một cuộc gọi setTitleTextAttributesđể làm cho tiêu đề của phân đoạn đã chọn có màu trắng?
rmaddy

Hmm, có vẻ như nên nhưng có vẻ như không. Tôi không có quyền truy cập vào atm sử dụng mã đó, nhưng hình ảnh bên trái được tạo bằng mã đó.
Jonathan.

8
stackoverflow.com/a/33675160/5790492 cho phần mở rộng UIImage (color :).
Nik Kov

1
Nó sẽ được tốt đẹp nếu bạn sẽ thêm phần mở rộng UIImage, theo cách này, câu trả lời của bạn không phải là hoàn toàn IHO
FredFlinstone

1
@VityaShurapov cài đặt cho nó khi nó được đánh dấu được chọn, nó không phải là một mảng các trạng thái được chuyển vào mà là một bộ tùy chọn, có nghĩa là các giá trị được kết hợp để tạo ra một trạng thái mới.
Jonathan.

36

Kiểm soát phân đoạn iOS 13 và Swift 5.0 (Xcode 11.0) Hoạt động 100%

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

 if #available(iOS 13.0, *) {
      yoursegmentedControl.backgroundColor = UIColor.black
      yoursegmentedControl.layer.borderColor = UIColor.white.cgColor
      yoursegmentedControl.selectedSegmentTintColor = UIColor.white
      yoursegmentedControl.layer.borderWidth = 1

      let titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]    
      yoursegmentedControl.setTitleTextAttributes(titleTextAttributes, for:.normal)

      let titleTextAttributes1 = [NSAttributedString.Key.foregroundColor: UIColor.black]
      yoursegmentedControl.setTitleTextAttributes(titleTextAttributes1, for:.selected)
  } else {
              // Fallback on earlier versions
}

7
bạn đã thử đặt nền là màu trắng chưa? đối với tôi nó đang đến hơi xám
Ronit

@ItanHant bạn đang sử dụng mã xcode và ngôn ngữ nhanh nào?
Maulik Patel

@Ronit dĩ nhiên rồi !! tôi sẽ thử nhưng làm ơn cho tôi biết loại hiển thị đầu ra bây giờ
Maulik Patel

swift 5, xcode 11.3! nó cho thấy những gì nó muốn! không phải là người tôi muốn :)
Itan Hant

15

Tôi đã thử giải pháp thay thế và nó hoạt động tốt đối với tôi. Đây là phiên bản Objective-C:

@interface UISegmentedControl (Common)
- (void)ensureiOS12Style;
@end
@implementation UISegmentedControl (Common)
- (void)ensureiOS12Style {
    // UISegmentedControl has changed in iOS 13 and setting the tint
    // color now has no effect.
    if (@available(iOS 13, *)) {
        UIColor *tintColor = [self tintColor];
        UIImage *tintColorImage = [self imageWithColor:tintColor];
        // Must set the background image for normal to something (even clear) else the rest won't work
        [self setBackgroundImage:[self imageWithColor:self.backgroundColor ? self.backgroundColor : [UIColor clearColor]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
        [self setBackgroundImage:tintColorImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
        [self setBackgroundImage:[self imageWithColor:[tintColor colorWithAlphaComponent:0.2]] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
        [self setBackgroundImage:tintColorImage forState:UIControlStateSelected|UIControlStateSelected barMetrics:UIBarMetricsDefault];
        [self setTitleTextAttributes:@{NSForegroundColorAttributeName: tintColor, NSFontAttributeName: [UIFont systemFontOfSize:13]} forState:UIControlStateNormal];
        [self setDividerImage:tintColorImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
        self.layer.borderWidth = 1;
        self.layer.borderColor = [tintColor CGColor];
    }
}

- (UIImage *)imageWithColor: (UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return theImage;
}
@end

2
Tôi không chắc rằng nó sẽ hoạt động với CGRectMake(0.0f, 0.0f, 1.0f, 1.0f): từ các thử nghiệm của tôi với Xcode 11 beta, rectphải có cùng kích thước với giới hạn của điều khiển được phân đoạn.
Cœur

2
Vì iOS13 beta 6, màu sắc không hiển thị trên một nút đã chọn, vì vậy tôi phải thêm một dòng: [self setTitleTextAttributes: @ {NSForegroundColorAttributeName: UIColor.blackColor, NSFontAttributeName: [UIFont systemFontOfSize: 13]} forState: UIContedrolState: UIContedrolState:
Peter Johnson

Khi tôi cố gắng sử dụng điều này trên, [[UISegmentedControl appearance] ensureiOS12Style]tôi nhận được một ngoại lệ. Bất cứ ý tưởng những gì đang xảy ra? Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSMethodSignature getArgumentTypeAtIndex:]: index (2) out of bounds [0, 1]'
Jeremy Hicks

13

Kể từ Xcode 11 beta 3

Bây giờ có selectedSegmentTintColortài sản trên UISegmentedControl.

Xin cảm ơn @rmaddy!


Câu trả lời gốc, dành cho Xcode 11 beta và beta 2

Có giải pháp thích hợp nào, sử dụng các API công khai, không yêu cầu đào sâu vào cấu trúc chế độ xem phụ riêng tư không?

Với Xcode 11.0 beta, có vẻ như là một thách thức để làm điều đó theo quy tắc, vì về cơ bản nó yêu cầu bạn phải tự mình vẽ lại tất cả các hình nền cho mọi trạng thái, với các góc tròn, độ trong suốt và resizableImage(withCapInsets:). Ví dụ: bạn sẽ cần tạo một hình ảnh có màu tương tự như:
nhập mô tả hình ảnh ở đây

Vì vậy, hiện tại, cách chúng ta cùng tìm hiểu về các bài xem phụ có vẻ dễ dàng hơn nhiều:

class TintedSegmentedControl: UISegmentedControl {

    override func layoutSubviews() {
        super.layoutSubviews()

        if #available(iOS 13.0, *) {
            for subview in subviews {
                if let selectedImageView = subview.subviews.last(where: { $0 is UIImageView }) as? UIImageView,
                    let image = selectedImageView.image {
                    selectedImageView.image = image.withRenderingMode(.alwaysTemplate)
                    break
                }
            }
        }
    }
}

Giải pháp này sẽ áp dụng chính xác màu sắc cho vùng chọn, như trong: nhập mô tả hình ảnh ở đây


1
Được thưởng vì thời gian sắp hết, nhưng tốt nhất là một giải pháp không liên quan đến việc đào sâu vào hệ thống phân cấp riêng sẽ được tìm thấy :)
Jonathan.

@Jonathan. Cảm ơn bạn. Bạn đã có giải pháp gần nhất không liên quan đến cách nhìn vào hệ thống phân cấp: bởi vì một khi bạn setBackgroundImagecho .normal, bạn phải đặt tất cả những hình ảnh khác (kể cả các tiểu bang khác và setDividerImage), có lẽ với một số UIBezierPathresizableImage(withCapInsets:), mà làm cho nó quá phức tạp nếu chúng ta muốn thiết kế iOS 13 cách này.
Cœur

Đúng vậy, lý tưởng là nó sẽ được sửa trong bản beta
Jonathan.

3
Điều này không còn cần thiết kể từ iOS 13b3. Bây giờ có selectedSegmentTintColortài sản trên UISegmentedControl.
rmaddy

11

Phiên bản Swift của @Ilahi Charfeddine answer:

if #available(iOS 13.0, *) {
   segmentedControl.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
   segmentedControl.selectedSegmentTintColor = UIColor.blue
} else {
   segmentedControl.tintColor = UIColor.blue
}

10
if (@available(iOS 13.0, *)) {

    [self.segmentedControl setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor whiteColor], NSFontAttributeName: [UIFont systemFontOfSize:13]} forState:UIControlStateSelected];
    [self.segmentedControl setSelectedSegmentTintColor:[UIColor blueColor]];

} else {

[self.segmentedControl setTintColor:[UIColor blueColor]];}

7

iOS13 UISegmentController

cách sử dụng:

segment.setOldLayout(tintColor: .green)

extension UISegmentedControl
{
    func setOldLayout(tintColor: UIColor)
    {
        if #available(iOS 13, *)
        {
            let bg = UIImage(color: .clear, size: CGSize(width: 1, height: 32))
             let devider = UIImage(color: tintColor, size: CGSize(width: 1, height: 32))

             //set background images
             self.setBackgroundImage(bg, for: .normal, barMetrics: .default)
             self.setBackgroundImage(devider, for: .selected, barMetrics: .default)

             //set divider color
             self.setDividerImage(devider, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)

             //set border
             self.layer.borderWidth = 1
             self.layer.borderColor = tintColor.cgColor

             //set label color
             self.setTitleTextAttributes([.foregroundColor: tintColor], for: .normal)
             self.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
        }
        else
        {
            self.tintColor = tintColor
        }
    }
}
extension UIImage {
    convenience init(color: UIColor, size: CGSize) {
        UIGraphicsBeginImageContextWithOptions(size, false, 1)
        color.set()
        let ctx = UIGraphicsGetCurrentContext()!
        ctx.fill(CGRect(origin: .zero, size: size))
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        self.init(data: image.pngData()!)!
    }
}

1
Đây là cách tiếp cận duy nhất phù hợp với tôi - ảnh nền. selectSegmentTintColor không hoạt động vì một số lý do.
DenNukem

7

XCODE 11.1 và iOS 13

Dựa trên câu trả lời của @Jigar Darji nhưng cách triển khai an toàn hơn.

Đầu tiên chúng tôi tạo một trình khởi tạo tiện lợi khả dụng:

extension UIImage {

convenience init?(color: UIColor, size: CGSize) {
    UIGraphicsBeginImageContextWithOptions(size, false, 1)
    color.set()
    guard let ctx = UIGraphicsGetCurrentContext() else { return nil }
    ctx.fill(CGRect(origin: .zero, size: size))
    guard
        let image = UIGraphicsGetImageFromCurrentImageContext(),
        let imagePNGData = image.pngData()
        else { return nil }
    UIGraphicsEndImageContext()

    self.init(data: imagePNGData)
   }
}

Sau đó, chúng tôi mở rộng UISegmentedControl:

extension UISegmentedControl {

func fallBackToPreIOS13Layout(using tintColor: UIColor) {
    if #available(iOS 13, *) {
        let backGroundImage = UIImage(color: .clear, size: CGSize(width: 1, height: 32))
        let dividerImage = UIImage(color: tintColor, size: CGSize(width: 1, height: 32))

        setBackgroundImage(backGroundImage, for: .normal, barMetrics: .default)
        setBackgroundImage(dividerImage, for: .selected, barMetrics: .default)

        setDividerImage(dividerImage,
                        forLeftSegmentState: .normal,
                        rightSegmentState: .normal, barMetrics: .default)

        layer.borderWidth = 1
        layer.borderColor = tintColor.cgColor

        setTitleTextAttributes([.foregroundColor: tintColor], for: .normal)
        setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
    } else {
        self.tintColor = tintColor
    }
  }
}

Hoàn hảo! Cảm ơn bạn!
Senocico Stelian

5

Đây là câu trả lời của tôi về câu trả lời của Jonathan cho Xamarin.iOS (C #), nhưng với các bản sửa lỗi cho định cỡ hình ảnh. Như với nhận xét của Cœur về câu trả lời của Colin Blake, tôi đã tạo tất cả các hình ảnh ngoại trừ dải phân cách bằng kích thước của điều khiển được phân đoạn. Dải phân cách là 1xheight của đoạn.

public static UIImage ImageWithColor(UIColor color, CGSize size)
{
    var rect = new CGRect(0, 0, size.Width, size.Height);
    UIGraphics.BeginImageContext(rect.Size);
    var context = UIGraphics.GetCurrentContext();
    context.SetFillColor(color.CGColor);
    context.FillRect(rect);
    var image = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();
    return image;
}

// https://stackoverflow.com/a/56465501/420175
public static void ColorSegmentiOS13(UISegmentedControl uis, UIColor tintColor, UIColor textSelectedColor, UIColor textDeselectedColor)
{
    if (!UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
    {
        return;
    }

    UIImage image(UIColor color)
    {
        return ImageWithColor(color, uis.Frame.Size);
    }

    UIImage imageDivider(UIColor color)
    {
        return ImageWithColor(color, 1, uis.Frame.Height);
    }

    // Must set the background image for normal to something (even clear) else the rest won't work
    //setBackgroundImage(UIImage(color: backgroundColor ?? .clear), for: .normal, barMetrics: .default)
    uis.SetBackgroundImage(image(UIColor.Clear), UIControlState.Normal, UIBarMetrics.Default);

    // setBackgroundImage(tintColorImage, for: .selected, barMetrics: .default)
    uis.SetBackgroundImage(image(tintColor), UIControlState.Selected, UIBarMetrics.Default);

    // setBackgroundImage(UIImage(color: tintColor.withAlphaComponent(0.2)), for: .highlighted, barMetrics: .default)
    uis.SetBackgroundImage(image(tintColor.ColorWithAlpha(0.2f)), UIControlState.Highlighted, UIBarMetrics.Default);

    // setBackgroundImage(tintColorImage, for: [.highlighted, .selected], barMetrics: .default)
    uis.SetBackgroundImage(image(tintColor), UIControlState.Highlighted | UIControlState.Selected, UIBarMetrics.Default);

    // setTitleTextAttributes([.foregroundColor: tintColor, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)
    // Change: support distinct color for selected/de-selected; keep original font
    uis.SetTitleTextAttributes(new UITextAttributes() { TextColor = textDeselectedColor }, UIControlState.Normal); //Font = UIFont.SystemFontOfSize(13, UIFontWeight.Regular)
    uis.SetTitleTextAttributes(new UITextAttributes() { TextColor = textSelectedColor, }, UIControlState.Selected); //Font = UIFont.SystemFontOfSize(13, UIFontWeight.Regular)

    // setDividerImage(tintColorImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    uis.SetDividerImage(imageDivider(tintColor), UIControlState.Normal, UIControlState.Normal, UIBarMetrics.Default);

    //layer.borderWidth = 1
    uis.Layer.BorderWidth = 1;

    //layer.borderColor = tintColor.cgColor
    uis.Layer.BorderColor = tintColor.CGColor;
}

3

Bạn có thể thực hiện phương pháp sau

extension UISegmentedControl{
    func selectedSegmentTintColor(_ color: UIColor) {
        self.setTitleTextAttributes([.foregroundColor: color], for: .selected)
    }
    func unselectedSegmentTintColor(_ color: UIColor) {
        self.setTitleTextAttributes([.foregroundColor: color], for: .normal)
    }
}

Mã sử ​​dụng

segmentControl.unselectedSegmentTintColor(.white)
segmentControl.selectedSegmentTintColor(.black)

0

Mặc dù các câu trả lời ở trên là tuyệt vời, nhưng hầu hết chúng đều bị sai màu văn bản bên trong đoạn đã chọn. Tôi đã tạo UISegmentedControllớp con mà bạn có thể sử dụng trên các thiết bị iOS 13 và trước iOS 13 và sử dụng thuộc tính tintColor như bạn làm trên các thiết bị iOS 13 trước.

    class LegacySegmentedControl: UISegmentedControl {
        private func stylize() {
            if #available(iOS 13.0, *) {
                selectedSegmentTintColor = tintColor
                let tintColorImage = UIImage(color: tintColor)
                setBackgroundImage(UIImage(color: backgroundColor ?? .clear), for: .normal, barMetrics: .default)
                setBackgroundImage(tintColorImage, for: .selected, barMetrics: .default)
                setBackgroundImage(UIImage(color: tintColor.withAlphaComponent(0.2)), for: .highlighted, barMetrics: .default)
                setBackgroundImage(tintColorImage, for: [.highlighted, .selected], barMetrics: .default)
                setTitleTextAttributes([.foregroundColor: tintColor!, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)

                setDividerImage(tintColorImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
                layer.borderWidth = 1
                layer.borderColor = tintColor.cgColor

// Detect underlying backgroundColor so the text color will be properly matched

                if let background = backgroundColor {
                    self.setTitleTextAttributes([.foregroundColor: background, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .selected)
                } else {
                    func detectBackgroundColor(of view: UIView?) -> UIColor? {
                        guard let view = view else {
                            return nil
                        }
                        if let color = view.backgroundColor, color != .clear {
                            return color
                        }
                        return detectBackgroundColor(of: view.superview)
                    }
                    let textColor = detectBackgroundColor(of: self) ?? .black

                    self.setTitleTextAttributes([.foregroundColor: textColor, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .selected)
                }
            }
        }

        override func tintColorDidChange() {
            super.tintColorDidChange()
            stylize()
        }
    }

    fileprivate extension UIImage {
        public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
          let rect = CGRect(origin: .zero, size: size)
          UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
          color.setFill()
          UIRectFill(rect)
          let image = UIGraphicsGetImageFromCurrentImageContext()
          UIGraphicsEndImageContext()

          guard let cgImage = image?.cgImage else { return nil }
          self.init(cgImage: cgImage)
        }
    }

Sử dụng tintColorDidChangephương pháp, chúng tôi đảm bảo rằng stylizephương thức sẽ được gọi mỗi khi thuộc tintColortính thay đổi trên chế độ xem phân đoạn hoặc bất kỳ chế độ xem cơ bản nào, đây là hành vi được ưu tiên trên iOS.

Kết quả: nhập mô tả hình ảnh ở đây


-2

Mở rộng một chút về câu trả lời Jonathan trong trường hợp bạn không muốn các góc tròn

extension UISegmentedControl {
    /// Tint color doesn't have any effect on iOS 13.
    func ensureiOS12Style(roundCorner: Bool = true) {
        if #available(iOS 13, *) {
            let tintColorImage = UIImage(color: tintColor)
            // Must set the background image for normal to something (even clear) else the rest won't work
            setBackgroundImage(UIImage(color: backgroundColor ?? .clear), for: .normal, barMetrics: .default)
            setBackgroundImage(tintColorImage, for: .selected, barMetrics: .default)
            setBackgroundImage(UIImage(color: tintColor.withAlphaComponent(0.2)), for: .highlighted, barMetrics: .default)
            setBackgroundImage(tintColorImage, for: [.highlighted, .selected], barMetrics: .default)
            setTitleTextAttributes([.foregroundColor: tintColor, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)
            setDividerImage(tintColorImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)

            if !roundCorner {
                layer.masksToBounds = false

                let borderView = UIView()
                borderView.layer.borderWidth = 1
                borderView.layer.borderColor = UIColor.black.cgColor
                borderView.isUserInteractionEnabled = false
                borderView.translatesAutoresizingMaskIntoConstraints = false

                addSubview(borderView)

                NSLayoutConstraint(item: borderView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0).isActive = true
                NSLayoutConstraint(item: borderView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
                NSLayoutConstraint(item: borderView, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0).isActive = true
                NSLayoutConstraint(item: borderView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: 0).isActive = true
            }
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.