如何在分组的UITableView中添加阴影(如官方Twitter应用程序中所示)?

时间:2011-12-24 22:13:43

标签: iphone objective-c ios ipad uitableview

我有一个标准的分组表视图。我想在它周围添加一个阴影(即在每个tableview部分的边缘附近) - 如果你不确定我的意思,那么请参阅官方Twitter应用程序(如下)作为示例。它非常微妙,但绝对是一个阴影而不是边界。

Twitter app

我怎样才能达到这个效果?

使用内置阴影的图像作为每个单元格的背景进行保存 - 这将不允许像我需要的那样调整动画单元格大小 - 我还没想出办法。

5 个答案:

答案 0 :(得分:25)

我有两个可能有用的解决方案。由于圆角,我认为你必须将阴影效果应用于单元格,并定位它们,使阴影不会在y轴上重叠。所以......

解决方案1 ​​(复杂的解决方案): 这是我认为如果你动画cornerRadius可以工作的解决方案,或者不确定细胞部分的确切形状。您是否尝试过使用像Ecarrion建议的shadowPath,但是将它应用到您的自定义UITableView单元格?想象一下中心单元(不是顶部和底部)的路径,它比x轴上的单元略宽,而在y轴上更短。

然后你必须确保阴影投射在剖面的顶部和底部,而不会使每个阴影重叠,对吗?因此,对于顶部和底部单元格,您在y轴上使阴影路径更大,让我们说大4点。然后在y轴上调整这些单元格的shadowOffset属性,也可以调整4个点。如果中心单元格的shadowOffset为(0,0),则顶部单元格为(0,-4),底部单元格为(0,4)。

如果是我,我会将各种尺寸和偏移调整放在一个plist中,这样我就可以修改小细节而无需编辑代码。只需将plist加载到字典或自定义类中,然后使用这些值设置属性。使小调整变得不那么烦躁。

编辑:除了使用shadowPath之外,您还可以为tableview创建一个复合单元格,其透明背景图层的阴影层稍小,而且还有一个用于添加文本和图像的较小图层。阴影层基于文本/图像层,可能稍宽,更高,更短等。对该图层应用模糊,然后使用矩形蒙版对其进行遮罩,以便一个阴影层结束,下一个阴影层开始。对于顶层和底层,遮罩必须向上或向下延伸到阴影效果出现的y轴上的最高/最低点(您仍然需要遮住邻接下一个单元格的一侧)。这取决于你愿意在多大程度上达到一个确切的效果......也许这会给你一些更多的弹药。

解决方案2 (更简单的解决方案): 如果你确切知道cornerRadius在顶部和底部单元格上的位置,并且你不一定知道的是单元格的长度和/或宽度,你可以使用旧的“拉伸的单像素图​​形”技巧

首先,Photoshop / Gimp为角影提供图像。如果宽度始终相同,则此图像可以是整个单元格顶部的阴影。通过旋转,可以将相同的图像用于其他角落或单元格的底部。

现在的伎俩。拍摄用于角落阴影的1 x 5部分模糊或渐变效果。如果您的阴影效果为3像素,请将其设置为1x3等。导出为PNG或首选格式,并检查如果将其边缘对角图像的边缘无缝排列(模糊或渐变具有相同的颜色值,而不是一个可见的缝隙。)

所有单元格都以1x5图像作为图层内容,在单元格的可见部分(左侧和右侧)旁边获得一个图层。也可以是一个拉伸的UIImageView,你的选择。这些排列使左右阴影。

将角落阴影放在剖面中的第一个和最后一个单元格上 - 它们可以是不同的自定义单元格,或者您可以设计单元格,以便在创建时将其索引传递给它并适当地自行排列。对齐侧面阴影,使它们从角落阴影结束处开始,然后向下延伸到单元格的底部。如果你也在改变单元格的宽度,你会在两个角落图像之间做同样的事情,在x轴上拉伸渐变。

好吧,一张图片上写着千言万语,所以既然我似乎在推动那么多的话就是一张图片来说明:

stretching a 1px image for a scalable border or shadow effect

答案 1 :(得分:12)

前几天我在自己的应用程序中需要这个效果。通过将CALayer阴影属性与CALayer蒙版结合使用,实际上很容易实现。我在Github上编写了一个简单的示例项目:

https://github.com/schluete/GroupedTableViewWithShadows

效果在UITableViewCell类别UITableViewCell+CellShadows.m中实现。

第一步是创建一个阴影矩形。根据单元格在截面(顶部,中间,底部)中的位置放大矩形,以防止圆角在错误的角落中可见(第18-23行)。然后将阴影添加到单元格的背景视图中(第35-41行)。

现在有一个很好的阴影效果,但是第一个细胞的阴影“流血”到第二个细胞中。为防止出血,只需添加一个图层蒙版即可切除阴影中所有不必要的部分(第25-32行和第43-46行)。就是这样,我们有了我们的影子!

答案 2 :(得分:2)

实际上,您可以尝试使用普通模式tableView(未分组)并创建2种(或更多种)具有特定标识符的单元格。一个用于顶部/左/右阴影,一个用于最后一个具有左/右/底部阴影,一个用于具有左/右阴影的其他单元。在你的tableView:cellForRowAtIndexPath中:只检查你是哪一行(例如indexPath.row == 0)并返回正确的单元格。

答案 3 :(得分:0)

冒着提出旧问题的风险,我觉得所提供的答案都没有带来任何体面的编码实践,也不是“干净和容易”。

我发现了一个更清洁的方法。看看你的想法。首先,您需要继承UITableViewCell。然后,在标题或其他地方,制作三个单独的定义(例如):

#define TOP_CELL 0
#define MIDDLE_CELL 1
#define BOTTOM_CELL 2

现在,覆盖layoutSubviews:方法并执行以下操作:

-(void) layoutSubviews {
    [super layoutSubviews];

    if([self tag] == BOTTOM_CELL) {

         self.layer.masksToBounds = NO;
         self.layer.shadowOffset = CGSizeMake(-10, 15);
         self.layer.shadowRadius = 5;
         self.layer.shadowOpacity = 0.5;
    }
    //else if middle_cell (Different shadowing)
    //else if top_cell (Different shadowing)
}

注意:我不确定layoutSubviews方法是否适合执行此操作,我只知道它在dequeueReusableCellWithIdentifier:之后被调用,这对下一步非常重要。

现在,在UITableViewDataSourcetableView:cellForRowAtIndexPath:

CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:ident];

if(indexPath.row == 0)
    [cell setTag:TOP_CELL];
else if(indexPath.row == (NUMBER_OF_ROWS - 1))
    [cell setTag:BOTTOM_CELL];
else
    [cell setTag: MIDDLE_CELL];

瞧!阴影部分

答案 4 :(得分:-1)

您可以随时设置ShadowPath:

myView.layer.shadowOpacity = 0.8;
myView.layer.shadowRadius = 5.0;
myView.layer.shadowOffset = CGSizeZero;
myView.layer.shadowPath = [UIBezierPath bezierPathWithRect:myView.layer.bounds].CGPath;

请注意,这需要QuartzCore或CoreGraphics,记不太清楚。

在本文中,有很多阴影路径:http://nachbaur.com/blog/fun-shadow-effects-using-custom-calayer-shadowpaths