iOS - 動態調整Dialog 高度

承上篇 - iOS - 客製化Dialog

若Dialog中有 TextField的時候, 可能會被軟體鍵盤所蓋住
因此必須使用動態調整Dialog的方式來解決.

Step 1: 監聽與取消監聽軟體鍵盤變化

在viewWillAppear監聽軟體鍵盤變化
在viewWillDisappear取消監聽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(Dialog.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(Dialog.keyboardWillHidden(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)

NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)

}

func keyboardWillShow(notification: NSNotification) {
}

func keyboardWillHidden(notification: NSNotification) {
}

Step 2: Reference TextField and 監聽TextField選取變化

如果有多個TextField時, 每個TextField的位置都不一樣, 所以我們必須得知目前被選到的TextField是哪一個.

設立變數

1
var selectedEditText : UITextField?

註冊TextField delegate

1
2
3
4
5
@IBOutlet weak var mEditText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
mEditText.delegate = self;
}

監聽TextField選取變化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension Dialog : UITextFieldDelegate {
func textFieldDidBeginEditing(textField: UITextField) {
selectedEditText = textField
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}

func textFieldDidEndEditing(textField: UITextField) {
selectedEditText = nil
}
}

Step 3: 將畫面向上調整

由於我們需要計算Dialog View在整個Frame的y軸位置, 所以必須先reference Dialog View後, 再使用mDialogView.frame.origin.y 得知y軸位置.

取得鍵盤高度

1
2
3
4
5
6
func keyboardWillShow(notification: NSNotification) {
let userInfo: NSDictionary? = notification.userInfo
let aValue: NSValue? = userInfo?.objectForKey(UIKeyboardFrameEndUserInfoKey) as? NSValue
let keyboardRect = aValue?.CGRectValue()
let keyboardHeight = keyboardRect?.size.height
}

計算輸入框和鍵盤高度的差值

由上圖得知 self.view.frame.size.height - keyboardHeight = 畫面剩餘空間

若mDialogVIew.frame.origin.y + frame.origin.y 的數值大於畫面剩餘空間的話,
表示輸入框會被鍵盤所覆蓋.

所以我們利用此公式來算出差值.

1
let offset = frame.origin.y + mDialogView.frame.origin.y + 36 - (self.view.frame.size.height - keyboardHeight!)

36 這個數值可根據文字的大小來動態調整, 或者使用輸入框的高度

使用動畫來調整畫面

1
2
3
4
5
6
7
UIView.animateWithDuration(0.3, animations: { () -> Void in
if (offset > 0) {
self.view.frame.origin.y -= offset;
} else {
self.view.frame.origin.y = 0;
}
})

Step 4: 輸入完畢後, 恢復畫面位置

1
2
3
4
5
func keyboardWillHidden(notification: NSNotification) {
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.view.frame.origin.y = 0;
})
}

執行結果

Source Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import UIKit

class Dialog: UIViewController {
@IBOutlet weak var mEditText: UITextField!
@IBOutlet weak var mDialogView: UIView!
var selectedEditText : UITextField?

override func viewDidLoad() {
super.viewDidLoad()
mEditText.delegate = self;
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(Dialog.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(Dialog.keyboardWillHidden(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)

NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWillShow(notification: NSNotification) {
let userInfo: NSDictionary? = notification.userInfo
let aValue: NSValue? = userInfo?.objectForKey(UIKeyboardFrameEndUserInfoKey) as? NSValue
let keyboardRect = aValue?.CGRectValue()
let keyboardHeight = keyboardRect?.size.height

let frame = selectedEditText!.frame
let offset = frame.origin.y + mDialogView.frame.origin.y + 36 - (self.view.frame.size.height - keyboardHeight!)

UIView.animateWithDuration(0.3, animations: { () -> Void in
if (offset > 0) {
self.view.frame.origin.y -= offset;
} else {
self.view.frame.origin.y = 0;
}
})
}


func keyboardWillHidden(notification: NSNotification) {
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.view.frame.origin.y = 0;
})
}
}

extension Dialog : UITextFieldDelegate {
func textFieldDidBeginEditing(textField: UITextField) {
selectedEditText = textField
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}

func textFieldDidEndEditing(textField: UITextField) {
selectedEditText = nil
}
}
作者

Nick Lin

發表於

2016-10-13

更新於

2023-01-18

許可協議


評論