如何使用自定义 UITableView 上传图片

Posted

技术标签:

【中文标题】如何使用自定义 UITableView 上传图片【英文标题】:How To Upload Image Using Custom UITableView 【发布时间】:2020-06-15 05:40:27 【问题描述】:

我对 ios 开发比较陌生。我想知道如何允许用户单击表格中的一行并提示他们上传图像?我知道如何创建图像选择器,但我不确定如何启动它?

下面是我创建的 UITableView。我想在用户点击“图片”行时创建一个动作。

UITableView

这是我想要在用户单击“图像”行时启动的图像选择器示例。

ImagePicker

非常感谢任何帮助!

下面是视图控制器/表视图代码:

//
//  AddAssetTableViewController.swift
//  ItemizePro
//
//  Created by Tyler Wasick on 5/27/20.
//  Copyright © 2020 Tyler Wasick. All rights reserved.
//

import UIKit

class AddAssetTableViewController: UITableViewController 

    // TODO: Add image IBOutlet

    @IBOutlet weak var nameTextField: UITextField!

    @IBOutlet weak var descriptionTextField: UITextField!

    @IBOutlet weak var datePurchasedTextField: UITextField!

    @IBOutlet weak var manufactureTextField: UITextField!

    @IBOutlet weak var modelTextField: UITextField!

    @IBOutlet weak var serialNumberTextField: UITextField!

    @IBOutlet weak var costTextField: UITextField!

    @IBOutlet weak var roomTextField: UITextField!

    @IBOutlet weak var notesTextView: UITextView!

    @IBOutlet weak var receiptTextField: UITextField!

    @IBOutlet weak var addUIButton: UIButton!

    // Set variables
    var newAsset = Asset()
    let datePicker = UIDatePicker()
    var dateAdded = Date()
    var cost = 0

    // Setup number formater
    lazy var numberFormatter: NumberFormatter = 
        // Setup Currency Formatter
        let currencyFormatter = NumberFormatter()
        currencyFormatter.usesGroupingSeparator = true
        currencyFormatter.numberStyle = .currency

        // localize to your grouping and decimal separator
        currencyFormatter.locale = Locale.current
        return currencyFormatter
    ()

    override func viewDidLoad() 
        super.viewDidLoad()

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem

        // Setup Date Picker
        createDatePicker()

        // Use input data for cost field and update the cost data and formatting automatically
        costTextField.delegate = self
        costTextField.placeholder = updateCostField()

    

    // MARK: - Table view data source

    /*
     override func numberOfSections(in tableView: UITableView) -> Int 
     // #warning Incomplete implementation, return the number of sections
     return 0
     

     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
     // #warning Incomplete implementation, return the number of rows
     return 0
     


     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
     let cell = tableView.dequeueReusableCell(withIdentifier: "imageCell", for: indexPath)

     // Configure the cell...

     return cell
     
     */

    /*
     // Override to support conditional editing of the table view.
     override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool 
     // Return false if you do not want the specified item to be editable.
     return true
     
     */

    /*
     // Override to support editing the table view.
     override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) 
     if editingStyle == .delete 
     // Delete the row from the data source
     tableView.deleteRows(at: [indexPath], with: .fade)
      else if editingStyle == .insert 
     // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
     
     
     */

    /*
     // Override to support rearranging the table view.
     override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) 

     
     */

    /*
     // Override to support conditional rearranging of the table view.
     override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool 
     // Return false if you do not want the item to be re-orderable.
     return true
     
     */


    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

        //if let detinationVC = segue.description as? RoomListViewController

        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
        if let target = segue.destination as? RoomListViewController
        
            target.selectionDelegate = self
        

    


    // MARK: - Functions
    // Date picker
    func createDatePicker() 

        // Setup the UIToolbar
        let toolbar = UIToolbar()
        toolbar.sizeToFit()

        // Setup "Done" button
        let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(doneTapped))
        toolbar.setItems([doneButton], animated: true)

        // Format date text field
        datePurchasedTextField.inputAccessoryView = toolbar
        datePurchasedTextField.inputView = datePicker
        datePicker.datePickerMode = .date
    

    // Obj-C Date Picker Action
    @objc func doneTapped() 

        // Format date field
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.timeStyle = .none
        let dateString = formatter.string(from: datePicker.date)
        dateAdded = formatter.date(from: dateString)!

        // Set the date text field
        datePurchasedTextField.text = dateString

        // Close date picker
        self.view.endEditing(true)

    

    func updateCostField() -> String 

        // Format number into currency data
        let num = cost
        let decimalNum = Double(num) / 100
        let numString = numberFormatter.string(from: NSNumber(value: decimalNum))

        // Return formatted number
        return numString!
    

    func showActionSheet(title:String) 

        // Create the action sheet
        let actionSheet = UIAlertController(title: title, message: "Select a source to upload an image", preferredStyle: .actionSheet)

        // Create camera action if available
        if UIImagePickerController.isSourceTypeAvailable(.camera) 

            let cameraAction = UIAlertAction(title: "Camera", style: .default)  (action) in

                // Set the camera action
                self.showImagePicker(type: .camera)
            

            // Add action to the action sheet
            actionSheet.addAction(cameraAction)
        

        // Create photo library action
        if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) 

            let photoAction = UIAlertAction(title: "Select From Photo Library", style: .default)  (action) in

                // Set photo library action
                self.showImagePicker(type: .photoLibrary)

            

            // Add action to the action sheet
            actionSheet.addAction(photoAction)
        

        // Create cancel actions
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)

        // Add the cancel action
        actionSheet.addAction(cancelAction)

        // Present action sheet
        present(actionSheet, animated: true, completion: nil)

    

    func showImagePicker(type:UIImagePickerController.SourceType) 

        // Create the image picker
        let imagePicker = UIImagePickerController()
        imagePicker.sourceType = type

        // Setup delegate
        imagePicker.delegate = self

        // Present it
        present(imagePicker, animated: true, completion: nil)
    

    // MARK: - IBAction outlets

    @IBAction func addButtonTapped(_ sender: UIButton) 

        // Name text field
        if nameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.name = nameTextField.text!
        
        else if nameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.name = ""
        

        // Description text field
        if descriptionTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.description = descriptionTextField.text!
        
        else if descriptionTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.description = ""
        

        // Date text field
        if datePurchasedTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.datePurchased = dateAdded
        
        else if datePurchasedTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.datePurchased = Date()
        

        // Manufacture text field
        if manufactureTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.manufacture = manufactureTextField.text!
        
        else if manufactureTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.manufacture = ""
        

        // Model text field
        if modelTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.model = modelTextField.text!
        
        else if modelTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.model = ""
        

        // Serial number text field
        if serialNumberTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.serialnumber = serialNumberTextField.text!
        
        else if serialNumberTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.serialnumber = ""
        

        // Cost text field
        if costTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines) != "" 
            let cost = costTextField.text!
            newAsset.cost = cost
        
        else if costTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" 
            newAsset.cost = "$0.00"
        

        // Room text field
        if roomTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.room = roomTextField.text!
        
        else if roomTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.room = ""
        

        // Notes text field
        if notesTextView.text?.trimmingCharacters(in: .whitespacesAndNewlines) != nil 
            newAsset.notes = notesTextView.text!
        
        else if notesTextView.text?.trimmingCharacters(in: .whitespacesAndNewlines) == nil 
            newAsset.notes = ""
        

        // TODO: - Receipt

        // TODO: - Image

        // Add to firebase
        let result = FirebaseDB.addAssets(asset: newAsset)

        print(result)
    





// MARK: - Extensions
// Table delegate extension
extension AddAssetTableViewController : RoomDelegate 
    func tappedOnRoom(room: String) 
        roomTextField.text = room
    


// Cost text field delegate
extension AddAssetTableViewController : UITextFieldDelegate 
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 

        // Check if num is <= 1 billion
        if cost < 1000000000 

            // Add new digit to the cost var
            if let num = Int(string) 
                cost = cost * 10 + num
                print(cost)
                costTextField.text = updateCostField()
            
        

        // If the user removes a digit, remove it from the cost var
        if string == "" 
            cost = cost / 10
            print(cost)
            costTextField.text = updateCostField()
        

        // Return false for return (return is unused)
        return false
    


// Image picker extension
extension AddAssetTableViewController : UIImagePickerControllerDelegate & UINavigationControllerDelegate 

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) 

        // TODO: User cancelled, dismiss image picker

    

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) 

        // TODO: If image was selected successfully, set the image to "selectImage" object
        if let selectImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage 


        
        // Dismiss the picker
        picker.dismiss(animated: true, completion: nil)
    


【问题讨论】:

【参考方案1】:

使用didSelectRow 方法,您已经拥有需要在代码中调用的方法。方法如下:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) -> Int 
     if indexPath.row == 0 
         showActionSheet(title: "Your title")
     

【讨论】:

以上是关于如何使用自定义 UITableView 上传图片的主要内容,如果未能解决你的问题,请参考以下文章

iOS 自定义按钮和滚动视图,如 venmo

当单元格获得自定义高度时如何自定义 UITableView 分隔符

web 图片上传实现本地预览

UITableView异步图片动态跳高

分组 UITableView 上的自定义背景图像

如何为uitableview自定义多选编辑模式