You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS:如何使用Core Graphics实现可切片图像混合

用Core Graphics混合可切片框架图与背景图的实现方案

嘿,这个需求我之前做UI自定义的时候刚好碰到过,用Core Graphics完全能搞定,核心就是不能直接把两张图整张混合——那样会破坏可切片图像的9宫格结构,得按切片区域拆分处理,再重新拼接。下面给你详细说下实现思路和代码:

核心思路

可切片图像(比如常见的气泡、按钮背景)本质是遵循9宫格规则:4个角保持固定大小不拉伸,4条边只沿单一方向拉伸,中间区域可以自由拉伸。要保持混合后的图像仍可切片,就必须对两张图的对应9宫格区域分别混合,再把这些混合后的区域拼接成最终图像。

具体实现步骤

  • 第一步:确定切片参数
    先拿到框架图的UIEdgeInsets(也就是上、下、左、右的固定边距,比如框架图的左上角10pt区域是固定角,那edgeInsets就是UIEdgeInsets(top:10, left:10, bottom:10, right:10))。背景图如果也是可切片的,建议用相同的insets;如果不是,就按框架图的insets来划分区域。
  • 第二步:创建绘制上下文
    用UIGraphicsBeginImageContextWithOptions创建和最终图像尺寸一致的上下文,记得设置scale为屏幕scale,避免生成模糊的图像。
  • 第三步:按9宫格区域逐一混合绘制
    对每个区域,先绘制背景图的对应部分,再通过Core Graphics的混合模式绘制框架图的对应部分。混合模式可以根据需求选择(比如正常叠加、颜色相乘、提亮等)。
  • 第四步:提取并清理
    从上下文里取出最终图像,然后关闭上下文,避免内存泄漏。

Swift示例代码

func blendSlicableFrame(with backgroundImage: UIImage, frameImage: UIImage, edgeInsets: UIEdgeInsets) -> UIImage? {
    // 确定最终图像尺寸,这里假设背景图和框架图尺寸一致,可按需调整
    let finalSize = backgroundImage.size
    // 创建上下文,false表示透明背景,scale用屏幕scale保证清晰度
    UIGraphicsBeginImageContextWithOptions(finalSize, false, UIScreen.main.scale)
    // 确保上下文一定会被清理
    defer { UIGraphicsEndImageContext() }
    
    guard let context = UIGraphicsGetCurrentContext() else { return nil }
    
    // 定义9宫格的所有区域
    let topLeft = CGRect(x: 0, y: 0, width: edgeInsets.left, height: edgeInsets.top)
    let topMiddle = CGRect(x: edgeInsets.left, y: 0, width: finalSize.width - edgeInsets.left - edgeInsets.right, height: edgeInsets.top)
    let topRight = CGRect(x: finalSize.width - edgeInsets.right, y: 0, width: edgeInsets.right, height: edgeInsets.top)
    
    let leftMiddle = CGRect(x: 0, y: edgeInsets.top, width: edgeInsets.left, height: finalSize.height - edgeInsets.top - edgeInsets.bottom)
    let center = CGRect(x: edgeInsets.left, y: edgeInsets.top, width: finalSize.width - edgeInsets.left - edgeInsets.right, height: finalSize.height - edgeInsets.top - edgeInsets.bottom)
    let rightMiddle = CGRect(x: finalSize.width - edgeInsets.right, y: edgeInsets.top, width: edgeInsets.right, height: finalSize.height - edgeInsets.top - edgeInsets.bottom)
    
    let bottomLeft = CGRect(x: 0, y: finalSize.height - edgeInsets.bottom, width: edgeInsets.left, height: edgeInsets.bottom)
    let bottomMiddle = CGRect(x: edgeInsets.left, y: finalSize.height - edgeInsets.bottom, width: finalSize.width - edgeInsets.left - edgeInsets.right, height: edgeInsets.bottom)
    let bottomRight = CGRect(x: finalSize.width - edgeInsets.right, y: finalSize.height - edgeInsets.bottom, width: edgeInsets.right, height: edgeInsets.bottom)
    
    let allRegions = [topLeft, topMiddle, topRight, leftMiddle, center, rightMiddle, bottomLeft, bottomMiddle, bottomRight]
    
    for region in allRegions {
        // 先绘制背景图的当前区域
        backgroundImage.draw(in: region)
        // 设置混合模式,这里用正常叠加,可替换为.multiply/.overlay等
        context.setBlendMode(.normal)
        // 绘制框架图的当前区域
        frameImage.draw(in: region)
    }
    
    // 从上下文提取最终图像
    return UIGraphicsGetImageFromCurrentImageContext()
}

关键注意事项

  • 尺寸适配:如果背景图和框架图尺寸不同,先把背景图缩放到框架图的尺寸,或者按比例调整区域大小,确保每个9宫格区域对应准确。
  • 混合模式选择:Core Graphics提供了十几种混合模式,比如kCGBlendModeMultiply会让颜色叠加变暗,kCGBlendModeScreen会提亮颜色,你可以根据视觉需求测试调整。
  • 性能优化:如果这个混合操作会频繁调用(比如列表里的每个cell都要生成),建议缓存混合后的图像,避免重复绘制消耗性能。
  • 切片规则一致性:混合后的图像仍可按原框架图的edgeInsets进行切片,只要你保持了每个区域的对应关系。

内容的提问来源于stack exchange,提问作者Daumantas Versockas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:41:45