【问题标题】:Use a CALayer to add a diagonal banner/badge to the corner of a UITableViewCell使用 CALayer 将对角横幅/徽章添加到 UITableViewCell 的角落
【发布时间】:2019-07-07 18:54:34
【问题描述】:

我正在尝试在我的表格视图中绘制装饰 UITableViewCell 的文本横幅,它看起来像一个图章,斜跨单元格的左上角。

我可能完全在错误的地方执行此操作,但我正在覆盖 -layoutSubviews 以添加图层。我尝试在-drawRect: 中执行此操作,但随着表格的呈现,横幅最终被表格视图的 imageView 覆盖(即图层位于图像视图下方,因为稍后添加了图像视图)。

我真的很难得到正确的数学。我计算过,假设横幅从单元格顶部 40 点和左侧 40 点开始,角度正好为 -45º,则斜边将为 56 点。所以我正在制作一个 56 点宽的 CALayer,然后将其旋转 -45º,这样就可以了。问题在于牢房内的位置……它坐落在牢房的外面,而不是硬靠在牢房的边缘。

我不是通过反复试验来把它放在正确的地方,有人可以帮我计算一下吗?显然我需要移动图层旋转它。

感觉 anchorPoint 是我在这里需要的,但这似乎实际上是在移动层,所以我一定错过了这一点(不是双关语)。

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.imageView.frame = CGRectMake(10, 10, 50, 50);

    if (self.hasBanner) {
        CALayer *banner = [CALayer layer];
        banner.backgroundColor = [UIColor colorWithRed:.5f green:.5f blue:.5f alpha:1.f].CGColor;
        banner.frame = CGRectMake(0, 40-15, 56, 15);
        banner.anchorPoint = CGPointMake(0, 1); // this just makes it worse
        banner.transform = CATransform3DMakeRotation(-45.0 / 180.0 * M_PI, 0.0, 0.0, 1.0);
        [self.layer addSublayer:banner];
    }
}

【问题讨论】:

    标签: iphone ios uitableview


    【解决方案1】:

    图层应该去哪里?

    让我们画一个图表:

    我们可以走得更远,做一些触发,但让我们停在这里。很明显,横幅的中顶点应该在(20,20)。我们可以告诉 Core Animation 这样做。

    定位图层

    从四个独立的步骤来考虑它:

    1. 设置图层大小
    2. 确定图层中的哪个点是方便的参考点
    3. 设置该参考点的位置
    4. 围绕参考点旋转图层

    这些对应于四个属性:boundsanchorPointpositiontransform

    您不想触及frame 属性,因为它的值派生自boundspositiontransformanchorPoint。如果您尝试设置frame,CALayer 将尝试反转transform,将其应用于您提供的矩形,然后设置boundsposition。这可能不会给出你想要的结果,所以你最好完全忽略它——这样就不会那么混乱了。

    (有关详细信息,请参阅Core Animation Guide,特别是Layer Objects Define Their Own Geometry 部分。)

    在代码中,我们将:

    1. bounds 设置为矩形0, 0, width, height。 (我故意将width 留给你——它必须超过 56 个。)
    2. anchorPoint 设置为点0.5, 0。换言之,沿图层宽度的一半,在图层的顶部。
    3. position 设置为点20, 20
    4. transform 设置为旋转45°。

    顺便说一句,在下面的代码中,我设置了affineTransform 而不是transform,只是因为它对于简单的二维转换更方便一些。

    何时设置图层

    你说得对,-drawRect: 是创建和添加图层的错误位置。该方法应该绘制到视图的内容中(它的CGContext),但什么都不做

    layoutSubviews 可以工作,但它会比您预期的更频繁地被调用,而且您不希望每次都创建和添加新层。

    看起来你只需要设置一次图层的几何图形,就再也不用碰它了。当您的hasBanner 属性发生更改时,为什么不直接创建或销毁该层?

    @interface MyTableViewCell ()
    
    @property (nonatomic) BOOL hasLayer;
    @property (nonatomic) CALayer* bannerLayer;
    
    @end
    
    - (void)setHasBanner:(BOOL)hasBanner
    {
        if (hasBanner != _hasBanner) {
            _hasBanner = hasBanner;
    
            if (hasBanner) {
                CALayer* banner = [CALayer layer];
                banner.backgroundColor = [UIColor colorWithRed:.5f green:.5f blue:.5f alpha:1.f].CGColor;
    
                banner.bounds = CGRectMake(0, 0, 56, 15);
                banner.anchorPoint = CGPointMake(0.5, 0);
                banner.position = CGPointMake(20, 20);
                banner.affineTransform = CGAffineTransformMakeRotation(-45.0 / 180.0 * M_PI);
    
                // Add the layer to the view, and remember it for later
                [self.layer addSublayer:banner];
                self.bannerLayer = banner;
            } else {
                // Remove the layer from the view, and discard it
                [self.bannerLayer removeFromSuperlayer];
                self.bannerLayer = nil;
            }
        }
    }
    

    【讨论】:

    • 在重新阅读您的问题时:我以为您没有指定横幅的确切位置,但您做到了。将做数学和编辑。
    • 谢谢...我仍在摆弄它以了解数学以找到正确的位置。这感觉像是一个基本操作,但横幅围绕中心点旋转的事实使其复杂化。如果它在左下角旋转,一切都会很容易。
    • 已编辑。我认为在这种情况下,中点是更自然的参考点。这有帮助吗?我在掩饰横幅应该有多宽的问题,但这至少应该让你更接近。
    • 如果我能给你两次投票,我会:) 非常感谢,你让我现在走上了正确的轨道。我可以做毕达哥拉斯,但没有完全得到与锚点有关的东西。像这样在纸上画出来真的很有帮助。还需要复习我的三角学,以获得更一般的几何知识(我已经从 Amazon Kindle 商店下载了 CK-12 书)。
    猜你喜欢
    • 1970-01-01
    • 2010-10-18
    • 2023-03-12
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多