Bagaimana cara mengubah warna segmen di UISegmentedControl di iOS 13?

109

A UISegmentedControlmemiliki tampilan baru di iOS 13 dan kode yang ada untuk mengubah warna kontrol tersegmentasi tidak lagi berfungsi seperti sebelumnya.

Sebelum iOS 13 Anda dapat mengatur tintColordan yang akan digunakan untuk perbatasan di sekitar kontrol tersegmentasi, garis antara segmen, dan warna latar belakang segmen yang dipilih. Kemudian Anda dapat mengubah warna judul setiap segmen menggunakan atribut warna latar depan dengan titleTextAttributes.

Di bawah iOS 13, tintColortidak melakukan apa pun. Anda dapat menyetel kontrol tersegmentasi backgroundColoruntuk mengubah warna keseluruhan dari kontrol tersegmentasi. Tetapi saya tidak dapat menemukan cara untuk mengubah warna yang digunakan sebagai latar belakang segmen yang dipilih. Mengatur atribut teks masih berfungsi. Saya bahkan mencoba mengatur warna latar belakang judul tetapi itu hanya mempengaruhi latar belakang judul, bukan warna latar belakang segmen yang dipilih lainnya.

Singkatnya, bagaimana Anda mengubah warna latar belakang segmen yang saat ini dipilih UISegmentedControldi iOS 13? Apakah ada solusi yang tepat, menggunakan API publik, yang tidak memerlukan penggalian ke dalam struktur subview pribadi?

Tidak ada properti baru di iOS 13 untuk UISegmentedControlatau UIControldan tidak ada perubahan di UIViewrelevan.

rmaddy
sumber

Jawaban:

134

Mulai iOS 13b3, sekarang ada selectedSegmentTintColoron UISegmentedControl.

Untuk mengubah warna keseluruhan dari kontrol tersegmentasi, gunakan its backgroundColor.

Untuk mengubah warna penggunaan segmen yang dipilih selectedSegmentTintColor.

Untuk mengubah warna / font dari judul segmen yang tidak dipilih, gunakan setTitleTextAttributesdengan status .normal/ UIControlStateNormal.

Untuk mengubah warna / font dari judul segmen yang dipilih, gunakan setTitleTextAttributesdengan status .selected/ UIControlStateSelected.

Jika Anda membuat kontrol tersegmentasi dengan gambar, jika gambar dibuat sebagai gambar template, maka kontrol tersegmentasi tintColorakan digunakan untuk mewarnai gambar. Tapi ini ada masalah. Jika Anda menyetel tintColorke warna yang sama seperti selectedSegmentTintColormaka gambar tidak akan terlihat di segmen yang dipilih. Jika Anda menyetel tintColorke warna yang sama seperti backgroundColor, maka gambar pada segmen yang tidak dipilih tidak akan terlihat. Ini berarti kontrol Anda yang tersegmentasi dengan gambar harus menggunakan 3 warna berbeda agar semuanya terlihat. Atau Anda dapat menggunakan gambar non-template dan tidak menyetel tintColor.

Di bawah iOS 12 atau lebih lama, cukup atur kontrol tersegmentasi tintColoratau andalkan warna tint keseluruhan aplikasi.

rmaddy
sumber
Bagaimana kita menyetel pengontrol segmen tanpa batas? Saya tidak melihat pengaturan untuk ini di iOS 13. Sebelumnya, pengaturan tintcolor sudah cukup untuk mendapatkan kontrol segmen tanpa batas.
Deepak Sharma
Harap tambahkan Warna Tepi, dll. Sehingga semua dapat menemukan semua segmen. Masalah terkait Warna diselesaikan di sini. apa yang dikatakan? :)
Yogesh Patel
1
@YogeshPatel Bagaimana dengan warna border? Tidak ada warna batas di iOS 13 dan di iOS 12 itu diatur dengan tintColoryang sudah tercakup dalam jawabannya.
rmaddy
@rmaddy Saya telah menyetel [segmentedControl.layer setBorderColor: [[UIColor whiteColor] CGColor]] ini; [segmentedControl.layer setBorderWidth: 0,5]; itu memberi saya warna batas dan batas di iOS 13.
Yogesh Patel
1
Oh, perbatasan itu. Itu berlaku untuk tampilan apa pun, bukan hanya kontrol tersegmentasi. Itu di luar cakupan pertanyaan awal dan jawaban ini. Komentar Anda sudah cukup.
rmaddy
47

Mulai Xcode 11 beta 3

Sekarang ada selectedSegmentTintColorproperti di UISegmentedControl.

Lihat jawaban rmaddy


Untuk mendapatkan kembali tampilan iOS 12

Saya tidak dapat mewarnai warna segmen yang dipilih, mudah-mudahan ini akan diperbaiki dalam versi beta yang akan datang.

Mengatur gambar latar belakang dari keadaan yang dipilih tidak berfungsi tanpa mengatur gambar latar belakang dari keadaan normal (yang menghapus semua gaya iOS 13)

Tapi saya bisa mengembalikannya ke tampilan iOS 12 (atau cukup dekat, saya tidak bisa mengembalikan radius sudut ke ukurannya yang lebih kecil).

Ini tidak ideal, tetapi kontrol tersegmentasi putih cerah terlihat agak tidak pada tempatnya di aplikasi kami.

(Tidak disadari UIImage(color:)adalah metode ekstensi dalam basis kode kami. Tetapi kode untuk menerapkannya ada di seluruh 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
        }
    }
}

Gambar yang menunjukkan efek dari kode di atas

Jonathan.
sumber
Ini bisa menjadi solusi yang bagus. Saya belum sempat mencobanya tapi apakah ini juga memerlukan panggilan setTitleTextAttributesuntuk membuat judul segmen yang dipilih berwarna putih?
rmaddy
Hmm, sepertinya memang seharusnya tapi sepertinya tidak. Saya belum mendapatkan akses ke penggunaan kode tersebut, tetapi gambar di sebelah kiri dibuat dengan kode itu.
Jonathan.
8
stackoverflow.com/a/33675160/5790492 untuk ekstensi UIImage (color :).
Nik Kov
1
Alangkah baiknya jika Anda menambahkan ekstensi UIImage, dengan cara ini, jawaban Anda tidak lengkap iho
FredFlinstone
1
@VityaShurapov mengaturnya saat disorot dan dipilih, ini bukan larik status yang diteruskan melainkan set opsi, yang berarti nilai digabungkan untuk membuat status baru.
Jonathan.
36

IOS 13 dan Swift 5.0 (Xcode 11.0) Kontrol Segmen 100% Berfungsi

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

 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
}
Maulik Patel
sumber
7
apakah Anda mencoba menyetel latar belakang menjadi putih? bagi saya itu datang s keabu
Ronit
@ItanHant xcode dan bahasa cepat mana yang Anda gunakan?
Maulik Patel
@Ronit tentu saja !! saya akan mencoba tapi tolong beritahu saya apa jenis tampilan keluaran sekarang
Maulik Patel
cepat 5, xcode 11.3! itu menunjukkan apa yang diinginkannya! bukan yang saya inginkan :)
Itan Hant
15

Saya sudah mencoba solusi tersebut dan hasilnya bagus untuk saya. Inilah versi 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
Colin Blake
sumber
2
Saya tidak yakin itu akan berfungsi dengan CGRectMake(0.0f, 0.0f, 1.0f, 1.0f): dari pengujian saya dengan Xcode 11 beta, rectharus berukuran sama dengan batas-batas kontrol tersegmentasi.
Cœur
2
Sejak iOS13 beta 6 tintcolor tidak muncul pada tombol yang dipilih, jadi saya harus menambahkan baris: [self setTitleTextAttributes: @ {NSForegroundColorAttributeName: UIColor.blackColor, NSFontAttributeName: [UIFont systemFontOfSize: 13]} forState: UIControlStateSelected];
Peter Johnson
Ketika saya mencoba menggunakan ini pada [[UISegmentedControl appearance] ensureiOS12Style]saya mendapatkan pengecualian. Tahu apa yang sedang terjadi? Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSMethodSignature getArgumentTypeAtIndex:]: index (2) out of bounds [0, 1]'
Jeremy Hicks
13

Mulai Xcode 11 beta 3

Sekarang ada selectedSegmentTintColorproperti di UISegmentedControl.

Terima kasih @rmaddy!


Jawaban asli, untuk Xcode 11 beta dan beta 2

Apakah ada solusi yang tepat, menggunakan API publik, yang tidak memerlukan penggalian ke dalam struktur subview pribadi?

Dengan Xcode 11.0 beta, tampaknya menjadi tantangan untuk melakukannya sesuai aturan, karena pada dasarnya perlu menggambar ulang semua gambar latar belakang untuk setiap negara bagian sendiri, dengan sudut bulat, transparansi, dan resizableImage(withCapInsets:). Misalnya, Anda perlu membuat gambar berwarna seperti:
masukkan deskripsi gambar di sini

Jadi untuk saat ini, cara mari-gali-ke-subview tampaknya jauh lebih mudah:

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

Solusi ini akan menerapkan warna tint dengan benar ke seleksi, seperti pada: masukkan deskripsi gambar di sini

Cœur
sumber
1
Diberikan karena waktu hampir habis, tetapi sebaiknya solusi yang tidak melibatkan penggalian ke dalam hierarki pribadi akan ditemukan :)
Jonathan.
@Jonathan. Terima kasih. Anda sudah mendapatkan solusi terdekat yang tidak melibatkan melihat hierarki: karena begitu Anda setBackgroundImagemelakukannya .normal, Anda harus mengatur semua gambar lain (termasuk status lain dan setDividerImage), mungkin dengan beberapa UIBezierPathdan resizableImage(withCapInsets:), yang membuatnya terlalu rumit jika kita menginginkan desain iOS 13 cara ini.
Cœur
Yup, idealnya akan diperbaiki dalam versi beta
Jonathan.
3
Ini tidak lagi diperlukan mulai iOS 13b3. Sekarang ada selectedSegmentTintColorproperti di UISegmentedControl.
rmaddy
11

Versi Swift jawaban @Ilahi Charfeddine:

if #available(iOS 13.0, *) {
   segmentedControl.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
   segmentedControl.selectedSegmentTintColor = UIColor.blue
} else {
   segmentedControl.tintColor = UIColor.blue
}
Vignan S
sumber
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]];}
Ilahi Charfeddine
sumber
7

iOS13 UISegmentController

Cara Penggunaan:

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()!)!
    }
}
Jigar Darji
sumber
1
Ini adalah satu-satunya pendekatan yang berhasil untuk saya - gambar latar belakang. selectedSegmentTintColor tidak berfungsi karena beberapa alasan.
DenNukem
7

XCODE 11.1 & iOS 13

Berdasarkan jawaban @Jigar Darji tetapi implementasi yang lebih aman.

Pertama-tama kami membuat penginisialisasi kenyamanan yang dapat gagal:

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

Kemudian kami memperluas 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
    }
  }
}
FredFlinstone
sumber
Sempurna! Terima kasih!
Senocico Stelian
5

Inilah pendapat saya tentang jawaban Jonathan. untuk Xamarin.iOS (C #), tetapi dengan perbaikan untuk ukuran gambar. Terkait dengan komentar Cœur atas jawaban Colin Blake, saya membuat semua gambar kecuali pembatas sebesar ukuran kontrol tersegmentasi. Pembatas adalah 1xtinggi segmen.

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;
}
t9mike
sumber
3

Anda dapat menerapkan metode berikut

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

Kode penggunaan

segmentControl.unselectedSegmentTintColor(.white)
segmentControl.selectedSegmentTintColor(.black)
Zain Anjum
sumber
0

Meskipun jawaban di atas bagus, sebagian besar mendapatkan warna teks di dalam segmen yang dipilih salah. Saya telah membuat UISegmentedControlsubclass yang dapat Anda gunakan pada perangkat iOS 13 dan pra-iOS 13 dan menggunakan properti tintColor seperti yang Anda lakukan pada perangkat pra-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)
        }
    }

Dengan menggunakan tintColorDidChangemetode, kami memastikan bahwa stylizemetode tersebut akan dipanggil setiap kali tintColorproperti berubah pada tampilan segmen, atau salah satu tampilan yang mendasari, yang merupakan perilaku yang disukai di iOS.

Hasil: masukkan deskripsi gambar di sini

Adam
sumber
-2

Memperluas sedikit pada jawaban Jonathan jika Anda tidak ingin sudut bundar

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