【大前端】【iOS】iOS 使用 Objective-C 绘制几大常见布局(UIKit / Core Graphics 实战)


iOS 使用 Objective-C 绘制几大常见布局(UIKit / Core Graphics 实战)

在 iOS 开发中,大多数 UI 都是通过 AutoLayout、Frame 或 SwiftUI 构建的。但在一些性能敏感高度定制化 的场景(如图表、卡片背景、占位骨架、营销组件)中,直接绘制 UI 反而更高效、可控。

本文将系统讲解:
如何使用 Objective-C 手动绘制常见布局
每种布局的适用场景 + 完整示例代码


一、为什么还要用"绘制布局"?

适合使用绘制的场景

  • 📊 图表 / 统计视图(折线图、柱状图)

  • 🧩 高度定制化卡片背景

  • ⚡ 列表性能优化(减少 View 层级)

  • 🦴 Skeleton 骨架屏

  • 🎨 渐变 / 圆角 / 不规则形状

不适合的场景

  • 表单类 UI

  • 强交互控件(按钮 / 输入框)

  • 动态约束频繁变化的页面


二、基础知识:drawRect 与 Core Graphics

1️⃣ 自定义 View

复制代码
@interface CustomLayoutView : UIView
@end

@implementation CustomLayoutView

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    CGContextRef ctx = UIGraphicsGetCurrentContext();
}
@end

⚠️ drawRect: 由系统调用,不要手动调用

通过 setNeedsDisplay 触发重绘


三、常见布局一:矩形卡片布局(最常见)

适用场景

  • 首页卡片

  • 营销 Banner

  • 模块背景

示例效果

  • 圆角矩形

  • 阴影 / 描边

绘制代码

复制代码
- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGRect cardRect = CGRectInset(rect, 16, 16);
    UIBezierPath *path =
        [UIBezierPath bezierPathWithRoundedRect:cardRect
                                    cornerRadius:12];

    [[UIColor whiteColor] setFill];
    [path fill];

    [[UIColor lightGrayColor] setStroke];
    path.lineWidth = 1;
    [path stroke];
}

优点

  • 无子 View

  • 性能极高

  • 样式统一


四、常见布局二:九宫格布局(Grid)

适用场景

  • 功能入口

  • 九宫格菜单

  • 轻量展示页

绘制思路

  • 计算行 / 列

  • 循环绘制 cell

  • 可点击:结合 touchesBegan

示例代码

复制代码
- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    int column = 3;
    CGFloat padding = 10;
    CGFloat itemW = (rect.size.width - padding * (column + 1)) / column;
    CGFloat itemH = itemW;

    for (int i = 0; i < 9; i++) {
        int row = i / column;
        int col = i % column;

        CGFloat x = padding + col * (itemW + padding);
        CGFloat y = padding + row * (itemH + padding);

        CGRect itemRect = CGRectMake(x, y, itemW, itemH);
        UIBezierPath *path =
            [UIBezierPath bezierPathWithRoundedRect:itemRect cornerRadius:8];

        [[UIColor colorWithWhite:0.95 alpha:1] setFill];
        [path fill];
    }
}

五、常见布局三:列表布局(模拟 Table)

适用场景

  • 骨架屏

  • 轻量列表占位

  • 加载态 UI

绘制代码

复制代码
- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGFloat itemH = 60;
    int count = rect.size.height / itemH;

    for (int i = 0; i < count; i++) {
        CGRect rowRect = CGRectMake(16, i * itemH + 8,
                                    rect.size.width - 32, 44);

        UIBezierPath *path =
            [UIBezierPath bezierPathWithRoundedRect:rowRect cornerRadius:6];

        [[UIColor colorWithWhite:0.9 alpha:1] setFill];
        [path fill];
    }
}

📌 性能优势

UITableView + Skeleton View 更轻


六、常见布局四:分割线 & 虚线布局

普通分割线

复制代码
CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
CGContextSetLineWidth(ctx, 0.5);
CGContextMoveToPoint(ctx, 16, y);
CGContextAddLineToPoint(ctx, rect.size.width - 16, y);
CGContextStrokePath(ctx);

虚线

复制代码
CGFloat dash[] = {4, 2};
CGContextSetLineDash(ctx, 0, dash, 2);

七、常见布局五:不规则布局(气泡 / 标签)

适用场景

  • 聊天气泡

  • 标签角标

  • 引导浮层

示例:气泡背景

复制代码
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10, 0)];
[path addLineToPoint:CGPointMake(rect.size.width - 10, 0)];
[path addQuadCurveToPoint:CGPointMake(rect.size.width, 10)
             controlPoint:CGPointMake(rect.size.width, 0)];
// ... 省略
[path closePath];

八、交互怎么做?(重点)

绘制 View 默认没有子控件,交互需自己处理:

复制代码
- (void)touchesBegan:(NSSet<UITouch *> *)touches
           withEvent:(UIEvent *)event {

    CGPoint point = [[touches anyObject] locationInView:self];

    if (CGRectContainsPoint(self.itemRects[index], point)) {
        NSLog(@"点击了第 %d 个", index);
    }
}

九、性能与注意事项

✅ 优点

  • 极少 View 层级

  • 内存占用低

  • 滚动流畅

⚠️ 注意事项

  • 避免频繁 setNeedsDisplay

  • 复杂动画建议用 CAShapeLayer

  • 文本多时结合 CoreText


十、总结

布局类型 是否推荐绘制
卡片背景 ✅ 强烈推荐
骨架屏 ✅ 推荐
图表 ✅ 必须
表单 ❌ 不推荐
输入控件 ❌ 不推荐
相关推荐
invicinble2 小时前
对于使用html去进行前端开发的全面认识,以及过度到vue开发
前端·javascript·vue.js
我这一生如履薄冰~2 小时前
element-plus去除el-dropdown组件当鼠标移入文本时会出现边框
前端·elementui·vue
小果子^_^2 小时前
div或按钮鼠标经过或鼠标点击后效果样式
前端·css·计算机外设
han_2 小时前
前端性能优化之性能瓶颈点,Web 页面加载全流程解析
前端·javascript·性能优化
禅思院2 小时前
Vite 开发环境下实现 YAML 配置热更新方案
前端·vue.js·前端框架
C_心欲无痕2 小时前
vue3 - toRefs将响应式对象转换为普通对象
前端·javascript·vue.js
sun0077002 小时前
macvlan解决vlan路由冲突
前端·chrome
小oo呆2 小时前
【自然语言处理与大模型】LangChainV1.0入门指南:AgentState介绍
前端·javascript·easyui
weixin_462446232 小时前
Electron 禁止复制粘帖
前端·javascript·electron