基本資料填寫頁面,各種Picker大亂鬥。

學到各式Picker選擇方法,想到可以把這些做成一個基本資料填寫頁面,覺得蠻實用的,所以試著做做看啦。

Demo

架構

因為填寫的項目一列一列的,用TableView,cell的數量是固定的,用static cell,Navigation的標題覺得用Large Title比較好看,勾選Prefers Large Titles。

因為想要TextField用程式設定外觀樣式,所以拉好每個TextField後繼承自CustomTextField作為引用。

class CustomTextField: UITextField{let padding = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)//設定文字override func textRect(forBounds bounds: CGRect) -> CGRect {return bounds.inset(by: padding)}//設定佔位符override func placeholderRect(forBounds bounds: CGRect) -> CGRect {return bounds.inset(by: padding)}//設定顯示的文字override func editingRect(forBounds bounds: CGRect) -> CGRect {return bounds.inset(by: padding)}override func layoutSubviews() {super.layoutSubviews()self.layer.cornerRadius = 8self.layer.masksToBounds = true}}

回到TextField,我想在輸入完成按下return的時候跳到下個TextField,所以在outlet設定didSet並在class繼承UITextFieldDelegate,TextField會傳送一個delegate給UITextFieldDelegate呼叫textFieldShouldReturn,設定按下return後跳到下一個。becomeFirstResponder()設定在firstNameTextField會自動跳出鍵盤,算是個從這開始輸入的導引。

@IBOutlet weak var firstNameTextField: CustomTextField! {
didSet{
firstNameTextField.backgroundColor = UIColor.systemGray5
firstNameTextField.tag = 1
firstNameTextField.becomeFirstResponder()
firstNameTextField.delegate = self
}
}

@IBOutlet weak var lastNameTextField: CustomTextField! {
didSet{
lastNameTextField.backgroundColor = UIColor.systemGray5
lastNameTextField.tag = 2
lastNameTextField.delegate = self
}
}
}

按下return依照上面tag順序往下。

func textFieldShouldReturn(_ textField: UITextField) -> Bool {if let nextTextfield = view.viewWithTag(textField.tag + 1) {textField.resignFirstResponder()//鍵盤按return,收起鍵盤nextTextfield.becomeFirstResponder()//鍵盤按return,跳至下一個textField}return true}

星座的PickerView

先設定滾輪裡有哪些東西,這裡用12星座。

var pickerView = UIPickerView()let zastrology = ["Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"]

一樣在class繼承UIPickerViewDelegate&UIPickerViewDataSource設起乃!記得在viewDidLoad設定用本頁(ContactTableViewController)當delegate跟dataSource喔。

//星座的pickerViewDelegat呼叫的方法,一個滾輪func numberOfComponents(in pickerView: UIPickerView) -> Int {return 1}//滾輪選項幾個func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {return zastrology.count}//給選項名字func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {zastrology[row]}//將選到的選項傳入ZastrologyTextFieldfunc pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {ZastrologyTextField.text = zastrology[row]}

在ViewDidLoad呼叫方法。設定toolBar,按了Done才會關掉PickerView。

func showZastrologyPicker() {

pickerView.delegate = self
pickerView.dataSource = self

let toolBar = UIToolbar()
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.tintColor = UIColor.darkGray
toolBar.sizeToFit()

let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneClick))


toolBar.setItems([doneButton], animated: false)
toolBar.isUserInteractionEnabled = true

ZastrologyTextField.inputView = pickerView
ZastrologyTextField.inputAccessoryView = toolBar
}

@objc func doneClick() {
ZastrologyTextField.resignFirstResponder()
}

備註欄的TextView

TextView沒有placeHolder的功能,why?蘋果出來說明!在StackOverFlow發現不只我有這個困擾,前輩大神提供簡單易懂方法,非常感謝他。

//點選TextView輸入框,清除placeHolder(灰字)
func textViewDidBeginEditing(_ textView: UITextView) {
if NotesTextView.textColor == UIColor.systemGray2 {
NotesTextView.text = nil
NotesTextView.textColor = UIColor.black
}
}

//清除在TextView的輸入,顯示palceHolder
func textViewDidEndEditing(_ textView: UITextView) {
if NotesTextView.text.isEmpty == true{
NotesTextView.text = "More Information..."
NotesTextView.textColor = UIColor.systemGray2
}
}

選照片的ImagePicker

cell的第一列放一個ImageView拉outlet,在didSelectRowAt設定點到圖後跳出ActionSheet跟裡面的選項。

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
let photoSourceRequestController = UIAlertController(title: "", message: "Choose your photo source", preferredStyle: .actionSheet)

//設定相機
let cameraAction = UIAlertAction(title: "Camera", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false //照片是否能編輯
imagePicker.sourceType = .camera
imagePicker.delegate = self

self.present(imagePicker, animated: true, completion: nil)
}
}

//設定相簿
let photoLibraryAction = UIAlertAction(title: "Photo Library", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false //照片是否能編輯
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self

self.present(imagePicker, animated: true, completion: nil)
}
}

//刪除照片
let deleteAction = UIAlertAction(title: "Delete Photo", style: .destructive) { (action) in
self.picImageView.image = UIImage(systemName: "person.fill")

}

//取消選取
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
photoSourceRequestController.addAction(cameraAction)
photoSourceRequestController.addAction(photoLibraryAction)
photoSourceRequestController.addAction(deleteAction)
photoSourceRequestController.addAction(cancelAction)

present(photoSourceRequestController, animated: true, completion: nil)
}
}

ContactTableViewController要同時遵從UIImagePickerControllerDelegate跟UINavigationControllerDelegate並實作Protocol,從info取得圖片的相關資料。picImageView.image = selectedImage將選到的照片傳給info。

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let selectedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
picImageView.image = selectedImage
picImageView.layer.cornerRadius = 65
}

dismiss(animated: true, completion: nil)
}

打到這累累,剩下DatePIcker我下篇再補充。

--

--