Подтвердить что ты не робот

Как можно добавить тень к сгруппированному UITableView (как видно из официального приложения Twitter)?

У меня есть стандартное сгруппированное представление таблицы. Я хотел бы добавить тень вокруг него (т.е. Вокруг края каждого раздела таблицы) - если вы не уверены, что я имею в виду, то посмотрите пример официального приложения Twitter (ниже) для примера. Это довольно тонко, но это определенно тень, а не граница.

Twitter app

Как я могу достичь этого эффекта?

Сохранить для использования изображений со встроенными тенями в качестве фона каждой ячейки - что не позволит изменять размер анимированных ячеек, как мне нужно - я не понял способ.

4b9b3361

Ответ 1

Мне нужен этот эффект в одном из моих приложений на днях. Это очень легко достичь, просто используя свойства тени CALayer в сочетании с маской CALayer. Я собрал простой пример проекта в Github:

https://github.com/schluete/GroupedTableViewWithShadows

Эффект реализован в категории UITableViewCell UITableViewCell + CellShadows.m.

Первый шаг - создать теневой прямоугольник. Увеличьте прямоугольник в зависимости от положения ячейки в секции (сверху, середине, снизу), чтобы избежать округления скругленных углов в неправильных углах (строки 18-23). Затем добавьте тень в фоновый вид ячейки (строки 35-41).

Теперь есть хороший эффект тени, но тень первой ячейки "истекает кровью" во вторую ячейку. Чтобы предотвратить кровотечение, просто добавьте маску слоя, чтобы отрезать все ненужные части тени (строки 25-32 и 43-46). Что это, у нас есть тень!

Ответ 2

У меня есть два решения, которые могут помочь. Из-за закругленных углов, я думаю, вам придется применить эффект тени к ячейкам и поместить их так, чтобы тени не перекрывались по оси y. Так что...

Решение 1 (сложное решение): Это решение, которое, как я думаю, может работать, если вы анимируете cornerRadius или не уверены в точной форме раздела ячеек. Вы пытались использовать shadowPath, как предлагает Ecarrion, но применяя его к своей пользовательской ячейке UITableView? Представьте себе путь для центральных ячеек (не сверху и снизу), который немного шире, чем ячейка по оси x и короче по оси y.

Затем вы должны убедиться, что тень заливается сверху и снизу секции, не делая каждого отдельного перекрытия тени, правильно? Таким образом, для верхней и нижней ячеек вы увеличиваете shadowPath на оси y, скажем, на 4 балла больше. Затем вы настраиваете свойство shadowOffset для этих ячеек, а также на 4 очка по оси y. Если shadowOffset центральной ячейки (0,0), то верхняя ячейка равна (0, -4), а нижняя ячейка равна (0,4).

Если бы это был я, я бы поместил различные размеры и корректировки смещения в plist, чтобы я мог возиться с маленькими деталями без редактирования кода. Просто загрузите plist в словарь или пользовательский класс, а затем установите свои свойства, используя эти значения. Делает небольшие корректировки намного менее суетливыми.

EDIT: выйдя за рамки shadowPath, вы можете создать составную ячейку для таблицы с прозрачным фоновым слоем, немного меньшим теневым слоем, и тем не менее меньшим слоем для добавления текста и изображений. Теневой слой основан на слое текста/изображения, может быть, немного шире, выше, короче и т.д. Примените размытие к этому слою, а затем замаскируйте его прямоугольной маской, чтобы там, где заканчивается один теневой слой, начинается следующее. С верхним и нижним уровнями маска должна увеличиваться или уменьшаться до самой высокой/самой низкой точки на оси 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

Ответ 3

На самом деле вы можете попытаться использовать обычный режим tableView (не сгруппированный) и создать 2 (или более) типа ячеек с определенным идентификатором для каждого. Один для верхнего с тенью "верхний/левый/правый", один для последнего с тенью "левый/правый/нижний" и один для остальных ячеек с тенью "влево/вправо". В tableView: cellForRowAtIndexPath: просто проверьте, в какой строке вы находитесь (например, indexPath.row == 0) и верните соответствующую ячейку.

Ответ 4

Вы всегда можете установить 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

Ответ 5

Рискуя поставить старый вопрос, я чувствую, что ни один из ответов не привел к каким-либо достойным правилам кодирования, и они не "чисты и легки".

Я обнаружил гораздо более чистый подход к этому. Посмотрите, что вы думаете. Во-первых, вам потребуется подкласс 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:, что важно для следующего шага.

Теперь, в вашем UITableViewDataSource, в tableView: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];

вуаля! скрытые разделы