Sửa đổi UIImage renderingMode từ tệp storyboard / xib


93

Là nó có thể để sửa đổi một UIImage's renderingModetừ một kịch bản hay xib biên tập viên?

Mục đích là áp dụng tintColorcho UIImageViewđối tượng cụ thể.

Câu trả lời:


101

Đây là cách bạn có thể thực hiện trong tệp .xib hoặc bảng phân cảnh:

(Obj-C) Tạo một danh mục trên UIImageView:

@interface UIImageView (Utils)

- (void)setImageRenderingMode:(UIImageRenderingMode)renderMode;

@end

@implementation UIImageView (Utils)

- (void)setImageRenderingMode:(UIImageRenderingMode)renderMode
{
    NSAssert(self.image, @"Image must be set before setting rendering mode");
    self.image = [self.image imageWithRenderingMode:renderMode];
}

@end

(Swift 4) Tạo tiện ích mở rộng cho UIImageView:

extension UIImageView {
    func setImageRenderingMode(_ renderMode: UIImage.RenderingMode) {
        assert(image != nil, "Image must be set before setting rendering mode")
        // AlwaysOriginal as an example
        image = image?.withRenderingMode(.alwaysOriginal)
    }
}

Sau đó, trong Trình kiểm tra danh tính trong tệp xib, hãy thêm thuộc tính thời gian chạy:

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


44
Điều tôi thích ở câu trả lời này, là nó là một câu trả lời cho câu hỏi.
algal

1
Tôi muốn tạo một lớp con UIImageView hơn là thực hiện cài đặt giá trị khóa. Bởi vì, điều này dễ thiết lập hơn và chúng tôi có thể tránh cài đặt số thành giá trị liệt kê. Ví dụ: `@implementation TemplateRenderingImageView - (id) initWithCoder: (NSCoder *) aDecoder {self = [super initWithCoder: aDecoder]; if (self) {self.image = [self.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate]; } tự trả lại; } @ end`
john fantasy

1
Câu trả lời chính xác! Các ảnh chụp màn hình rất hữu ích.
BigSauce

1
Tất nhiên, không hoạt động với Launch Screen.xib vì bạn không thể sử dụng các thuộc tính thời gian chạy do người dùng xác định với nó.
Steve Moser

3
hardcoding 2 as a value là bad bad bad .. Việc sử dụng xcassets catalog là câu trả lời đúng.
tGilani

198

Bạn có thể đặt chế độ kết xuất hình ảnh không phải trong .xibtệp mà trong .xcassetsthư viện.

Sau khi thêm hình ảnh vào thư viện nội dung, hãy chọn hình ảnh và mở trình kiểm tra thuộc tính ở phía bên phải của Xcode. Tìm thuộc tính 'Render As' và đặt nó thành 'template'.

Sau khi thiết lập chế độ vẽ của hình ảnh, bạn có thể thêm một màu sắc đến UIImageViewtrong một .xibhoặc .storyboardtập tin để điều chỉnh màu sắc hình ảnh.

Điều này đặt thuộc tính trên hình ảnh ở bất kỳ nơi nào nó được sử dụng thay vì chỉ trong một tệp trình tạo giao diện, nhưng trong hầu hết các trường hợp (mà tôi đã gặp) thì đây là hành vi bạn muốn.

Ảnh chụp màn hình Xcode hiển thị trình kiểm tra thuộc tính cho một hình ảnh

Một số điều cần lưu ý:

  • Màu hình ảnh sẽ không thay đổi trong trình tạo giao diện (kể từ Xcode 6.1.1) nhưng sẽ hoạt động khi ứng dụng được chạy.
  • Tôi đã gặp phải một số rắc rối với tính năng này và trong một số tình huống, tôi phải xóa và thêm lại UIImageView. Tôi đã không nhìn sâu vào điều đó.
  • Điều này cũng hoạt động tốt trên các UIKitComponentshình ảnh khác như hình ảnh trong UIButton's và UIBarButtonItem'.
  • Nếu bạn có một loạt hình ảnh màu trắng ẩn trong thư viện nội dung của mình, thì việc đặt chúng là hình ảnh đen / trong suốt và thay đổi chế độ hiển thị sẽ giúp cuộc sống của bạn tốt hơn gấp 10 lần.

15
Có vẻ như đã xảy ra lỗi khi bật màu sắc UIImageView, vì vậy màu sắc không phải lúc nào cũng hiển thị khi chạy ứng dụng.
Fogh

@Fogh Tôi cũng gặp một số lỗi không nhất quán như vậy. Cài đặt màu theo chương trình có khắc phục được điều này không?
Anthony Mattox

2
Tôi có thể xác nhận rằng có sự cố khi đặt màu sắc trong IB. Đặt nó hoạt động theo chương trình. Tôi đã gửi lỗi # 20305518 cho nó.
Nikolay Derkach

1
@AxelGuilmin Yup. Trên thực tế, chỉ kênh alpha được sử dụng, vì vậy nó có thể là bất kỳ màu nào miễn là độ trong suốt là những gì bạn muốn.
Anthony Mattox

1
Nó hiện hoạt động với Xcode 7.3 (7D175)! Mặc dù câu trả lời được chấp nhận là một cách giải quyết rất trực quan, tôi thích câu trả lời này hơn.
nstein

43

Sử dụng chế độ hiển thị mẫu với UIImageView trong bảng phân cảnh hoặc xib rất nhiều lỗi, cả trên iOS 7 và iOS 8.

Trên iOS 7

UIImage không được giải mã đúng cách từ bảng phân cảnh / xib. Nếu bạn kiểm tra thuộc imageView.image.renderingModetính trong viewDidLoadphương thức, bạn sẽ nhận thấy rằng nó luôn như vậy UIImageRenderingModeAutomatic, ngay cả khi bạn đặt nó thành Hiển thị Dưới dạng Hình ảnh Mẫu trong tệp xcassets của mình.

Để giải quyết vấn đề, bạn phải đặt chế độ kết xuất theo cách thủ công:

self.imageView.image = [self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Trên iOS 8

UIImage được giải mã đúng cách và thuộc tính của nó renderingModephản ánh những gì đã được chọn trong tệp xcassets nhưng hình ảnh không được tô màu.

Để giải quyết vấn đề, bạn có hai tùy chọn:

  1. Đặt thuộc tintColortính trong Thuộc tính thời gian chạy do người dùng xác định thay vì ngăn kiểm tra thuộc tính.

hoặc là

  1. Đặt lại màu theo cách thủ công:
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;

Bạn có thể chọn tùy chọn ưa thích của mình, cả hai đều tô màu đúng cho hình ảnh.

(Nếu bạn đang biên dịch với Xcode 6.2, chỉ cần làm self.imageView.tintColor = self.imageView.tintColor;là đủ nhưng điều này không hoạt động nữa nếu bạn đang biên dịch với Xcode 6.3)

Phần kết luận

Nếu bạn cần hỗ trợ cả iOS 7 và iOS 8, bạn sẽ cần cả hai cách giải quyết. Nếu bạn chỉ phải hỗ trợ iOS 8, chỉ cần một giải pháp thay thế.


2
Cảm ơn. Chỉ có giải pháp số 2 đang hoạt động đối với tôi trong Xcode 7 và iOS 8.
lướt web

3
Tôi xác nhận rằng các workaround cho iOS 8 cũng là valable dành cho iOS 9.
Michael Pirotte

1
Tôi chắc chắn thấy điều tương tự trên Xcode 7 - cách giải quyết thuộc tính người dùng là tốt. Cảm ơn!
Geoffrey Wiseman

đặt lại màu theo cách thủ công trong AwakeFromNib đã làm được! (hình ảnh cũng được đặt thành mẫu trong danh mục .xcassets, nếu không bạn phải tạo hình ảnh mẫu từ bản gốc). Cảm ơn!!
horsehoe7

15

Cài đặt imageView RenderingMode để sử dụng màu sắc trong bảng phân cảnh có thể được giảm thành một lớp lót:

[self.imageView setImage:[self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];

Sau đó, hình ảnh và màu sắc đều có thể được đặt trong Bảng phân cảnh.


13

Bạn có thể khắc phục sự cố .xib bằng một tiện ích mở rộng:

import UIKit

// fixing Bug in XCode
// http://openradar.appspot.com/18448072
extension UIImageView {
    override open func awakeFromNib() {
        super.awakeFromNib()
        self.tintColorDidChange()
    }
}

Nguồn: https://gist.github.com/buechner/3b97000a6570a2bfbc99c005cb010bac

Thật ngạc nhiên, con bọ này đã tồn tại khoảng 4-5 năm nay.


3
Điều này nên được chọn là câu trả lời
farzadshbfn

Vẫn là một lỗi và điều này vẫn được khắc phục kể từ iOS 12.0.
Sam Soffes

Vẫn là một lỗi trong iOS 12.1
Cesare

Kẻ không thực, không thực.
Mat

8

Bạn không renderingModethể đặt từ storyboardhoặc xib. Nó có thể truy cập theo chương trình.

Ví dụ:

UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

3
Tôi nghĩ, bạn đã mắc những lỗi chính tả nhỏ trong mã của mình. Dòng thứ hai nênUIImage *selectedImage = [unSeletedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Artem Stepanenko

8

Đặt tintColor & Class trong Storyboard.

//
//  TintColoredImageView.swift
//  TintColoredImageView
//
//  Created by Dmitry Utmanov on 14/07/16.
//  Copyright © 2016 Dmitry Utmanov. All rights reserved.
//

import UIKit

@IBDesignable class TintColoredImageView: UIImageView {

    override var image: UIImage? {
        didSet {
            let _tintColor = self.tintColor
            self.tintColor = nil
            self.tintColor = _tintColor
        }
    }


    override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialize()
    }

    override init(image: UIImage?) {
        super.init(image: image)
        initialize()
    }

    override init(image: UIImage?, highlightedImage: UIImage?) {
        super.init(image: image, highlightedImage: highlightedImage)
        initialize()
    }

    func initialize() {
        let _tintColor = self.tintColor
        self.tintColor = nil
        self.tintColor = _tintColor
    }

}

Đây là câu trả lời duy nhất phù hợp với tốc độ nhanh mới. Cảm ơn bạn.
Simon Moshenko

Không phù hợp với tôi vì một số lý do kỳ lạ ... Nó có phải cập nhật màu trong bảng phân cảnh không?
Cesare

4

Nó rất dễ sửa chữa

Chỉ cần tạo UIImageViewPDF lớp và sử dụng nó trong bảng phân cảnh của bạn

IB_DESIGNABLE
@interface UIImageViewPDF : UIImageView

@end

@implementation UIImageViewPDF

- (void) didMoveToSuperview
{
    [super didMoveToSuperview];
    self.image = [self.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    id color = self.tintColor;
    self.tintColor = color;
}

@end

3

Một giải pháp khác là tạo một UIImageViewlớp con:

final class TemplateImageView: UIImageView {
    override func awakeFromNib() {
        super.awakeFromNib()
        guard let oldImage = image else { return }
        image = nil
        image = oldImage.withRenderingMode(.alwaysTemplate)
    }
}

Sau đó, chỉ cần đặt lớp trong Trình tạo giao diện thành TemplateImageView.


giải pháp tốt nhất !!
Irshad Mohamed

2

Cách đơn giản để thiết lập từ Storyboard:

@IBDesignable
public class CustomImageView: UIImageView {
    @IBInspectable var alwaysTemplate: Bool = false {
        didSet {
            if alwaysTemplate {
                self.image = self.image?.withRenderingMode(.alwaysTemplate)
            } else {
                self.image = self.image?.withRenderingMode(.alwaysOriginal)
            }

        }
    }
}

Hoạt động tốt trên iOS 10 và Swift 3


1

Trong iOS 9, thiết lập thuộc tintColortính trong Trình tạo giao diện vẫn còn lỗi.

Lưu ý rằng một giải pháp hiệu quả bên cạnh việc viết các dòng sửa đổi trực tiếp ImageViewthuộc tính là đặt Render As: Template Image trong danh mục tài sản và gọi ví dụ:

[[UIImageView appearanceWhenContainedInInstancesOfClasses:@[[MyView class]]] setTintColor:[UIColor whiteColor]];

1

Tôi đã khắc phục sự cố này bằng cách thêm thuộc tính thời gian chạy tintColortrong trình tạo giao diện.

LƯU Ý: Bạn vẫn cần đặt hình ảnh của mình được hiển thị dưới dạng hình ảnh mẫu trong tệp Images.xcassets của bạn.

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


0

Nếu bạn tạo một IBOutlet, bạn có thể thay đổi nó trong phương thứcakenFromNib của mình như vậy ...

self.myImageView.image = [self.myImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Mặc dù câu trả lời của @ Moby đúng hơn - câu trả lời này có thể ngắn gọn hơn.


1
Câu hỏi là làm thế nào để thực hiện điều này trong bảng phân cảnh (hoặc xib), không phải trong mã.
Artem Stepanenko

@artem - vâng, xin lỗi, tôi không có ý suy luận rằng tôi đã có câu trả lời cho câu hỏi của bạn. Chỉ đơn thuần là chỉ ra một cách đơn giản để đối phó với điều này thông qua một IBOutlet
amergin

0

Thật điên rồ, lỗi này vẫn còn trong iOS 12.1! Đối với bảng phân cảnh / xibs: Thêm thẻ vào UIImageView có thể là một giải pháp nhanh chóng.

Swift 4.2

view.viewWithTag(1)?.tintColorDidChange()

0
extension UIImageView {

   @IBInspectable var renderModeTemplate : Bool {
       get{
           return image?.renderingMode == .alwaysTemplate
       }

       set{
          image = image?.withRenderingMode(newValue ? .alwaysTemplate:.alwaysOriginal)
       }
   }
}

Trong bảng phân cảnh, chọn UIImageView và chọn trình kiểm tra, đặt thuộc tính renderModeTemplate= On Trong bảng phân cảnh

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.