swift 如何在生成文本时扩展UITableViewCell的UILabel的Background属性?

iszxjhcz  于 2023-06-21  发布在  Swift
关注(0)|答案(2)|浏览(139)

我不能让我的标签的背景属性正确地扩展/增长的文本,因为它是输入到标签。
我已经做了一个UITableView与自定义单元格。这个自定义单元格的文件是.xib文件(称为StoryCell.xib)。.xib文件与一个.swift文件相关联,我可以在其中输入代码。在这个.swift文件(它被称为StoryCell.swift)中,我有一个输入动画函数,无论这个标签中的字符串是什么,它都会被逐个字符地输入,直到字符串变量的全文在一段时间内被完全输入。有了这个标签,我就有了一个背景属性集。(效果)。
我的问题是,当字符和单词被输入到带有输入字符串变量的标签中时,background属性不能正确地扩展每一行被输入的文本。使用不同的代码并启用不同的属性和约束,我的标签的背景要么是预先确定的(这意味着背景属性将自动设置为某些尺寸[某个框],以适应完整的文本,一旦它被完全键入),或者我的背景属性只是保持为一行,在该行移动到另一行后切断文本以写入更多文本。
我不知道该怎么办。如果任何人对我能做什么或我能调查的资源有任何想法,我将永远感激。
TL;DR我希望我的UILabel的background属性在我的自定义单元格(在UITableView中)中逐行扩展,并通过我的键入函数键入我的文本,但我无法实现这种效果。如何到达?
My StoryCell.swift的代码,如果你需要的话可以参考:
导入UIKit

class StoryCell: UITableViewCell {
    
    var typingTimer: Timer? // Add typingTimer property

    @IBOutlet weak var label: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        // Configure the view for the selected state
    }

    // Add startTypingAnimation method
    func startTypingAnimation(withText text: String) {
        label.text = "" // Clear existing text
        var charIndex = 0

        // Create a timer to simulate typing animation
        typingTimer?.invalidate() // this code line here is to make sure that no previous timers are running
        
        typingTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { timer in
            if charIndex < text.count {
                let index = text.index(text.startIndex, offsetBy: charIndex) // The text.index(_, offsetBy:) method is used to obtain the index of a character in the string text. It takes two arguments: the starting index and an offset. The offset specifies the number of positions to move from the starting index.

                let nextChar = String(text[index]) // the character at the position specified by the offset value
                
                self.label.text?.append(nextChar)
                charIndex += 1
            } else {
                timer.invalidate()
            }
        }
    }
}

如果你一定要知道,标签的文本来自另一个.swift文件,这就是为什么你不会在这个文件中看到任何文本。

ilmyapht

ilmyapht1#

我不知道为什么你的约束不起作用。我记得以前做过类似的事情,单元格会自动按预期调整大小。
在任何情况下,如果您使用自iOS 14以来存在的UIListContentConfiguration API,单元格都会自动调整大小。这允许您以各种方式自定义表视图单元格,而无需自己手动添加子视图。当然,它不如手工制作自己的细胞灵活,但它允许的定制仍然很多。还有一些相关的类,如UIBackgroundConfiguration
下面是startTypingAnimation,但改为使用UIListContentConfiguration

// in awakeFromNib, set an initial configuration:
self.contentConfiguration = self.defaultContentConfiguration()

// ...

func startTypingAnimation(withText text: String) {
    var config = self.contentConfiguration as! UIListContentConfiguration
    config.text = ""
    self.contentConfiguration = config
    //label.text = ""
    var charIndex = 0

    typingTimer?.invalidate()
    
    typingTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { timer in
        if charIndex < text.count {
            let index = text.index(text.startIndex, offsetBy: charIndex)

            let nextChar = String(text[index]) // the character at the position specified by the offset value
            
            var newConfig = self.contentConfiguration as? UIListContentConfiguration
            newConfig?.text?.append(nextChar)
            self.contentConfiguration = newConfig
            //self.label.text?.append(nextChar)
            charIndex += 1
        } else {
            timer.invalidate()
        }
    }
}
eh57zj3b

eh57zj3b2#

当表格视图布局其行/单元格时...

  • heightForRowAt indexPath实现了吗?
  • 使用该值
  • 否则,tableView.rowHeight是否设置为特定值?
  • 使用该值
  • 否则,询问单元格的高度(基于其约束和数据)
  • 使用该值

表格显示后,不再修改行高
所以,如果你的代码改变了单元格的内容,单元格的高度也会改变,我们必须通知控制器,让它重新布局单元格。
这通常是通过cell类中的closure来完成的。
所以,假设你的单元格xib看起来像这样:

我们可以将它添加到您的cell类中:

// closure to inform the table view controller that the text has changed
var textChanged: (() -> ())?

然后,当计时器向标签的文本添加新字符时:

self.label.text?.append(nextChar)
charIndex += 1
                
// inform the controller that the text has changed
self.textChanged?()

回到cellForRowAt中的控制器类,我们设置闭包:

cell.textChanged = { [weak self] in
    guard let self = self else { return }
        
    // this will update the row height if needed
    self.tableView.performBatchUpdates(nil)
}

下面是一个完整的例子(假设你有StoryCell.xib,如上所示)。

单元格类别

class StoryCell: UITableViewCell {
    
    // closure to inform the table view controller that the text has changed
    var textChanged: (() -> ())?
    
    var typingTimer: Timer? // Add typingTimer property
    
    @IBOutlet weak var label: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        // Configure the view for the selected state
    }
    
    // Add startTypingAnimation method
    func startTypingAnimation(withText text: String) {
        label.text = "" // Clear existing text
        var charIndex = 0
        
        // Create a timer to simulate typing animation
        typingTimer?.invalidate() // this code line here is to make sure that no previous timers are running
        
        typingTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { [weak self] timer in
            guard let self = self else {
                timer.invalidate()
                return
            }
            if charIndex < text.count {
                let index = text.index(text.startIndex, offsetBy: charIndex) // The text.index(_, offsetBy:) method is used to obtain the index of a character in the string text. It takes two arguments: the starting index and an offset. The offset specifies the number of positions to move from the starting index.
                
                let nextChar = String(text[index]) // the character at the position specified by the offset value
                
                self.label.text?.append(nextChar)
                charIndex += 1
                
                // inform the controller that the text has changed
                self.textChanged?()
                
            } else {
                timer.invalidate()
            }
        }
    }
}

单元格文本的简单结构体

struct StoryStruct {
    var prompt: String = ""
    var story: String = ""
    var isStoryShowing: Bool = false
}

和一个示例视图控制器-(为StoryVC分配一个新的普通视图控制器):

class StoryVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    let tableView = UITableView()
    
    var myData: [StoryStruct] = [
        StoryStruct(prompt: "What's going on?", story: "Learn App Development!"),
        StoryStruct(prompt: "What is a UILabel?", story: "UILabel\n\nA label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label."),
        StoryStruct(prompt: "What is a UIButton?", story: "UIButton\n\nA button displays a plain styled button that can have a title, subtitle, image, and other appearance properties."),
        StoryStruct(prompt: "What is a UISwitch?", story: "UISwitch\n\nA switch displays an element that shows the user the boolean state of a given value.\n\nBy tapping the control, the state can be toggled."),
        StoryStruct(prompt: "What next?", story: "Congratulations! You've now learned everything there is to know about developing iPhone Apps!"),
    ]
    
    var activeRow: Int = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: g.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
        ])
        
        tableView.register(UINib(nibName: "StoryCell", bundle: nil), forCellReuseIdentifier: "StoryCell")
        tableView.dataSource = self
        tableView.delegate = self
        
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "StoryCell", for: indexPath) as! StoryCell
        
        cell.selectionStyle = .none
        
        let ss: StoryStruct = myData[indexPath.row]
        
        if ss.isStoryShowing {
            cell.label.text = ss.story
        } else {
            cell.label.text = ss.prompt
        }
            
        cell.textChanged = { [weak self] in
            guard let self = self else { return }
            
            // this will update the row height if needed
            self.tableView.performBatchUpdates(nil)
        }
            
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if indexPath.row == activeRow {
            if let c = tableView.cellForRow(at: indexPath) as? StoryCell {
                c.startTypingAnimation(withText: myData[indexPath.row].story)
                myData[indexPath.row].isStoryShowing = true
            }
            activeRow += 1
        }
    }
}

运行时,它看起来像这样:

当您从上到下点击每行时,您的打字模拟将更改该行中的文本,并且它将扩展:

注意-您需要将标签上的Content Mode设置为Top Left

否则,标签中的文本将在调整大小时“反弹”。
请记住--这是示例代码!***********

相关问题