Ответ 1
Самый простой способ удалить все подслои с уровня - установить свойство подслоя на nil:
rootLayer.sublayers = nil;
У меня возникли проблемы с удалением всех подслоев уровня. В настоящее время я делаю это вручную, но это приводит к ненужным беспорядкам. Я нашел много тем об этом в google, но ответа нет.
Я попытался сделать что-то вроде этого:
for(CALayer *layer in rootLayer.sublayers) { [layer removeFromSublayer]; }
но это не сработало.
Кроме того, я попытался клонировать rootLayer.sublayers в отдельный NSArray, но результат был тот же.
Любые идеи?
Edit:
Я думал, что это работает сейчас, но я был неправ. Он отлично работает с CALayers, но он не работает с CATextLayers. Любые идеи?
Самый простой способ удалить все подслои с уровня - установить свойство подслоя на nil:
rootLayer.sublayers = nil;
Следующее должно работать:
for (CALayer *layer in [[rootLayer.sublayers copy] autorelease]) {
[layer removeFromSuperlayer];
}
[rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
Swift (короткая версия):
layer.sublayers?.forEach { $0.removeFromSuperlayer() }
Вызов rootLayer.sublayers = nil;
может привести к сбою (например, если под iOS 8 вы дважды вызываете removeFromSuperview на видении rootLayer
).
Правильный путь:
[[rootLayer.sublayers copy] makeObjectsPerformSelector:@selector(removeFromSuperlayer)]
Вызов copy
необходим для того, чтобы массив, на который removeFromSuperlayer
итеративно вызывается, не изменяется, в противном случае возникает исключение.
Как использовать обратное перечисление?
NSEnumerator *enumerator = [rootLayer.sublayers reverseObjectEnumerator];
for(CALayer *layer in enumerator) {
[layer removeFromSuperlayer];
}
Поскольку группа в подслоях изменяется во время перечисления, если порядок нормальный. Я хотел бы знать приведенный выше результат кода.
Без разборки все подслои вызывают неприятные сбои в iOS 7, что может произойти намного позже при выполнении программы. Я проверил это с помощью rootLayer.sublayers = nil
и [rootLayer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]
. Должен быть создан системный слой, который запутывается.
Вы должны сохранить свой собственный массив слоев и удалить их самостоятельно:
[myArrayOfLayersIAddedMyself makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
Я попытался удалить только первый подуровень с индексом 0, и это сработало:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cell.contentView.layer.sublayers count] != 0) {
[[cell.contentView.layer.sublayers objectAtIndex:0] removeFromSuperlayer];
}
Я должен был сделать это в Xamarin/С#. У меня был UITableViewCell
с некоторыми CAShapeLayers
для границ. Все вышеперечисленные опции (включая копирование массива, а затем удаление слоев вызвали сбой). Подход, который работал у меня:
При добавлении CALayer
я дал ему имя:
var border = new CALayer();
border.BackgroundColor = color.CGColor;
border.Frame = new CGRect(x, y, width, height);
border.Name = "borderLayerName";
Layer.AddSublayer(border);
В PrepareForReuse
на UITableViewCell
я создал копию свойства SubLayers
и удалил все, что соответствует имени, которое я назначил ранее:
CALayer[] copy = new CALayer[Layer.Sublayers.Length];
Layer.Sublayers.CopyTo(copy, 0);
copy.FirstOrDefault(l => l.Name == "borderLayerName")?.RemoveFromSuperLayer();
Без сбоев.
Надеюсь, это поможет!
Обе настройки self.view.layer.sublayers = nil
и [layer removeFromSuperlayer]
приведут к сбою, если UIView
содержит какое-либо подвью. Лучший способ удалить CALayer
из superLayer - это поддерживать массив слоев.
Например, этот массив является arrayOfLayers,
Каждый раз, когда вы добавляете слой на UIView.sublayer
, добавляете этот слой в этот массив
то есть.
[
arrayOfLayers addObject:layer];
[self.view.layer addSublayer:layer];
Удаляя только вызов,
[arrayOfLayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
Я столкнулся с той же проблемой и нашел много решений, но ни один из них не идеален.
Наконец, из выше ответа pnavk у меня появилась идея. Там код для пользователей Xamarin/С#.
Версия iOS может быть следующей:
Swift 2.3
if rootLayer.sublayers?.count > 0 {
rootLayer.sublayers?.forEach {
if $0.name == "bottomBorderLayer" {
$0.removeFromSuperlayer()
}
}
}
let border = CALayer()
let height = CGFloat(1.0)
border.borderColor = UIColor.blackColor().CGColor
border.borderWidth = height
border.frame = CGRectMake(0, self.frame.size.height - height, self.frame.size.width, self.frame.size.height)
border.name = "bottomBorderLayer"
rootLayer.addSublayer(border)
rootLayer.masksToBounds = true
Objective-C
if (rootLayer.sublayers.count > 0) {
for (CALayer *layer in rootLayer.sublayers) {
if ([layer.name isEqualToString:@"bottomBorderLayer"]) {
[layer removeFromSuperlayer];
}
}
}
CALayer *border = [[CALayer alloc] init];
CGFloat height = 1.0;
border.borderColor = [UIColor blackColor].CGColor;
border.borderWidth = height;
border.frame = CGRectMake(0, self.view.frame.size.height - height, self.view.frame.size.width, self.view.frame.size.height);
border.name = @"bottomBorderLayer";
[rootLayer addSublayer:border];
rootLayer.masksToBounds = TRUE;
Приведенный выше код будет работать только для нижней границы. Вы можете изменить пограничную сторону в соответствии с вашим требованием.
Здесь перед добавлением любого уровня в контроллер, я только что запустил цикл for, чтобы проверить, применяется ли какая-либо граница или нет?
Чтобы идентифицировать ранее добавленную границу, я использую свойство имени CALayer. И сравните этот слой перед удалением из подслоев.
Я использовал один и тот же код перед использованием свойства name, но создает случайный сбой. Но после использования свойства name и сравнения имени перед удалением будет устранена проблема сбоя.
Я надеюсь, что это поможет кому-то.
Конечно, вы можете сделать: self.layer.sublayers=nil;
как предложил Паскаль Бурк. Но лучше назвать сеттер для свойства подслоев: [self.layer setSublayers:nil];
Во избежание проблем с очисткой, если это возможно.
Для swift3 + вы можете использовать это.
yourView.layer.sublayers?.removeAll(keepingCapacity: true)
Смотрите здесь: Справочник API Apple
Или вы можете:
yourView.layer.sublayers?.forEach{ $0.removeFromSuperlayer()}
Что делать:
rootLayer.sublayers = @[];