基本資料填寫頁面,各種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我下篇再補充。