Làm cách nào để che một UIImageView?


100

Tôi đang cố che một hình ảnh bằng một thứ như thế này:

hình ảnh bị che

bạn có thể làm ơn giúp toi được không?

Tôi đang sử dụng mã này:

- (void) viewDidLoad {
    UIImage *OrigImage = [UIImage imageNamed:@"dogs.png"];
    UIImage *mask = [UIImage imageNamed:@"mask.png"];
    UIImage *maskedImage = [self maskImage:OrigImage withMask:mask];
    myUIIMage.image = maskedImage;
}

27
Tôi là người đã viết hướng dẫn ban đầu. Hình ảnh mặt nạ chỉ là một hình ảnh thang độ xám đơn giản mà tôi đã tạo bằng photoshop. Không có gì đặc biệt về nó. Vùng đen trở thành phần "trong suốt" của mặt nạ. Hãy nhớ rằng bất kỳ bóng nào của màu xám đều được hiểu là một mức độ mờ. Theo cách này, mặt nạ cũng có thể là gradient rất hữu ích để tạo đường viền mềm mại xung quanh mặt nạ.
ra9r

Cái này phải có cùng kích thước, phải không?
KarenAnne

mã siêu thanh lịch, cảm ơn. chỉ là một liên kết hữu ích nếu có ai cần để cắt một hình ảnh trước mặt nạ ... stackoverflow.com/questions/17712797/...
Fattie

Bất kỳ ý tưởng nào về điều này .. stackoverflow.com/questions/28122370/…
Milan patel,

1
Tôi mong bạn vui lòng thay đổi câu trả lời đã chọn thành câu trả lời có số phiếu ủng hộ gần gấp 3 lần. Theo tôi thì tốt hơn về mọi mặt.
Albert Renshaw

Câu trả lời:


163

Có một cách dễ dàng hơn.

#import <QuartzCore/QuartzCore.h>
// remember to include Framework as well

CALayer *mask = [CALayer layer];
mask.contents = (id)[[UIImage imageNamed:@"mask.png"] CGImage];
mask.frame = CGRectMake(0, 0, <img_width>, <img_height>);
yourImageView.layer.mask = mask;
yourImageView.layer.masksToBounds = YES;

Đối với Swift 4 và cộng, hãy làm theo mã bên dưới

let mask = CALayer()
mask.contents =  [ UIImage(named: "right_challenge_bg")?.cgImage] as Any
mask.frame = CGRect(x: 0, y: 0, width: leftBGImage.frame.size.width, height: leftBGImage.frame.size.height)
leftBGImage.layer.mask = mask
leftBGImage.layer.masksToBounds = true

1
cảm ơn bạn nhưng tôi đã đặt mã này viewDidLoadnhưng không có gì xảy ra!
Mc.Lover

6
Bạn nên đặt thuộc tính lớp để sử dụng mặt nạ, tức là [yourImageView.layer setMasksToBounds: YES];
Wolfgang Schreurs

3
Lưu ý rằng đây là cần thiết để trở thành UIImageView cho giải pháp này. Giải pháp khác chỉ hoạt động với UIImage.
adriendenat

1
Tôi đã thử cách tiếp cận này nhưng cách này dường như không hoạt động trong iOS 8
bdv 12/12/14

2
Đối với mã Swift, khi đặt trong mask.contents, nên CGImage. Không phải [CGImage]. Nếu sử dụng dấu ngoặc [], nó có nghĩa là Mảng.
strawnut

59

Hướng dẫn sử dụng phương thức này với hai tham số: imagemaskImage, những tham số này bạn phải đặt khi gọi phương thức. Một cuộc gọi ví dụ có thể trông như thế này, giả sử phương thức nằm trong cùng một lớp và các ảnh nằm trong gói của bạn:

Lưu ý - đáng kinh ngạc là các hình ảnh thậm chí không cần phải có cùng kích thước.

...
UIImage *image = [UIImage imageNamed:@"dogs.png"];
UIImage *mask = [UIImage imageNamed:@"mask.png"];

// result of the masking method
UIImage *maskedImage = [self maskImage:image withMask:mask];

...

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {

    CGImageRef maskRef = maskImage.CGImage; 

    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef), NULL, false);

    CGImageRef maskedImageRef = CGImageCreateWithMask([image CGImage], mask);
    UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];

    CGImageRelease(mask);
    CGImageRelease(maskedImageRef);

    // returns new image with mask applied
    return maskedImage;
}

Sau khi bạn cung cấp mã của mình, tôi đã thêm một số con số dưới dạng nhận xét vào nó để tham khảo. Bạn vẫn có hai lựa chọn. Toàn bộ điều này là một phương pháp, mà bạn đang gọi ở đâu đó. Bạn không cần phải tạo các hình ảnh bên trong nó: điều này làm giảm khả năng tái sử dụng của phương pháp xuống 0.

Để mã của bạn hoạt động. Thay đổi đầu phương thức ( 1. ) thành

- (UIImage *)maskImageMyImages {

Sau đó, thay đổi tên của biến trong 2. thành

UIImage *maskImage = [UIImage imageNamed:@"mask.png"];

Phương thức này sẽ trả về các hình ảnh bị che, vì vậy bạn sẽ phải gọi phương thức này ở một số nơi. Bạn có thể cho chúng tôi xem mã nơi bạn đang gọi phương thức của mình không?


lấy làm tiếc ! nơi nào nên viết UIImage *imagemã? !!! bởi vì trên -(UIimage *) maskeImagetrình biên dịch đưa ra lỗi định nghĩa lại!
Mc.Lover

xin lỗi bạn vui lòng tải lên mã mẫu cho tôi được không? Iam bối rối: -s
Mc.Lover

1
Không thể, mọi thứ đều có. Bạn sẽ phải cho chúng tôi biết cách bạn đang gọi phương thức này, hoặc ít nhất là phần mà bạn muốn che hình ảnh của mình và hiển thị kết quả.
Nick Weaver

vấn đề của tôi là để gọi nó, nó phải là một cái gì đó như thế này ?? (viewDidLoad): xem mã đã chỉnh sửa của tôi
Mc.Lover

Bất kỳ ý tưởng nào về Reverse masking. (Đảo ngược quá trình trên) Có nghĩa là tôi muốn xóa vùng tô màu (làm cho nó trong suốt) và vùng trong suốt có tô màu.
Milan patel

16

Swift 3 - Giải pháp đơn giản nhất mà tôi tìm thấy

Tôi đã tạo một @IBDesignablecho điều này để bạn có thể thấy hiệu ứng ngay lập tức trên bảng phân cảnh của mình.

import UIKit

@IBDesignable
class UIImageViewWithMask: UIImageView {
    var maskImageView = UIImageView()

    @IBInspectable
    var maskImage: UIImage? {
        didSet {
            maskImageView.image = maskImage
            updateView()
        }
    }

    // This updates mask size when changing device orientation (portrait/landscape)
    override func layoutSubviews() {
        super.layoutSubviews()
        updateView()
    }

    func updateView() {
        if maskImageView.image != nil {
            maskImageView.frame = bounds
            mask = maskImageView
        }
    }
} 

Cách sử dụng

  1. Tạo một tệp mới và dán mã đó ở trên.
  2. Thêm UIImageView vào bảng phân cảnh của bạn (chỉ định hình ảnh nếu bạn muốn).
  3. Trên Trình kiểm tra danh tính: Thay đổi lớp tùy chỉnh thành "UIImageViewWithMask" (tên lớp tùy chỉnh ở trên).
  4. Trên Trình kiểm tra thuộc tính: Chọn hình ảnh mặt nạ bạn muốn sử dụng.

Thí dụ

Tạo mặt nạ trên Bảng phân cảnh

Ghi chú

  • Hình ảnh mặt nạ của bạn phải có nền trong suốt (PNG) cho phần không phải màu đen.

12

Tôi đã thử cả hai mã bằng CALayer hoặc CGImageCreateWithMask nhưng không có mã nào trong số chúng không hoạt động với tôi

Nhưng tôi phát hiện ra rằng vấn đề là ở định dạng tệp png, KHÔNG phải mã !!
vì vậy chỉ để chia sẻ phát hiện của tôi!

Nếu bạn muốn sử dụng

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage

bạn phải sử dụng png 24 bit không có kênh alpha

Nếu bạn muốn sử dụng mặt nạ CALayer, bạn phải sử dụng png (24 bit hoặc 8 bit) với kênh alpha trong đó phần trong suốt của png sẽ che hình ảnh (đối với mặt nạ alpha gradient mịn .. sử dụng png 24 bit với kênh alpha)


10
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

        CGImageRef maskImageRef = [maskImage CGImage];

        // create a bitmap graphics context the size of the image
        CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
        CGColorSpaceRelease(colorSpace);

        if (mainViewContentContext==NULL)
            return NULL;

        CGFloat ratio = 0;

        ratio = maskImage.size.width/ image.size.width;

        if(ratio * image.size.height < maskImage.size.height) {
            ratio = maskImage.size.height/ image.size.height;
        }

        CGRect rect1  = {{0, 0}, {maskImage.size.width, maskImage.size.height}};
        CGRect rect2  = {{-((image.size.width*ratio)-maskImage.size.width)/2 , -((image.size.height*ratio)-maskImage.size.height)/2}, {image.size.width*ratio, image.size.height*ratio}};


        CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
        CGContextDrawImage(mainViewContentContext, rect2, image.CGImage);


        // Create CGImageRef of the main view bitmap content, and then
        // release that bitmap context
        CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
        CGContextRelease(mainViewContentContext);

        UIImage *theImage = [UIImage imageWithCGImage:newImage];

        CGImageRelease(newImage);

        // return the image
        return theImage;
}

Điều này làm việc cho tôi.


cảm ơn bạn, câu trả lời này tốt hơn là câu trả lời của người khác về hiệu suất với nhiều hình ảnh hơn và lớn hơn.
Radu Ursache

1
Bất kỳ ý tưởng nào về mặt nạ đảo ngược. (Đảo ngược quá trình trên) Nghĩa là tôi muốn loại bỏ vùng tô màu (làm cho nó trong suốt) và vùng trong suốt có tô màu.
Tuần lễ Milan

Cảm ơn, mã này hoạt động tốt hơn đầu tiên !! Nhưng tôi có hai vấn đề: Cảnh báo trên "kCGImageAlphaPremultipliedLast" (tôi truyền sang "CGBitmapInfo" để khắc phục sự cố) VÀ không hoạt động đối với hình ảnh võng mạc !! bạn có thể giúp tôi không ?? ...
ngón tay vào

@Milanpatel Giải pháp đơn giản là chỉ cần đảo ngược màu sắc của bạn trong hình ảnh mặt nạ. :)
DIDS

@ZyiOS làm cách nào để tôi có thể tùy chỉnh khung của Hình ảnh bị che. tức là người dùng có thể tăng hoặc giảm kích thước của hình ảnh bị che.
Dalvik

8

SWIFT 3 XCODE 8.1

func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {

    let maskRef = maskImage.cgImage

    let mask = CGImage(
        maskWidth: maskRef!.width,
        height: maskRef!.height,
        bitsPerComponent: maskRef!.bitsPerComponent,
        bitsPerPixel: maskRef!.bitsPerPixel,
        bytesPerRow: maskRef!.bytesPerRow,
        provider: maskRef!.dataProvider!,
        decode: nil,
        shouldInterpolate: false)

    let masked = image.cgImage!.masking(mask!)
    let maskedImage = UIImage(cgImage: masked!)

    // No need to release. Core Foundation objects are automatically memory managed.

    return maskedImage

}

// để sử dụng

testImage.image = maskImage(image: UIImage(named: "OriginalImage")!, withMask: UIImage(named: "maskImage")!)

bạn có thể cho tôi những hình ảnh
Ahmed Safadi

3

Phiên bản Swift của giải pháp được chấp nhận:

func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {

    let maskRef = maskImage.CGImage

    let mask = CGImageMaskCreate(
        CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef),
        nil,
        false)

    let masked = CGImageCreateWithMask(image.CGImage, mask)
    let maskedImage = UIImage(CGImage: masked)!

    // No need to release. Core Foundation objects are automatically memory managed.

    return maskedImage

}

Đề phòng ai đó cần.

Nó làm việc cho tôi một cách hoàn hảo.


Bạn có phiên bản Swift 3.0 của cái này không?
Van Du Tran

2

chúng tôi nhận thấy, câu trả lời đúng đó hiện không hoạt động và đã triển khai lớp thả vào nhỏ, giúp che bất kỳ hình ảnh nào trong UIImageView.

Nó có sẵn tại đây: https://github.com/Werbary/WBMaskedImageView

Thí dụ:

WBMaskedImageView *imgView = [[WBMaskedImageView alloc] initWithFrame:frame];
imgView.originalImage = [UIImage imageNamed:@"original_image.png"];
imgView.maskImage = [UIImage imageNamed:@"mask_image.png"];

1
Tốt! Nó thực sự hữu ích.
abhimuralidharan
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.