จะเปลี่ยนสีของเซ็กเมนต์ใน UISegmentedControl ใน iOS 13 ได้อย่างไร


110

A UISegmentedControlมีรูปลักษณ์ใหม่ใน iOS 13 และโค้ดที่มีอยู่เพื่อปรับเปลี่ยนสีของตัวควบคุมแบบแบ่งส่วนไม่ทำงานเหมือนเดิมอีกต่อไป

ก่อนหน้า iOS 13 คุณสามารถตั้งค่าtintColorและจะใช้สำหรับเส้นขอบรอบตัวควบคุมแบบแบ่งกลุ่มเส้นระหว่างส่วนและสีพื้นหลังของส่วนที่เลือก titleTextAttributesจากนั้นคุณสามารถเปลี่ยนสีของชื่อของแต่ละส่วนที่ใช้แอตทริบิวต์สีพื้นด้วย

ภายใต้ iOS 13 tintColorไม่ทำอะไรเลย คุณสามารถตั้งค่าการควบคุมแบบแบ่งกลุ่มbackgroundColorเพื่อเปลี่ยนสีโดยรวมของตัวควบคุมแบบแบ่งกลุ่ม แต่ฉันไม่พบวิธีเปลี่ยนสีที่ใช้เป็นพื้นหลังของส่วนที่เลือก การตั้งค่าแอตทริบิวต์ข้อความยังคงใช้งานได้ ฉันได้ลองตั้งค่าสีพื้นหลังของชื่อเรื่อง แต่จะมีผลกับพื้นหลังของชื่อเท่านั้นไม่ใช่สีพื้นหลังที่เหลือของส่วนที่เลือก

ในระยะสั้นคุณจะแก้ไขสีพื้นหลังของส่วนที่เลือกในปัจจุบันของUISegmentedControliOS 13 ได้อย่างไร? มีวิธีแก้ปัญหาที่เหมาะสมโดยใช้ API สาธารณะที่ไม่ต้องขุดลงไปในโครงสร้างมุมมองย่อยส่วนตัวหรือไม่

ไม่มีคุณสมบัติใหม่ใน iOS 13 สำหรับUISegmentedControlหรือUIControlและไม่มีการเปลี่ยนแปลงUIViewใด ๆ ที่เกี่ยวข้อง

คำตอบ:


134

สำหรับ iOS 13b3 ตอนนี้มีselectedSegmentTintColorบนUISegmentedControl.

backgroundColorในการเปลี่ยนสีโดยรวมในการใช้งานการควบคุมการแบ่งกลุ่มของตน

selectedSegmentTintColorในการเปลี่ยนสีของใช้ส่วนที่เลือก

ในการเปลี่ยนสี / font ของชื่อส่วนที่ไม่ได้เลือกใช้setTitleTextAttributesกับรัฐของ/.normalUIControlStateNormal

ในการเปลี่ยนสี / แบบอักษรของชื่อเซ็กเมนต์ที่เลือกให้ใช้setTitleTextAttributesกับสถานะ.selected/UIControlStateSelected /

หากคุณสร้างการควบคุมแบบแบ่งส่วนด้วยรูปภาพหากรูปภาพถูกสร้างเป็นรูปภาพเทมเพลตระบบtintColorจะใช้ตัวควบคุมแบบแบ่งกลุ่มเพื่อระบายสีรูปภาพ แต่สิ่งนี้มีปัญหา หากคุณตั้งค่าเป็นtintColorสีเดียวselectedSegmentTintColorกับภาพจะไม่ปรากฏในส่วนที่เลือก หากคุณตั้งค่าเป็นtintColorสีเดียวbackgroundColorกับภาพในส่วนที่ไม่ได้เลือกจะไม่ปรากฏให้เห็น ซึ่งหมายความว่าการควบคุมแบบแบ่งส่วนของคุณด้วยรูปภาพต้องใช้ 3 สีที่แตกต่างกันเพื่อให้ทุกอย่างมองเห็นได้ หรือคุณสามารถใช้รูปภาพที่ไม่ใช่เทมเพลตและไม่ตั้งค่าไฟล์tintColor.

ภายใต้ iOS 12 ขึ้นไปเพียงตั้งค่าการควบคุมแบบแบ่งส่วนtintColorหรือพึ่งพาสีอ่อนโดยรวมของแอป


เราจะตั้งค่าตัวควบคุมเซ็กเมนต์แบบไม่มีขอบได้อย่างไร? ฉันไม่เห็นการตั้งค่าสำหรับสิ่งนี้ใน iOS 13 ก่อนหน้านี้การตั้งค่า tintcolor ก็เพียงพอแล้วสำหรับการควบคุมเซ็กเมนต์แบบไร้ขอบ
Deepak Sharma

โปรดเพิ่ม Border Color เป็นต้นเพื่อให้ทุกคนสามารถค้นหาปัญหาที่เกี่ยวข้องกับส่วนสีทั้งหมดได้รับการแก้ไขที่นี่ อะไรเอ่ย? :)
Yogesh Patel

1
@YogeshPatel แล้วสีเส้นขอบล่ะ? ไม่มีสีขอบใน iOS 13 และใน iOS 12 มีการตั้งค่าtintColorซึ่งครอบคลุมอยู่ในคำตอบแล้ว
rmaddy

@rmaddy ฉันได้ตั้งค่านี้ [segmentedControl.layer setBorderColor: [[UIColor whiteColor] CGColor]]; [segmentedControl.layer setBorderWidth: 0.5]; มันทำให้ฉันมีเส้นขอบและสีเส้นขอบใน iOS 13
Yogesh Patel

1
โอ้ชายแดนนั้น ซึ่งใช้กับข้อมูลพร็อพเพอร์ตี้ใด ๆ ไม่ใช่แค่การควบคุมแบบแบ่งกลุ่ม นั่นเกินขอบเขตของคำถามเดิมและคำตอบนี้ ความคิดเห็นของคุณก็เพียงพอแล้ว
rmaddy

48

ณ Xcode 11 เบต้า 3

มีตอนนี้คือทรัพย์สินในselectedSegmentTintColorUISegmentedControl

ดูคำตอบของ rmaddy


เพื่อกลับมาใช้ iOS 12

ฉันไม่สามารถย้อมสีของกลุ่มที่เลือกได้หวังว่าจะได้รับการแก้ไขในเบต้าที่กำลังจะมาถึง

การตั้งค่าภาพพื้นหลังของสถานะที่เลือกจะไม่ทำงานหากไม่มีการตั้งค่าภาพพื้นหลังของสถานะปกติ (ซึ่งจะลบสไตล์ iOS 13 ทั้งหมด)

แต่ฉันสามารถทำให้มันกลับมาเป็น iOS 12 ได้ (หรือใกล้พอที่ฉันไม่สามารถคืนรัศมีมุมให้เล็กลงได้)

ไม่เหมาะอย่างยิ่ง แต่การควบคุมแบบแบ่งส่วนสีขาวสว่างดูไม่เหมาะสมในแอปของเรา

(ไม่ทราบว่าUIImage(color:)เป็นวิธีการส่วนขยายใน codebase ของเรา แต่โค้ดที่จะนำไปใช้นั้นมีอยู่ทั่วเว็บ)

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
        }
    }
}

รูปภาพแสดงเอฟเฟกต์ของโค้ดด้านบน


นี่อาจเป็นวิธีแก้ปัญหาที่ดี ฉันยังไม่ได้มีโอกาสลองทำ แต่สิ่งนี้จำเป็นต้องมีการโทรsetTitleTextAttributesเพื่อทำให้ชื่อของกลุ่มที่เลือกเป็นสีขาวหรือไม่
rmaddy

อืมดูเหมือนว่าควร แต่ดูเหมือนจะไม่ใช่ ฉันไม่สามารถเข้าถึง atm การใช้รหัสนั้นได้ แต่รูปภาพทางด้านซ้ายถูกสร้างขึ้นด้วยรหัสนั้น
โจนาธาน

8
stackoverflow.com/a/33675160/5790492สำหรับส่วนขยาย UIImage (สี :)
Nik Kov

1
คงจะดีไม่น้อยถ้าคุณจะเพิ่มส่วนขยาย UIImage ด้วยวิธีนี้คำตอบของคุณยังไม่สมบูรณ์ iho
FredFlinstone

1
@VityaShurapov ตั้งค่าไว้เมื่อทั้งไฮไลต์และเลือกไม่ใช่อาร์เรย์ของสถานะที่ส่งผ่าน แต่เป็นชุดตัวเลือกซึ่งหมายความว่าค่าต่างๆจะรวมกันเพื่อสร้างสถานะใหม่
โจนาธาน

37

iOS 13 และ Swift 5.0 (Xcode 11.0) การควบคุมเซ็กเมนต์ทำงานได้ 100%

ป้อนคำอธิบายภาพที่นี่

ป้อนคำอธิบายภาพที่นี่

 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
}

8
คุณลองตั้งพื้นหลังเป็นสีขาวดูไหม สำหรับฉันมันกำลังจะมาเป็นสีเทา
Ronit

@Itan ต้องการ xcode และภาษาที่รวดเร็วที่คุณใช้?
Maulik Patel

@Ronit แน่นอน !! ฉันจะลอง แต่โปรดบอกฉันว่าตอนนี้แสดงผลประเภทใด
Maulik Patel

รวดเร็ว 5, xcode 11.3! มันแสดงให้เห็นว่ามันต้องการอะไร! ไม่ใช่คนที่ฉันต้องการ :)
Itan Hant

16

ฉันได้ลองวิธีแก้ปัญหาแล้วและได้ผลดีสำหรับฉัน นี่คือรุ่น 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
ฉันไม่แน่ใจว่าจะใช้ได้กับCGRectMake(0.0f, 0.0f, 1.0f, 1.0f): จากการทดสอบของฉันกับ Xcode 11 beta rectจะต้องมีขนาดเท่ากับขอบเขตของการควบคุมแบบแบ่งกลุ่ม
Cœur

2
เนื่องจาก iOS13 เบต้า 6 tintcolor ไม่ปรากฏบนปุ่มที่เลือกดังนั้นฉันจึงต้องเพิ่มบรรทัด: [self setTitleTextAttributes: @ {NSForegroundColorAttributeName: UIColor.blackColor, NSFontAttributeName: [UIFont systemFontOfSize: 13]} forState: UIControl];
Peter Johnson

เมื่อฉันพยายามใช้สิ่งนี้[[UISegmentedControl appearance] ensureiOS12Style]ฉันได้รับข้อยกเว้น มีความคิดอะไรเกิดขึ้น? Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSMethodSignature getArgumentTypeAtIndex:]: index (2) out of bounds [0, 1]'
Jeremy Hicks

13

ณ Xcode 11 เบต้า 3

มีตอนนี้คือทรัพย์สินในselectedSegmentTintColorUISegmentedControl

ขอบคุณ @rmaddy!


คำตอบเดิมสำหรับ Xcode 11 เบต้าและเบต้า 2

มีวิธีแก้ปัญหาที่เหมาะสมโดยใช้ API สาธารณะที่ไม่ต้องขุดลงไปในโครงสร้างมุมมองย่อยส่วนตัวหรือไม่

ด้วย Xcode 11.0 beta ดูเหมือนว่าจะเป็นความท้าทายที่จะต้องทำตามกฎเพราะโดยพื้นฐานแล้วจะต้องวาดภาพพื้นหลังทั้งหมดใหม่สำหรับทุกสถานะด้วยตัวเองด้วยมุมกลมความโปร่งใสและresizableImage(withCapInsets:). ตัวอย่างเช่นคุณจะต้องสร้างภาพที่มีสีคล้ายกับ:
ป้อนคำอธิบายภาพที่นี่

ดังนั้นสำหรับตอนนี้วิธีการเจาะลึกลงไปในมุมมองย่อยดูเหมือนง่ายกว่ามาก:

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
                }
            }
        }
    }
}

โซลูชันนี้จะใช้สีอ่อนกับสิ่งที่เลือกได้อย่างถูกต้องเช่น: ป้อนคำอธิบายภาพที่นี่


1
ได้รับรางวัลเนื่องจากเวลาหมดลง แต่ควรหาวิธีแก้ปัญหาที่ไม่เกี่ยวข้องกับการขุดลงในลำดับชั้นส่วนตัว :)
โจนาธาน

@ โจนาธาน. ขอบคุณ. คุณมีวิธีแก้ปัญหาที่ใกล้เคียงที่สุดที่ไม่เกี่ยวข้องกับการดูลำดับชั้น: เพราะเมื่อคุณsetBackgroundImageต้องการ.normalแล้วคุณต้องตั้งค่ารูปภาพอื่น ๆ ทั้งหมด (รวมถึงสถานะอื่น ๆ และsetDividerImage) อาจมีบางส่วนUIBezierPathและresizableImage(withCapInsets:)ทำให้ซับซ้อนเกินไปหากเราต้องการการออกแบบ iOS 13 ทางนี้.
Cœur

ใช่มันจะได้รับการแก้ไขในเบต้า
โจนาธาน

3
สิ่งนี้ไม่จำเป็นอีกต่อไปสำหรับ iOS 13b3 มีตอนนี้คือทรัพย์สินในselectedSegmentTintColor UISegmentedControl
rmaddy

11

คำตอบของ @Ilahi Charfeddine เวอร์ชันที่รวดเร็ว:

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

วิธีใช้:

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
นี่เป็นวิธีเดียวที่ใช้ได้ผลสำหรับฉัน - ภาพพื้นหลัง selectedSegmentTintColor ไม่ทำงานด้วยเหตุผลบางประการ
DenNukem

7

XCODE 11.1 และ iOS 13

ตามคำตอบของ @Jigar Darji แต่การใช้งานที่ปลอดภัยกว่า

อันดับแรกเราสร้างตัวเริ่มต้นอำนวยความสะดวกที่ล้มเหลว:

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)
   }
}

จากนั้นเราขยาย 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
    }
  }
}

สมบูรณ์แบบ! ขอบคุณ!
Senocico Stelian

5

นี่คือคำตอบของ Jonathan. สำหรับ Xamarin.iOS (C #) แต่มีการแก้ไขสำหรับการปรับขนาดภาพ เช่นเดียวกับความคิดเห็นของCœurเกี่ยวกับคำตอบของ Colin Blake ฉันสร้างภาพทั้งหมดยกเว้นการแบ่งขนาดของตัวควบคุมแบบแบ่งส่วน ตัวแบ่งมีความสูง 1 เท่าของส่วน

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

คุณสามารถใช้วิธีการต่อไปนี้

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

รหัสการใช้งาน

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

2

แม้ว่าคำตอบข้างต้นจะดีมาก แต่ส่วนใหญ่มีสีของข้อความในส่วนที่เลือกผิด ฉันได้สร้างUISegmentedControlคลาสย่อยที่คุณสามารถใช้ได้บนอุปกรณ์ iOS 13 และก่อน iOS 13 และใช้คุณสมบัติ tintColor เหมือนกับที่คุณทำบนอุปกรณ์ iOS 13 รุ่นก่อน

    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)
        }
    }

การใช้tintColorDidChangeวิธีนี้ทำให้เรามั่นใจได้ว่าstylizeจะมีการเรียกเมธอดทุกครั้งที่tintColorคุณสมบัติเปลี่ยนแปลงในมุมมองกลุ่มหรือมุมมองพื้นฐานใด ๆ ซึ่งเป็นพฤติกรรมที่ต้องการบน iOS

ผลลัพธ์: ป้อนคำอธิบายภาพที่นี่


-2

ขยายความเล็กน้อยเกี่ยวกับคำตอบของโจนาธานในกรณีที่คุณไม่ต้องการมุมมน

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
            }
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.