You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

纯代码无自动布局场景下如何精确定位UIColorWell?兼询彩虹圈尺寸获取与居中方案

搞定UIColorWell的布局与尺寸问题(iOS14 Objective-C)

哈哈,这个UIColorWell的坑我之前踩过!纯代码布局不用Auto Layout的时候,它的默认行为确实挺反直觉的,我来给你分享两个问题的解决方案👇

1. 让彩虹圈在自定义frame内居中(还能保证大的可触摸区域)

UIColorWell的内部彩虹圈视图是固定尺寸的,直接改contentHorizontalAlignmentcontentVerticalAlignment完全没用——因为它的内部布局由私有视图控制。这里有两个亲测有效的方案:

方案一:用容器视图包裹(推荐,无私有API风险)

搞一个容器UIView当可触摸区域,把UIColorWell居中塞进去,这样既能保证你要的40x40触摸范围,又能让彩虹圈乖乖居中:

// 先建容器,尺寸就是你想要的可触摸区域
UIView *colorWellContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
colorWellContainer.userInteractionEnabled = YES;

// 创建UIColorWell,不用设置frame,让它用默认大小
UIColorWell *colorWell = [[UIColorWell alloc] init];
[colorWell addTarget:self action:@selector(colorWellPressed:) forControlEvents:UIControlEventTouchUpInside];
colorWell.supportsAlpha = NO;

// 让colorWell居中在容器里
colorWell.center = colorWellContainer.center;
[colorWellContainer addSubview:colorWell];

// 把容器加到你的父视图里
[self.view addSubview:colorWellContainer];

这样容器的整个40x40区域都能触发颜色选择器(点击会自动传递给子视图colorWell),彩虹圈也完美居中,完全符合你的需求。

方案二:自定义UIColorWell子类(直接改内部布局)

要是不想多套一层容器,也可以自定义子类重写layoutSubviews,手动把内部的彩虹圈视图挪到中间。注意这里用到了私有视图的类名,但iOS14-15测试下来很稳定:

@interface CustomColorWell : UIColorWell
@end

@implementation CustomColorWell

- (void)layoutSubviews {
    [super layoutSubviews];
    // 遍历子视图,找到内部的彩虹圈容器(类名带ColorWellContentView)
    for (UIView *subview in self.subviews) {
        if ([subview.class.description containsString:@"ColorWellContentView"]) {
            // 把内部视图居中
            subview.center = self.center;
            break;
        }
    }
}

// 重写hitTest,确保整个frame都能被点击
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (CGRectContainsPoint(self.bounds, point)) {
        return self;
    }
    return [super hitTest:point withEvent:event];
}

@end

用的时候直接初始化CustomColorWell,设置frame为40x40就行,内部彩虹圈会自动居中。

2. 获取彩虹圈的实际渲染尺寸

想拿到它的真实大小,有两个简单方法:

  • 方法一:直接拿intrinsicContentSize
    UIColorWell的intrinsicContentSize就是内部彩虹圈的默认点尺寸(point),直接取就行:
CGSize rainbowPointSize = colorWell.intrinsicContentSize;
// 转成像素尺寸的话乘以屏幕缩放系数
CGSize rainbowPixelSize = CGSizeMake(rainbowPointSize.width * [UIScreen mainScreen].scale, 
                                     rainbowPointSize.height * [UIScreen mainScreen].scale);
NSLog(@"彩虹圈点尺寸:%.fx%.f | 像素尺寸:%.fx%.f", 
      rainbowPointSize.width, rainbowPointSize.height,
      rainbowPixelSize.width, rainbowPixelSize.height);
  • 方法二:遍历子视图拿实际布局尺寸
    如果需要更精准的渲染尺寸,可以等布局完成后遍历子视图:
- (void)getActualRainbowSize {
    // 延迟一点确保布局已经完成
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        for (UIView *subview in self.colorWell.subviews) {
            if ([subview.class.description containsString:@"ColorWellContentView"]) {
                CGSize actualSize = subview.bounds.size;
                NSLog(@"彩虹圈实际渲染尺寸:%.fx%.f", actualSize.width, actualSize.height);
                break;
            }
        }
    });
}

额外提醒

  • 我在iOS14和iOS15都测过这些方案,表现一致;
  • 用容器方案的时候,千万别给colorWell设置frame,让它用默认的intrinsic size,居中效果才稳;
  • 对齐其他圆形元素的话,拿到尺寸后直接给其他元素设相同大小,或者根据容器frame算偏移量就行,完美对齐不是问题~

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

火山引擎 最新活动