UITableViewCell中的CALayer阴影绘制不正确

时间:2016-07-27 21:53:29

标签: ios objective-c uitableview calayer

我正在使用CALayer将阴影应用于UITableViewCell。

这是我的代码:

- (void)addShadowToView:(UIView *)view
{
    // shadow
    view.layer.shadowColor = [[UIColor colorWithWhite:0.0f alpha:0.1f] CGColor];
    view.layer.shadowOpacity = 1.0f;
    view.layer.shadowOffset = CGSizeMake(0.0f, 3.0f);
    view.layer.shadowRadius = 6.0f;

    CGRect shadowFrame = view.layer.bounds;
    CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
    view.layer.shadowPath = shadowPath;
}

问题是对于某些tableviewcells,阴影不会跨越单元格的整个宽度。对于某些细胞来说,这是正确的,对于其他细胞则是错误的。我注意到设备的旋转也会影响它,重新加载tableview数据有时会解决它。

缓解此问题的最佳方法是什么(并且我并不是要在每次轮换时重新加载整个tableview等。)

正确应用阴影的单元格底部示例: enter image description here

向下滚动后同一个tableview中的单元格底部(阴影仅应用于宽度的前75%): enter image description here

编辑:我注意到问题是由这些代码行引起的:

CGRect shadowFrame = view.layer.bounds;
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
view.layer.shadowPath = shadowPath;

如果我把它们抛弃,一切都很好。但是我被告知使用它时会有一些性能上的好处。不知何故,旋转后阴影未正确应用于新尺寸。

4 个答案:

答案 0 :(得分:5)

您可以为自己的小区框架覆盖设置器并致电addShadowToView:。您可以通过存储单元格的大小来更好地优化它,并且仅在大小更改时更新阴影路径,例如:

@property (nonatomic, assign) CGSize size;

- (void) setFrame:(CGRect)frame
{
    [super setFrame:frame];
    // Need to check make sure this subview has been initialized
    if(self.subviewThatNeedsShadow != nil && !CGSizeEqualToSize(self.size,_frame.size)
    {
        [self addShadowToView: self.subviewThatNeedsShadow];
    }
}

答案 1 :(得分:1)

最简单的解决方案是将阴影添加到UITableViewCell的 contentView (相对于单元格的支持视图的图层)。由于单元格的边界在滚动时发生变化,如果将阴影添加到根视图,则必须在每个滚动事件上更新阴影的路径,这将是昂贵且不必要的。

你肯定是正确的:但是没有明确设置shadowPath会影响性能。如果您在单元格中没有任何动画内容,我还建议对其进行栅格化以进一步提高性能。

编辑:您还必须确保在设置阴影路径时,contentView的边界处于“最终”位置。 如果稍后修改了单元格的大小,这将导致contentView的边界发生变化,从而导致阴影路径不正确。解决方法是更新UITableViewCell中的路径 - layoutSubviews 方法。

答案 2 :(得分:0)

这里关注的不是父视图框架,您在这里工作的关注点是它的子图层及其大小,在布局更改时应该更改它。您可以覆盖以下方法,这将有助于您在布局更改时设置正确的框架。

public override void LayoutSublayersOfLayer(CALayer layer)
{

     base.LayoutSublayersOfLayer(layer);
     if (layer.Name == "gradient")
     {
          layer.Frame = view.Layer.Frame;
     }
} 

在上面的代码view中,您添加了sublayer。如果您在同一视图中使用多个图层,则可以使用标识符name属性处理特定图层。

答案 3 :(得分:0)

感谢@beyowulf 的回答给了我覆盖 UIView 框架获取和设置的线索

就我而言,我想让子类 tableView 单元格中的另一个子视图使用阴影棒。

Swift 5

// TargetView old size
var lastSize: CGSize = .zero

// Override frame in subclass tableView cell
override var frame: CGRect {
    get {
       super.frame
    }
    set {
       super.frame = newValue
       if targetView != nil {
           // Compared targetView size with old one.
          if lastSize != targetView.frame.size {
              
             /* Update the other subview's shadow path or layer frame here */
              
             lastSize = targetView.frame.size
         }
      }
   }
}

它对我有用。