Изменить только один определенный цвет оттенка UITabBarItem

Хорошо известно, что цвет оттенка выбранных (или активных) элементов в UITabBarController можно легко изменить, вот пример:

myBarController.tabBar.tintColor = [UIColor redColor];

В этом случае любой элемент панели вкладок в tabBar будет иметь красный оттенок, как только он станет активным. Опять же, это относится ко всем элементам на этой панели вкладок.

Как может различаться активный цвет оттенка для других элементов панели вкладок на той же панели? Например, при выделении один элемент может иметь красный оттенок, а другой - синий.

Я знаю, что это, вероятно, можно решить, перерисовав и создав подклассы всей панели вкладок. Однако это единственное изменение, которое мне нужно, и это кажется излишним. Я не пытаюсь изменить стиль или то, как элементы отображаются каким-либо образом, просто чтобы сделать этот стиль различным для разных элементов.

Я нигде не видел ответов на этот вопрос, относящихся к обновлениям в iOS 7 и 8.


person element119    schedule 23.07.2014    source источник
comment
Пожалуйста, проверьте мой подробный ответ: stackoverflow.com/questions/43002013/   -  person erickva    schedule 05.12.2017


Ответы (6)


Есть более простой способ сделать это! Добавьте это в ViewController, который элемент UITabBar должен быть другого цвета

- (void) viewWillAppear:(BOOL)animated {
   // change tint color to red
   [self.tabBarController.tabBar setTintColor:[UIColor redColor]];
   [super viewWillAppear: animated];
}

Вставьте это в другие ViewControllers

- (void) viewWillAppear:(BOOL)animated {
   // change tint color to black
   [self.tabBarController.tabBar setTintColor:[UIColor blackColor]];
   [super viewWillAppear: animated];
}

Я использую это, чтобы получить разные цвета оттенка в каждом ViewController, например: [красный | черный | зеленый | розовый ]

person Kai Burghardt    schedule 13.08.2014
comment
Для тех, кто использует swift: tabBarController?.tabBar.tintColor = UIColor.redColor() - person Andrej; 11.03.2016

Решение @ element119 с использованием быстрого (для вас, ленивых):

extension UIImage {
    func tabBarImageWithCustomTint(tintColor: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        let context: CGContextRef = UIGraphicsGetCurrentContext()

        CGContextTranslateCTM(context, 0, self.size.height)
        CGContextScaleCTM(context, 1.0, -1.0)
        CGContextSetBlendMode(context, kCGBlendModeNormal)
        let rect: CGRect = CGRectMake(0, 0, self.size.width, self.size.height)

        CGContextClipToMask(context, rect, self.CGImage)

        tintColor.setFill()
        CGContextFillRect(context, rect)

        var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        newImage = newImage.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
        return newImage
    }
}

Я использую этот код, чтобы подкрасить свой средний значок в красный цвет:

if let items = self.tabBar.items as? [UITabBarItem] {
    let button = items[1]
    button.image = button.image?.tabBarImageWithCustomTint(UIColor.redColor())
}
person Binsh    schedule 20.08.2015
comment
SWIFT 2: CGBlendMode.Normal вместо kCGBlendModeNormal, спасибо за ответ выше - person Yogesh Lolusare; 20.11.2015

Я немного поэкспериментировал и на основе этого ответа нашел способ делать то, что я хочу без подкласс UITabBarItem или UITabBar!

По сути, идея состоит в том, чтобы создать метод UIImage, который имитирует поведение маски оттенка UITabBar, при этом отображая его в «исходной» форме и избегая собственной маски оттенка.

Все, что вам нужно сделать, это создать новый метод экземпляра UIImage, который возвращает изображение, замаскированное желаемым цветом:

@interface UIImage(Overlay)
- (instancetype)tabBarImageWithCustomTint:(UIColor *)tintColor;
@end

@implementation UIImage(Overlay)

- (instancetype)tabBarImageWithCustomTint:(UIColor *)tintColor
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0, self.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGContextClipToMask(context, rect, self.CGImage);
    [tintColor setFill];
    CGContextFillRect(context, rect);
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    newImage = [newImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    return newImage;
}
@end

Это довольно простая версия кода в ответе, который я опубликовал, за одним исключением - для возвращенного изображения установлен режим рендеринга всегда исходный, что гарантирует, что маска UITabBar по умолчанию не будет применяться. Теперь все, что нужно, - это использовать этот метод при редактировании элемента панели вкладок:

navController.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"title" image:normal_image selectedImage:[selected_image tabBarImageWithCustomTint:[UIColor redColor]]];

Излишне говорить, что selected_image - это нормальное изображение, получаемое от UIImage imageNamed:, а [UIColor redColor можно заменить любым желаемым цветом.

person element119    schedule 23.07.2014

Это сработало для меня !! код для Swift 3

extension UIImage {
    func tabBarImageWithCustomTint(tintColor: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        let context: CGContext = UIGraphicsGetCurrentContext()!
        context.translateBy(x: 0, y: self.size.height)
        context.scaleBy(x: 1.0, y: -1.0)
        context.setBlendMode(CGBlendMode(rawValue: 1)!)
        let rect: CGRect = CGRect(x: 0, y: 0, width:  self.size.width, height: self.size.height)
        context.clip(to: rect, mask: self.cgImage!)
        tintColor.setFill()
        context.fill(rect)
        var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        newImage = newImage.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
        return newImage
    }
}

и после...

 button.image = button.image?.tabBarImageWithCustomTint(tintColor: UIColor(red: 30.0/255.0, green: 33.0/255.0, blue: 108.0/255.0, alpha: 1.0))

Благодарность ;))

person David Torguet    schedule 05.11.2016

swift xcode7.1 протестирован:

extension UIImage {
    func tabBarImageWithCustomTint(tintColor: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        let context: CGContextRef = UIGraphicsGetCurrentContext()!

        CGContextTranslateCTM(context, 0, self.size.height)
        CGContextScaleCTM(context, 1.0, -1.0)
        CGContextSetBlendMode(context, CGBlendMode.Normal)
        let rect: CGRect = CGRectMake(0, 0, self.size.width, self.size.height)

        CGContextClipToMask(context, rect, self.CGImage)

        tintColor.setFill()
        CGContextFillRect(context, rect)

        var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        newImage = newImage.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
        return newImage
    }
}

исправлена ​​ошибка совместимости в ответе @Binsh

person ergunkocak    schedule 13.11.2015

Swift 5:

extension UIImage {
    func tintWithColor(color: UIColor) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        
        context.scaleBy(x: 1.0, y: -1.0)
        context.translateBy(x: 0.0, y: -self.size.height)
        context.setBlendMode(.multiply)
        
        let rect = CGRect(origin: .zero, size: size)
        guard let cgImage = self.cgImage else { return nil }
        context.clip(to: rect, mask: cgImage)
        color.setFill()
        context.fill(rect)
        
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return newImage
        
    }
    
}
person joel.d    schedule 16.11.2020