如何根据条件为单元格正确分配样式,而不会在快速滚动后出现奇怪的样式行为?

Posted

技术标签:

【中文标题】如何根据条件为单元格正确分配样式,而不会在快速滚动后出现奇怪的样式行为?【英文标题】:How to properly assign a style based on a condition to a cell, without getting a weird style behaviour after fast scrolling? 【发布时间】:2020-04-22 20:08:25 【问题描述】:

我阅读了很多关于滚动 TableView 的内容,一般的答案是我必须使用 prepareForReuse 再次设置元素样式并重置图像。

我的问题仍然存在。如果我滚动得足够快,我在单元格中的预览图像不是一个圆圈,而是一个 5px 的圆形边框,尽管条件从未满足。

这里的魔力在哪里,我总是有想要的条件结果? postType == 0 = 照片(应该是圆形的),postType == 2 = 文本,应该有圆角。

主视图

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableViewNew.dequeueReusableCell(withIdentifier: "cellNewPosts", for: indexPath) as! MainNewTableViewCell

    cell.post = posts[indexPath.row]

    return cell
    

我的自定义单元格

import UIKit
import AVKit
import SDWebImage

class MainNewTableViewCell: UITableViewCell 

// Storyboard
@IBOutlet weak var viewContainer: ShadowedView! 
       didSet 
        viewContainer.layer.cornerRadius = 10
        viewContainer.backgroundColor = .white
        viewContainer.shadowColor = colorGrey
        viewContainer.shadowRadius = 1
       
   
@IBOutlet weak var imageViewPreview: UIImageView! 
    didSet 
        imageViewPreview.backgroundColor = .white
        imageViewPreview.layer.cornerRadius = imageViewPreview.frame.height / 2
        
    
@IBOutlet weak var viewContainerPreview: UIView! 
    didSet 
        viewContainerPreview.backgroundColor = .white
        viewContainerPreview.layer.cornerRadius = viewContainerPreview.frame.height / 2
        viewContainerPreview.layer.borderWidth = 2
        viewContainerPreview.layer.borderColor = colorLightGrey.cgColor
    

@IBOutlet weak var labelPostFromCity: UILabel! 
       didSet 
        labelPostFromCity.layer.shadowColor = colorLightGrey.cgColor
        labelPostFromCity.layer.shadowRadius = 1
        labelPostFromCity.layer.shadowOpacity = 1
        labelPostFromCity.layer.shadowOffset = CGSize(width: 1, height: 1)
        labelPostFromCity.layer.masksToBounds = false
       
   
@IBOutlet weak var labelPostFromCountry: UILabel!
@IBOutlet weak var labelPostDate: UILabel!
@IBOutlet weak var imageTextBubble: UIImageView! 
    didSet 
        imageTextBubble.tintColor = colorDarkPastelBlue
    

@IBOutlet weak var imageHeart: UIImageView!
@IBOutlet weak var labelAmountLikes: UILabel!
@IBOutlet weak var labelAmountComments: UILabel!


// Variables
// AVPlayer Looper
var playerLooper: NSObject?
var playerLayer: AVPlayerLayer!
var queuePlayer: AVQueuePlayer?
var player: AVPlayer?
var mediaToUpload: Data?
var movieString: String?
var movieUrl: URL?

var post: PostModel? 
    didSet 
        guard let _postFromCity = post?.postFromCity else  return 
        guard let _postFromCountry = post?.postFromCountry else  return 
        guard let _postDate = post?.postDate else  return 
        guard let _postMediaUrl = post?.postMediaUrl else  return 
        guard let _postType = post?.postType else  return 
        guard let _postText = post?.postText else  return 

        setupViewCell(postFromCity: _postFromCity, postFromCountry: _postFromCountry, postDate: _postDate, postMediaUrl: _postMediaUrl, postType: _postType, postText: _postText)
    


func setupViewCell(postFromCity: String, postFromCountry: String, postDate: Double, postMediaUrl: String, postType: Int, postText: String) 

    imageViewPreview.image = nil

    labelPostFromCity.text = postFromCity
    labelPostFromCountry.text = postFromCountry

    let postDate = postDate
    let formattedPostDate = Date(timeIntervalSince1970: postDate)
    let timeAgo = formattedPostDate.timeAgo(numericDates: false)
    labelPostDate.text = timeAgo

    if postType == 0 
        imageViewPreview.layer.cornerRadius = imageViewPreview.frame.height / 2
    viewContainerPreview.layer.cornerRadius = viewContainerPreview.frame.height / 2
        let mappedUrl = URL(string: postMediaUrl)
        imageViewPreview.sd_imageIndicator = SDWebImageActivityIndicator.white
        imageViewPreview.sd_setImage(with: mappedUrl) (_, _, _, _) in 
    

    if postType == 1 
    

    if postType == 2 
        imageViewPreview.layer.cornerRadius = 0
        viewContainerPreview.layer.cornerRadius = 10
        let xxx = UIColor.clear.image(CGSize(width: 50, height: 50))
        let xxxx = textToImage(drawText: postText, inImage: xxx, atPoint: CGPoint(x: 0, y: 0))
        imageViewPreview.image = xxxx
    




// Add text to the fake preview image
func textToImage(drawText text: String, inImage image: UIImage, atPoint point: CGPoint) -> UIImage 
    let textColor = UIColor.black
    let textFont = UIFont(name: "Helvetica Bold", size: ????!

    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(image.size, false, scale)

    let textFontAttributes = [
        NSAttributedString.Key.font: textFont,
        NSAttributedString.Key.foregroundColor: textColor,
        ] as [NSAttributedString.Key : Any]
    image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))

    let rect = CGRect(origin: point, size: image.size)
    text.draw(in: rect, withAttributes: textFontAttributes)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!


override func awakeFromNib() 
    super.awakeFromNib()
    self.selectionStyle = .none


override func prepareForReuse() 
    imageViewPreview.layer.cornerRadius = imageViewPreview.frame.height / 2
    viewContainerPreview.layer.cornerRadius = viewContainerPreview.frame.height / 2
    super.prepareForReuse()
    



extension UIColor 
func circleImage(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage 
    return UIGraphicsImageRenderer(size: size).image(actions:  rendererContext in
        self.setFill()
        rendererContext.cgContext.fillEllipse(in: CGRect(origin: .zero, size: size))
        )
    

【问题讨论】:

【参考方案1】:

希望这会有所帮助 在单元格类的layoutSubview() 中添加条件

 func layoutSubview() 
   if postType == 0 
    imageViewPreview.layer.cornerRadius = imageViewPreview.frame.height / 2
viewContainerPreview.layer.cornerRadius = viewContainerPreview.frame.height / 2
    let mappedUrl = URL(string: postMediaUrl)
    imageViewPreview.sd_imageIndicator = SDWebImageActivityIndicator.white
    imageViewPreview.sd_setImage(with: mappedUrl) (_, _, _, _) in 
 else if postType == 2 
    imageViewPreview.layer.cornerRadius = 0
    viewContainerPreview.layer.cornerRadius = 10
    let xxx = UIColor.clear.image(CGSize(width: 50, height: 50))
    let xxxx = textToImage(drawText: postText, inImage: xxx, atPoint: CGPoint(x: 0, y: 0))
    imageViewPreview.image = xxxx

【讨论】:

以上是关于如何根据条件为单元格正确分配样式,而不会在快速滚动后出现奇怪的样式行为?的主要内容,如果未能解决你的问题,请参考以下文章

根据输入到单元格中的数字为单元格分配颜色和值,而无需点击运行按钮

Xamarin form-UWP - 在快速滚动列表时显示数据之前的黑色单元格

单行 UITableView 直到滚动才显示 detailTextLabel

根据其他节点的条件或行值动态更改 AG 网格上一个单元格样式

UITableView动态单元格高度仅在某些滚动后才能正确显示

EXCEL如何根据条件自动设置单元格颜色