30

我想在我的 IOS 应用程序中使用 9-patch 图像。可能吗?

4

4 回答 4

20

查看 UIImage 的方法resizableImageWithCapInsets:(UIEdgeInsets)capInsets

于 2012-07-12T08:21:47.937 回答
4

你可以试试这个简单的实现: https ://github.com/shiami/SWNinePatchImageFactory

这个概念很简单,描述如下:

该技术只是将 9-patch PNG 图像转换为 iOS 兼容、可调整大小的 UIImage 对象。有关更多信息,请参阅 UIImage 的方法 resizableImageWithCapInsets:(UIEdgeInsets)insets。所以它只支持在水平和垂直两侧拉伸一段补丁标记。

+ (UIImage*)createResizableImageFromNinePatchImage:(UIImage*)ninePatchImage
{
    NSArray* rgbaImage = [self getRGBAsFromImage:ninePatchImage atX:0 andY:0 count:ninePatchImage.size.width * ninePatchImage.size.height];
    NSArray* topBarRgba = [rgbaImage subarrayWithRange:NSMakeRange(1, ninePatchImage.size.width - 2)];
    NSMutableArray* leftBarRgba = [NSMutableArray arrayWithCapacity:0];
    int count = [rgbaImage count];
    for (int i = 0; i < count; i += ninePatchImage.size.width) {
        [leftBarRgba addObject:rgbaImage[i]];
    }

    int top = -1, left = -1, bottom = -1, right = -1;
    count = [topBarRgba count];
    for (int i = 0; i <= count - 1; i++) {
        NSArray* aColor = topBarRgba[i];
        if ([aColor[3] floatValue] == 1) {
            left = i;
            break;
        }
    }
    NSAssert(left != -1, @"The 9-patch PNG format is not correct.");
    for (int i = count - 1; i >= 0; i--) {
        NSArray* aColor = topBarRgba[i];
        if ([aColor[3] floatValue] == 1) {
            right = i;
            break;
        }
    }
    NSAssert(right != -1, @"The 9-patch PNG format is not correct.");
    for (int i = left + 1; i <= right - 1; i++) {
        NSArray* aColor = topBarRgba[i];
        if ([aColor[3] floatValue] < 1) {
            NSAssert(NO, @"The 9-patch PNG format is not support.");
        }
    }
    count = [leftBarRgba count];
    for (int i = 0; i <= count - 1; i++) {
        NSArray* aColor = leftBarRgba[i];
        if ([aColor[3] floatValue] == 1) {
            top = i;
            break;
        }
    }
    NSAssert(top != -1, @"The 9-patch PNG format is not correct.");
    for (int i = count - 1; i >= 0; i--) {
        NSArray* aColor = leftBarRgba[i];
        if ([aColor[3] floatValue] == 1) {
            bottom = i;
            break;
        }
    }
    NSAssert(bottom != -1, @"The 9-patch PNG format is not correct.");
    for (int i = top + 1; i <= bottom - 1; i++) {
        NSArray* aColor = leftBarRgba[i];
        if ([aColor[3] floatValue] == 0) {
            NSAssert(NO, @"The 9-patch PNG format is not support.");
        }
    }

    UIImage* cropImage = [ninePatchImage crop:CGRectMake(1, 1, ninePatchImage.size.width - 2, ninePatchImage.size.height - 2)];

    return [cropImage resizableImageWithCapInsets:UIEdgeInsetsMake(top, left, bottom, right)];
}

SWNinePatchImageView 还提供了 Nib 或 Storyboard 用法。您可以在 repo 中查看示例项目。

于 2014-07-10T15:59:39.600 回答
1

最可能的结果是 https://github.com/andylanddev/Tortuga22-NinePatch 9-patch 库已经使用了波纹管方法 resizableImageWithCapInsets:(UIEdgeInsets)insets

于 2014-03-19T02:18:39.030 回答
0

您可以使用图像裁剪和图像拉伸。

图像裁剪

       func crop(img: UIImage, with rect: CGRect) -> UIImage? {
            guard let cgImg = img.cgImage else { return nil }
            // Create bitmap image from context using the rect
            if let imageRef: CGImage = cgImg.cropping(to: rect){
                // Create a new image based on the imageRef and rotate back to the original orientation
                let image: UIImage = UIImage(cgImage: imageRef, scale: img.scale, orientation: img.imageOrientation)
                return image
            }
            else{
                return nil
            }
        }

图像拉伸

func stretch(image: UIImage, newWidth: CGFloat) -> UIImage? {
        guard image.size.width < newWidth else {
            return image
        }

        let originalWidth = image.size.width
        let offset: CGFloat = 1
        // crop left first
        let left = crop(img: image, with: CGRect(x: 0, y: 0, width: originalWidth/2, height: image.size.height))
        // crop right first
        let right = crop(img: image, with: CGRect(x: originalWidth/2, y: 0, width: originalWidth/2, height: image.size.height))

        UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: image.size.height),
                                               false, image.scale)

        let lhsResizable = left?.resizableImage(withCapInsets: UIEdgeInsets(top: 0,
                                                                                  left: originalWidth/2 - offset,
                                                                                  bottom: 0,
                                                                                  right: 0),
                                                  resizingMode: .stretch)
        // draw left stretched first
        lhsResizable?.draw(in: CGRect(x: 0, y: 0, width: newWidth/2, height: image.size.height))
        
        let rhsResizable = right?.resizableImage(withCapInsets: UIEdgeInsets(top: 0,
                                                                                  left: 0,
                                                                                  bottom: 0,
                                                                                  right: originalWidth/2 - offset),
                                                  resizingMode: .stretch)
        // then , draw right stretched
        rhsResizable?.draw(in: CGRect(x: newWidth/2, y: 0, width: newWidth/2, height: image.size.height))

        let fullImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return fullImage
    }

这是一个例子:

  • 原始图像:

礼物.9

0000

  • 处理后的图像

22233

  • 示例代码:

          view.backgroundColor = UIColor.white
          let imgViewWidth: CGFloat = 300
          let imgView = UIImageView(frame: CGRect(origin: CGPoint(x: 50, y: 250), size: CGSize(width: imgViewWidth, height: 100)))
          view.addSubview(imgView)
          if let image = UIImage(named: "gift.9"), let img = stretch(image: image, newWidth: imgViewWidth){
              imgView.image = img
          }
    
于 2022-01-18T19:26:22.593 回答