输入新值时复制表的最后一行

Posted

技术标签:

【中文标题】输入新值时复制表的最后一行【英文标题】:Duplicating last row of table when new value entered 【发布时间】:2019-04-27 19:19:29 【问题描述】:

我的应用中有聊天功能。该页面将现有数据加载为名为 hhmessages 的数组。对话中的最后一条消息是“欢迎”,当我输入新文本“谢谢”并按 Enter 时,表格会自动再次显示“欢迎”而不是“谢谢”。如果它退出页面并返回,它现在会显示“谢谢”作为最后一条消息。它在后端工作,只是即时更新在输入时没有显示 UITableView 中的值。

这是针对 iPhone 应用程序的。 已更新以显示完整代码 - 现在反向已被删除,新条目显示为空白。

import UIKit
import Foundation

 extension String 

    // Calculeta the hight string Function
    func calculateTextFrameRect(
        objectsInPlaceHeight: CGFloat,
        objectsInPlaceWidth: CGFloat,
        fontSize: CGFloat,
        fontWeight: CGFloat) -> CGSize
    
        let bounding = CGSize(width: UIScreen.main.bounds.width - objectsInPlaceWidth, height: .infinity)
        let rect = NSString(string: self).boundingRect(
            with: bounding,
            options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin),
            attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight(rawValue: fontWeight))],
            context: nil)
        return CGSize(width: UIScreen.main.bounds.width, height: rect.height + objectsInPlaceHeight )
    

// Messages for test
let frame = CGRect(origin: .zero, size: CGSize.init(width: 375, height: 559))

class Message 
    let message: String
    var incoming: [Int]
    let image: UIImage
    var avas = UIImage()
    init(message: String, image: UIImage, incoming: Int, avas: UIImage) 
        self.message = message
        self.image = image
        self.incoming = [incoming]
        self.avas = avas
    


class ConversationViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate 
    //var user = NSDictionary()
    var messages = NSDictionary()
    //var guest = NSDictionary()

    @IBOutlet var senderLbl: UILabel!
    @IBOutlet var senderageLbl: UILabel!
    @IBOutlet var senderraceLbl: UILabel!
    @IBOutlet var sendergenderLbl: UILabel!
    @IBOutlet var sendercityLbl: UILabel!
    @IBOutlet var senderstateLbl: UILabel!
    // @IBOutlet var tableView: UITableView!
    var hhmessages = [AnyObject]()
    //var messages: [Message] = []
    var pictures = [UIImage]()

    var avas = [UIImage]()
    var avaURL = [String]()
    var isLoading = false
    var skip = 0
    var limit = 50
    var images = [UIImage]()
    var incoming: [Int] = []
    var comments = [String]()
    var ids = [String]()


    //var isSent: String = ""
    var isPictureSelected = false
    //var currentUser_ava = [Any]()
    @IBOutlet var pictureImg: UIImageView!
    @IBOutlet var avaImg: UIImageView!

    @IBOutlet var viewprofile_btn: UIButton!
    @IBOutlet var imgprofile_btn: UIButton!

    @IBOutlet var replyTxt: UITextView!

    //var replyTxt:UITextView!
    @IBOutlet var replyTxt_height: NSLayoutConstraint!

    @IBOutlet var replyTxt_bottom: NSLayoutConstraint!

    @IBOutlet var picSelect: UIButton!
    @IBOutlet var replyBtn: UIButton!
    var puuid = String()
    var imageSelected = false
    var coolIndicator: UIActivityIndicatorView!
    var commentsTextView_bottom_identity = CGFloat()


    @IBOutlet var tableView: UITableView!

    // Table View here + basic configuration

    override func viewDidLoad() 
        //self.tabBarController?.tabBar.isHidden = true

        super.viewDidLoad()
        tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));

        // dynamic cell height
        tableView.dataSource = self
        tableView.delegate = self
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 200

        loadPosts()

        replyTxt.layer.cornerRadius = replyTxt.bounds.width / 50
        replyTxt.backgroundColor = UIColor.clear
        replyTxt.layer.borderColor = UIColor.gray.cgColor
        replyTxt.layer.borderWidth = 1.0

        let username = messages["sender"] as? String

        self.navigationItem.title = username

    
    // pre last func
    override func viewWillDisappear(_ animated: Bool) 
        super.viewWillDisappear(animated)

        // remove observers of notification when the viewController is left
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
           NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)

    


    // exec-d once notification is caught -> KeyboardWillShow
    @objc func keyboardWillShow(_ notification: Notification) 

        // getting the size of the keyboard
        if let keyboard_size = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue 

            // increasing the bottom constraint by the keyboard's height
            replyTxt_bottom.constant += keyboard_size.height

        

        // updating the layout with animation
        UIView.animate(withDuration: 0.3) 
            self.view.layoutIfNeeded()
        

    


    // exec-d once notification is caught -> KeyboardWillHide
    @objc func keyboardWillHide() 


        // updating the layout with animation
        UIView.animate(withDuration: 0.3) 
            self.view.layoutIfNeeded()
        

    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
        //replyTxt().resignFirstResponder()
        self.view.endEditing(false)

    

    // TABLEVIEW

    // Number os cells
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

        return hhmessages.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let colorSmoothGray = UIColor(red: 229/255, green: 229/255, blue: 234/255, alpha: 1)
        let colorBrandBlue = UIColor(red: 148 / 255, green: 33 / 255, blue: 147 / 255, alpha: 1)
        let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String

        print("test 1", pictureURL)

        // no picture in the post
        if pictureURL == nil || pictureURL == "" 
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ConversationCell

            cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))

            // shortcuts
            let hhpost = hhmessages[indexPath.row]
            let text = hhpost["messagetext"] as? String

                cell.messageLbl.text = text
                cell.messageLbl.textAlignment = .right
                cell.messageLbl.backgroundColor = colorSmoothGray
                cell.messageLbl.textColor = .black
                cell.messageLbl.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
                cell.messageLbl.font?.withSize(25)
                cell.messageLbl.clipsToBounds = true
           cell.messageLbl.sizeToFit()
            pictures.append(UIImage())


            return cell
         else 
            let cell = tableView.dequeueReusableCell(withIdentifier: "PicCell", for: indexPath) as! PicConversationCell
            cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))

            let smimages = hhmessages[indexPath.row]["path"] as? UIImage

            cell.smavaImg.image = smimages

            for i in 0 ..< self.incoming.count 
                // Confiture the constraints for cell
                if self.incoming[indexPath.row] == 1 
                    // Text
                   cell.messageLbl.textAlignment = .left
                    cell.messageLbl.backgroundColor = colorBrandBlue
                    cell.messageLbl.textColor = .white
                    cell.messageLbl.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
                    cell.messageLbl.font?.withSize(25)
                    cell.messageLbl.clipsToBounds = true

                    // Constraints
                   cell.lefBubbleConstraint.isActive = true
                    cell.rightBubbleConstraint.isActive = false
                    if cell.postpictureImg.image == nil 
                        cell.postpictureImg.backgroundColor = .black
                        cell.postpictureImg.clipsToBounds = true

                    
                    else 
                        cell.postpictureImg.backgroundColor = .black
                        cell.postpictureImg.clipsToBounds = true

                    

                
                else if self.incoming[indexPath.row] == 0 
                    // Text
                    cell.messageLbl.textAlignment = .right
                    cell.messageLbl.backgroundColor = colorSmoothGray
                    cell.messageLbl.textColor = .black
                    cell.messageLbl.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
                    cell.messageLbl.font?.withSize(25)
                    cell.messageLbl.clipsToBounds = true

                    // Constraints
                    cell.lefBubbleConstraint.isActive = false
                    cell.rightBubbleConstraint.isActive = true
                    if cell.postpictureImg.image == nil 
                        cell.postpictureImg.backgroundColor = .black
                        cell.postpictureImg.clipsToBounds = true

                    
                    else 
                        cell.postpictureImg.backgroundColor = .black
                        cell.postpictureImg.clipsToBounds = true

                    

                

           if cell.lefBubbleConstraint.isActive == true 


            cell.lefImageConstraint.isActive = true
                cell.rightImageConstraint.isActive = false

             else 



                cell.lefImageConstraint.isActive = false
                cell.rightImageConstraint.isActive = true
            


                let pictureString = hhmessages[indexPath.row]["uploadpath"] as! String
                let pictureURL = URL(string: pictureString)!

                // if there are still pictures to be loaded
                if hhmessages.count != pictures.count 

                    URLSession(configuration: .default).dataTask(with: pictureURL)  (data, response, error) in


                        // downloaded
                        if let image = UIImage(data: data!) 

                            self.pictures.append(image)

                            DispatchQueue.main.async 
                                cell.postpictureImg.image = image
                            
                        

                        .resume()

                    // cached picture
                 else 

                    DispatchQueue.main.async 
                        cell.postpictureImg.image = self.pictures[indexPath.row]
                    
                


            
            return cell

        

    



    // pre load func
    override func viewDidAppear(_ animated: Bool) 


    
    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)


    

    // func of loading posts from server
    @objc func loadPosts() 
        //isLoading = true
        let me = user!["username"] as! String
        let meid = user!["id"] as! String
        print(meid)
        print(me)
        //print(username)
        let uuid = messages["uuid"] as! String
        print(uuid)

        // accessing php file via url path
        let url = URL(string: "http://localhost/message.php")!

        // pass information to php file
        let body = "username=\(me)&uuid=\(uuid)&recipient_id=\(meid)"
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = body.data(using: String.Encoding.utf8)
        tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));

        // launch session
        URLSession.shared.dataTask(with: request)  (data, response, error) in
            DispatchQueue.main.async 

                // no error of accessing php file
                // error occured
                if error != nil 
                    Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
                    //self.isLoading = false
                    return
                

                do 
                    // access data - safe mode
                    guard let data = data else 
                        Helper().showAlert(title: "Data Error", message: error!.localizedDescription, in: self)
                        //self.isLoading = false
                        return
                    
                    // getting content of $returnArray variable of php file
                    let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary

                    // accessing json data - safe mode
                    guard let posts = json?["messages"] as? [NSDictionary] else 
                        //self.isLoading = false
                        return
                    

                    // assigning all successfully loaded posts to our Class Var - posts (after it got loaded successfully)
                    self.hhmessages = posts

                    self.tableView.reloadData()

                    // scroll to the latest index (latest cell -> bottom)
                    let indexPath = IndexPath(row: self.hhmessages.count - 1, section: 0)
                    self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
                  //  self.isLoading = false

                 catch 
                    Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
                    //self.isLoading = false
                    return
                

            
            .resume()

    

        @IBAction func viewprofile_clicked(_ sender: Any) 
        // performSegue(withIdentifier: "guest2", sender: self.guest)

    
    @IBAction func imgprofile_clicked(_ sender: Any) 
        // performSegue(withIdentifier: "guest2", sender: self.guest)

    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.identifier == "guest" 

            if let destination = segue.destination as? GuestViewController 
                destination.guest = messages
            
        
    

    // function sending requset to PHP to uplaod a file
    func uploadPost() 
        // validating vars before sending to the server
        guard let user_id = user?["id"] as? String, let username = user?["username"] as? String, let avaPath = user?["ava"] else 

            // converting url string to the valid URL
            if let url = URL(string: user?["ava"] as! String) 

                // downloading all data from the URL
                guard let data = try? Data(contentsOf: url) else 
                    return
                

                // converting donwloaded data to the image
                guard let image = UIImage(data: data) else 
                    return
                

                // assigning image to the global var
                let currentUser_ava = image
            

            return
        

        let user_id_int = Int(user_id)!
        let messagetext = replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines)
        hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)

        let indexPath = IndexPath(row: hhmessages.count - 1, section: 0)
        tableView.beginUpdates()
        tableView.insertRows(at: [indexPath], with: .automatic)
        tableView.endUpdates()
        tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
        tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)

        replyTxt.text = ""
        textViewDidChange(replyTxt)
        let recipient = messages["username"] as! String
        let rid = String(describing: messages["recipient_id"]!)
        let uuid = messages["uuid"] as! String
        puuid = UUID().uuidString

        // prepare request
        let url = URL(string: "http://localhost/messagepost.php")!
        let body = "sender_id=\(user_id)&sender=\(username)&text=\(messagetext)&recipient_id=\(rid)&recipient=\(recipient)&uuid=\(uuid)&puuid=\(puuid)"

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = body.data(using: .utf8)

        // send request
        URLSession.shared.dataTask(with: request)  (data, response, error) in
            DispatchQueue.main.async 

                // error happened
                if error != nil 
                    Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
                    return
                

                do 
                    // converting received data from the server into json format
                    let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary

                    // safe mode of casting json
                    guard let parsedJSON = json else 
                        return
                    

                    // if the status of JSON is 200 - success
                    if parsedJSON["status"] as! String == "200" 

                     else 
                        Helper().showAlert(title: "400", message: parsedJSON["status"] as! String, in: self)
                        return
                    

                    // json error
                 catch 
                    Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
                    return
                

            
            .resume()

    
    // exec-d whenever delegated textView has been changed by chars
    func textViewDidChange(_ textView: UITextView) 

        // declaring new size of the textView. we increase the height
        let new_size = textView.sizeThatFits(CGSize.init(width: textView.frame.width, height: CGFloat(MAXFLOAT)))

        // assign new size to the textView
        textView.frame.size = CGSize.init(width: CGFloat(fmaxf(Float(new_size.width), Float(textView.frame.width))), height: new_size.height)

        //UIView.animate(withDuration: 0.2) 
        self.view.layoutIfNeeded()
        //

    

    @IBAction func picSelect_clicked(_ sender: AnyObject) 
        // calling picker for selecting iamge
       showActionSheet()
    
    // this function launches Action Sheet for the photos
    func showActionSheet() 

        // declaring action sheet
        let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        // declaring camera button
        let camera = UIAlertAction(title: "Camera", style: .default)  (action) in

            // if camera available on device, than show
            if UIImagePickerController.isSourceTypeAvailable(.camera) 
                self.showPicker(with: .camera)
            

        

        // declaring library button
        let library = UIAlertAction(title: "Photo Library", style: .default)  (action) in

            // checking availability of photo library
            if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) 
                self.showPicker(with: .photoLibrary)
            

        

        // declaring cancel button
        let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        // adding buttons to the sheet
        sheet.addAction(camera)
        sheet.addAction(library)
        sheet.addAction(cancel)

        // present action sheet to the user finally
        self.present(sheet, animated: true, completion: nil)

    


    // takes us to the PickerController (Controller that allows us to select picture)
    func showPicker(with source: UIImagePickerControllerSourceType) 

        let picker = UIImagePickerController()
        picker.delegate = self
        picker.allowsEditing = true
        picker.sourceType = source
        present(picker, animated: true, completion: nil)

    


    // executed whenever the image has been picked via pickerController
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 

        // accessing selected image
        let image = info[UIImagePickerControllerEditedImage] as? UIImage

        // assigning selected image to pictureImageView
        pictureImg.image = image

        // cast boolean as TRUE -> Picture Is Selected
        isPictureSelected = true

        // remove pickerController

        pictureImg.image = info[UIImagePickerControllerEditedImage] as? UIImage
        self.dismiss(animated: true, completion: nil)

        // cast as a true to save image file in server
        if pictureImg.image == info[UIImagePickerControllerEditedImage] as? UIImage 
            imageSelected = true
        
        dismiss(animated: true, completion: nil)
    


    // exec when pictureImageView has been tapped
    @IBAction func pictureImageView_tapped(_ sender: Any) 

        // declaring action sheet
        let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        // declaring delete button
        let delete = UIAlertAction(title: "Delete", style: .destructive)  (action) in
            self.pictureImg.image = UIImage()
        

        // declaring cancel button
        let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        // adding buttons to the sheet
        sheet.addAction(delete)
        sheet.addAction(cancel)

        // present action sheet to the user finally
        self.present(sheet, animated: true, completion: nil)

    


    // custom body of HTTP request to upload image file
    func createBodyWithParams(_ parameters: [String: String]?, filePathKey: String?, imageDataKey: Data, boundary: String) -> Data 

        let body = NSMutableData();

        if parameters != nil 
            for (key, value) in parameters! 
                body.appendString("--\(boundary)\r\n")
                body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
                body.appendString("\(value)\r\n")
            
        


        // if file is not selected, it will not upload a file to server, because we did not declare a name file
        var filename = ""

        if imageSelected == true 
            filename = "notes-\(puuid).jpg"
        


        let mimetype = "image/jpg"

        body.appendString("--\(boundary)\r\n")
        body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
        body.appendString("Content-Type: \(mimetype)\r\n\r\n")
        body.append(imageDataKey)
        body.appendString("\r\n")

        body.appendString("--\(boundary)--\r\n")

        return body as Data

    



    @IBAction func replyBtn_clicked(_ sender: Any) 

        if replyTxt.text.isEmpty == false && replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false 
            uploadPost()
            //tableView.reloadData()
        

    



    @objc func keyboardWillChange(notification: NSNotification) 

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y
        //print("deltaY",deltaY)

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: 
            self.replyTxt.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
            self.tableView.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
            self.replyBtn.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
            self.picSelect.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField

        ,completion: nil)
    

    func textFieldShouldReturn(_ replyTxt: UITextField) -> Bool 
        replyTxt.resignFirstResponder()
        return true
    


【问题讨论】:

numberOfRows 函数的代码是什么? @MaryamFekri 刚刚更新为显示 numberOfRows: func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int return hhmessages.count 我认为,如果您完全滚动表格,tableView 再次为所有行调用 cellForRow,它将修复您的行。但可以肯定这不是解决方案,我只想知道这是否是我正在考虑的状态 我建议先评论这一行:tableView.scrollToRow(at: indexPath, at: .bottom, animated: true) 我觉得这个会再次调用你的 cellForRow 函数,因为你有将文本添加到您的数组中,然后它将再次显示为最后一行 你也可以在 cellForRow 函数中下一个断点,并检查在哪一行代码之后它被调用了多少次 【参考方案1】:

问题是您在

处插入新文本

let indexPath = IndexPath(row: hhmessages.count - 1, section: 0)

这是数组的最后一个字段。 但在你的 cellForRow 中:你有

let text = hhmessages.reversed()[indexPath.row]["messagetext"] as! String

它在 tableView 的最后一个单元格中显示数组的第一个字段。

我认为那是你的问题。

【讨论】:

感谢@Maryam,不幸的是,我尝试了您推荐的不同变体,但没有运气。我会按要求发布我的整个视图控制器。 嗨@Maryam,我删除了反向并更改了其他一些代码,但现在它显示为空白而不是重复最后一行。 在看到您的代码之前,我无法告诉您出了什么问题。您应该跟踪您的代码并查看每一步需要多少行以及每一步的array.count 是多少,如果一切都匹配,那么您需要检查您的字符串数组,看看它是否符合您想要的顺序。【参考方案2】:

就像其他人所说的那样,您在 hhmessages 中弄乱了您的订单。 假设您有消息WelcomeHello,并且您正在尝试添加Thank Your,您的代码包含更多 cmets:

 self.hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex) // Thank You is inserted to the end of the array at 3rd position (2)

 let indexPath = IndexPath(row: hhmessages.count - 1, section: 0) // ok, let's get index of 3rd row (2)
    tableView.beginUpdates()
    tableView.insertRows(at: [indexPath], with: .automatic) // add new row to the end
    tableView.endUpdates()

然后 UIKit 要求您在位置 2 加载这个新的第 3 行,然后您调用:

   let text = hhmessages.reversed()[indexPath.row]["messagetext"] as! String

问题是hhmessages.reversed() 反转了您的数组,实际上使Thank you 在位置0 的第一个,Welcome 在位置2 的最后一个,这将得到文本Welcome。 我看到的第二个问题是这一行:

let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String

在这里你得到了未经审查的图片网址,这至少很奇怪。

【讨论】:

感谢@KleMix,我尝试删除反向,但没有任何反应。我在那里有反转,所以我的桌子将从底部加载 我删除了反向并更改了一些其他代码,但现在它显示为空白而不是重复最后一行

以上是关于输入新值时复制表的最后一行的主要内容,如果未能解决你的问题,请参考以下文章

Excel 如何快速从第一行选到最后一行

Hudi 0.5.2 Hudi 写时复制 读时合并表区别联系

Excel将一行的内容进行复制时,列与列之间是用制表符“ ”进行分隔的

VBA复制最后一行范围并粘贴到另一个工作表

复制表结构并且不复制表数据

WPS表格自动跳转到最后一行(100多万的空白行)