Использование cornerRadius в UIImageView в UITableViewCell
Я использую UIImageView
для каждого из моих UITableViewCells
, как миниатюры. Мой код использует SDWebImage
для асинхронного захвата этих изображений из моего бэкэнд и загрузки их, а затем их кеширования. Это нормально работает.
My UIImageView
- это квадрат 50x50, созданный в Interface Builder. Его фон непрозрачен, белый цвет (такой же, как мой цвет фона UITableViewCell
, для производительности). Тем не менее, я бы хотел использовать гладкие углы для лучшей эстетики. Если я это сделаю:
UIImageView *itemImageView = (UIImageView *)[cell viewWithTag:100];
itemImageView.layer.cornerRadius = 2.5f;
itemImageView.layer.masksToBounds = NO;
itemImageView.clipsToBounds = YES;
Мой TableView падает около 5-6 кадров сразу, укупорки около 56 кадров в секунду во время быстрой прокрутки (что хорошо), но когда я перетащить и тянуть контроль обновления, она отстает немного и падает до примерно 40 кадров в секунду. Если я удалю строку cornerRadius
, все будет нормально и не будет отставать. Это было протестировано на iPod touch 5G с помощью инструментов.
Есть ли другой способ, которым я мог бы иметь округленные UIImageView
для моих ячеек и не пострадать от удара производительности? Я уже оптимизировал свой cellForRowAtIndexPath
, и я получаю 56-59 FPS при быстрой прокрутке без cornerRadius
.
Ответы
Ответ 1
Да, это потому, что cornerRadius и clipToBounds требуют экранированного рендеринга, я предлагаю вам прочитать этот ответ с одного из моих question. Я также цитирую две сессии WWDC, которые вы должны увидеть.
Лучшее, что вы можете сделать, это захватить изображение сразу после загрузки, а в другом потоке отправить метод, который вокруг изображений. Желательно, чтобы вы работали над изображением вместо изображения.
// Get your image somehow
UIImage *image = [UIImage imageNamed:@"image.jpg"];
// Begin a new image that will be the new image with the rounded corners
// (here with the size of an UIImageView)
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
cornerRadius:10.0] addClip];
// Draw your image
[image drawInRect:imageView.bounds];
// Get the image, here setting the UIImageView image
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
// Lets forget about that we were drawing
UIGraphicsEndImageContext();
Метод grabbed здесь
Вы также можете подклассифицировать tableviewcell и переопределить метод drawRect.
Грязный, но очень эффективный способ - нарисовать маску в фотошопе с внутренней альфой и вокруг соответствующего цвета фона ячейки и добавить еще одно изображение, не непрозрачное с четким цветом фона, на изображение с изображениями.
Ответ 2
Неблокирующее решение
Как продолжение реакции Андреа, вот функция, которая будет запускать его код в фоновом режиме.
+ (void)roundedImage:(UIImage *)image
completion:(void (^)(UIImage *image))completion {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Begin a new image that will be the new image with the rounded corners
// (here with the size of an UIImageView)
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
CGRect rect = CGRectMake(0, 0, image.size.width,image.size.height);
// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:rect
cornerRadius:image.size.width/2] addClip];
// Draw your image
[image drawInRect:rect];
// Get the image, here setting the UIImageView image
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
// Lets forget about that we were drawing
UIGraphicsEndImageContext();
dispatch_async( dispatch_get_main_queue(), ^{
if (completion) {
completion(roundedImage);
}
});
});
}
Ответ 3
Для этого есть еще одно хорошее решение. Я делал это несколько раз в своих проектах. Если вы хотите создать закругленные углы или что-то еще, вы можете просто использовать обложку перед вашим основным изображением.
Например, вы хотите сделать закругленные углы. В этом случае вам нужен квадратный слой изображения с вырезанной окружностью в центре.
Используя этот метод, вы получите 60 кадров в секунду при прокрутке внутри UITableView
или UICollectionView
. Поскольку этот метод не требуется для рендеринга экрана для настройки UIImageView
(например, аватары и т.д.).
Ответ 4
Свифт 3 версии ответа thedeveloper3124
func roundedImage(image: UIImage, completion: @escaping ((UIImage?)->(Void))) {
DispatchQueue.global().async {
// Begin a new image that will be the new image with the rounded corners
// (here with the size of an UIImageView)
UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
let rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
// Add a clip before drawing anything, in the shape of an rounded rect
UIBezierPath(roundedRect: rect, cornerRadius: image.size.width/2).addClip()
// Draw your image
image.draw(in: rect)
// Get the image, here setting the UIImageView image
guard let roundedImage = UIGraphicsGetImageFromCurrentImageContext() else {
print("UIGraphicsGetImageFromCurrentImageContext failed")
completion(nil)
return
}
// Lets forget about that we were drawing
UIGraphicsEndImageContext()
DispatchQueue.main.async {
completion(roundedImage)
}
}
}