تم إهمال uikeyboardboundsuserinfokey ، ماذا تستخدم بدلاً من ذلك؟
-
25-09-2019 - |
سؤال
أنا أعمل على تطبيق iPad باستخدام 3.2 SDK. أنا أتعامل مع الحصول على حجم لوحة المفاتيح لمنع حقول النص الخاصة بي من الاختباء خلفه.
أحصل على تحذير في Xcode -> uikeyboardboundsuserinfokey يتم إهمال ما الذي يجب أن أستخدمه بدلاً من ذلك حتى لا أحصل على هذا التحذير؟
المحلول
لقد لعبت مع الحل المعروض سابقًا ولكن لا يزال لدي مشاكل. هذا ما توصلت إليه بدلاً من ذلك:
- (void)keyboardWillShow:(NSNotification *)aNotification {
[self moveTextViewForKeyboard:aNotification up:YES];
}
- (void)keyboardWillHide:(NSNotification *)aNotification {
[self moveTextViewForKeyboard:aNotification up:NO];
}
- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];
// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
newFrame.origin.y -= keyboardFrame.size.height * (up? 1 : -1);
textView.frame = newFrame;
[UIView commitAnimations];
}
نصائح أخرى
من توثيق ل UIKeyboardBoundsUserInfoKey
:
مفتاح كائن NSValue يحتوي على cgrect يحدد مستطيل الحدود للوحة المفاتيح في إحداثيات النوافذ. هذه القيمة كافية للحصول على حجم لوحة المفاتيح. إذا كنت ترغب في الحصول على أصل لوحة المفاتيح على الشاشة (قبل أو بعد الرسوم المتحركة) ، استخدم القيم التي تم الحصول عليها من قاموس معلومات المستخدم من خلال ثوابت uikeyboardcenterbeginuserinfokey أو uikeyboardenerenduserinfokey. استخدم uikeyboardframebeginuserinfokey أو uikeyboardframeenduserinfokey المفتاح بدلاً من ذلك.
توصي Apple بتنفيذ روتين الراحة مثل هذا (والذي يمكن تنفيذه كإضافة فئة إلى UIScreen
):
+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view {
UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window];
return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil];
}
لاستعادة خصائص حجم لوحة المفاتيح المعدل النافذة.
اتبعت نهجًا مختلفًا ، يتضمن التحقق من اتجاه الجهاز:
CGRect _keyboardEndFrame;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&_keyboardEndFrame];
CGFloat _keyboardHeight = ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) ? _keyboardEndFrame.size.height : _keyboardEndFrame.size.width;
يمكنك ببساطة استخدام هذا الرمز:
//NSVale *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
//instead of Upper line we can use either next line or nextest line.
//NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
الرمز التالي يحدد مشكلة في إجابة جاي, الذي يفترض ذلك UIKeyboardWillShowNotification
لن تطلق النار مرة أخرى عندما تكون لوحة المفاتيح موجودة بالفعل.
عند الكتابة مع لوحة المفاتيح اليابانية/الصينية ، تطلق iOS إضافيًا UIKeyboardWillShowNotification
مع إطار لوحة المفاتيح الجديد على الرغم من وجود لوحة المفاتيح بالفعل ، مما يؤدي إلى ارتفاع self.textView
يتم تقليلها للمرة الثانية في الكود الأصلي.
هذا يقلل self.textView
لا شيء تقريبا. يصبح من المستحيل بعد ذلك التعافي من هذه المشكلة لأننا سنتوقع فقط واحدة UIKeyboardWillHideNotification
في المرة القادمة التي يتم فيها رفض لوحة المفاتيح.
بدلا من طرح/إضافة الارتفاع إلى self.textView
اعتمادًا على ما إذا كان يتم عرض لوحة المفاتيح/مخفية كما في الكود الأصلي ، فإن الكود التالي يحسب فقط الحد الأقصى الممكن لارتفاعه self.textView
بعد طرح ارتفاع لوحة المفاتيح على الشاشة.
هذا يفترض ذلك self.textView
من المفترض أن تملأ عرض وحدة التحكم بأكملها ، ولا توجد رؤية فرعية أخرى يجب أن تكون مرئية.
- (void)resizeTextViewWithKeyboardNotification:(NSNotification*)notif {
NSDictionary* userInfo = [notif userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrameInWindowsCoordinates;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindowsCoordinates];
[self resizeTextViewToAccommodateKeyboardFrame:keyboardFrameInWindowsCoordinates
withAnimationDuration:animationDuration
animationCurve:animationCurve];
}
- (void)resizeTextViewToAccommodateKeyboardFrame:(CGRect)keyboardFrameInWindowsCoordinates
withAnimationDuration:(NSTimeInterval)duration
animationCurve:(UIViewAnimationCurve)curve
{
CGRect fullFrame = self.view.frame;
CGRect keyboardFrameInViewCoordinates =
[self.view convertRect:keyboardFrameInWindowsCoordinates fromView:nil];
// Frame of the keyboard that intersects with the view. When keyboard is
// dismissed, the keyboard frame still has width/height, although the origin
// keeps the keyboard out of the screen.
CGRect keyboardFrameVisibleOnScreen =
CGRectIntersection(fullFrame, keyboardFrameInViewCoordinates);
// Max frame availble for text view. Assign it to the full frame first
CGRect newTextViewFrame = fullFrame;
// Deduct the the height of any keyboard that's visible on screen from
// the height of the text view
newTextViewFrame.size.height -= keyboardFrameVisibleOnScreen.size.height;
if (duration)
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
}
// Adjust the size of the text view to the new one
self.textView.frame = newTextViewFrame;
if (duration)
{
[UIView commitAnimations];
}
}
أيضًا ، لا تنسَ تسجيل إعلامات لوحة المفاتيح في الحمولة:
- (void)viewDidLoad
{
[super viewDidLoad];
NSNotificationCenter* notifCenter = [NSNotificationCenter defaultCenter];
[notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillShowNotification object:nil];
[notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillHideNotification object:nil];
}
حول تقسيم التعليمات البرمجية إلى جزأين
سبب تقسيم رمز تغيير حجم TextView إلى جزأين (resizeTextViewWithKeyboardNotification:
و resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:
) هو إصلاح مشكلة أخرى عندما تستمر لوحة المفاتيح من خلال دفعة من وحدة تحكم عرض إلى أخرى (انظر كيف يمكنني اكتشاف لوحة مفاتيح iOS عندما تبقى بين وحدات التحكم؟).
نظرًا لأن لوحة المفاتيح موجودة بالفعل قبل دفع وحدة التحكم في العرض ، فلا توجد إخطارات إضافية لوحة المفاتيح التي يتم إنشاؤها بواسطة iOS ، وبالتالي لا توجد طريقة لتغيير حجمها textView
بناءً على إعلامات لوحة المفاتيح هذه.
الرمز أعلاه (وكذلك الكود الأصلي) الذي يغير self.textView
وبالتالي ، لن تعمل إلا عند عرض لوحة المفاتيح بعد تم تحميل العرض.
الحل الخاص بي هو إنشاء مفردة تخزن إحداثيات لوحة المفاتيح الأخيرة ، وعلى - viewDidAppear:
من ViewController ، اتصل:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Resize the view if there's any keyboard presence before this
// Only call in viewDidAppear as we are unable to convertRect properly
// before view is shown
[self resizeViewToAccommodateKeyboardFrame:[[UASKeyboard sharedKeyboard] keyboardFrame]
withAnimationDuration:0
animationCurve:0];
}
UASKeyboard
هل بلدي المفرد هنا. من الناحية المثالية ، يجب أن نسمي هذا - viewWillAppear:
, ولكن في تجربتي (على الأقل على iOS 6) ، convertRect:fromView:
الطريقة التي نحتاج إلى استخدامها في resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:
لا يقوم بتحويل إطار لوحة المفاتيح بشكل صحيح إلى إحداثيات العرض قبل أن يكون العرض مرئيًا تمامًا.
فقط استخدم UIKeyboardFrameBeginUserInfoKey
أو UIKeyboardFrameEndUserInfoKey
مفتاح بدلا من UIKeyboardBoundsUserInfoKey
jason ، أنت رمز إذا كان بخير باستثناء نقطة واحدة.
في الوقت الحالي ، أنت لا تقوم في الواقع بتحريك أي شيء ، وسوف "البوب" ببساطة إلى حجمه الجديد.
عليك أن تحدد حالة تحريكها. الرسوم المتحركة هي نوع من (من الدولة)-> (إلى الدولة).
لحسن الحظ ، هناك طريقة مريحة للغاية لتحديد الوضع الحالي للعرض على أنه (من الحالة).
[UIView setAnimationBeginsFromCurrentState:YES];
إذا قمت بإضافة هذا السطر مباشرة بعد البدء: السياق: يعمل الرمز الخاص بك تمامًا.
- (CGSize)keyboardSize:(NSNotification *)aNotification {
NSDictionary *info = [aNotification userInfo];
NSValue *beginValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
CGSize keyboardSize;
if ([UIKeyboardDidShowNotification isEqualToString:[aNotification name]]) {
_screenOrientation = orientation;
if (UIDeviceOrientationIsPortrait(orientation)) {
keyboardSize = [beginValue CGRectValue].size;
} else {
keyboardSize.height = [beginValue CGRectValue].size.width;
keyboardSize.width = [beginValue CGRectValue].size.height;
}
} else if ([UIKeyboardDidHideNotification isEqualToString:[aNotification name]]) {
// We didn't rotate
if (_screenOrientation == orientation) {
if (UIDeviceOrientationIsPortrait(orientation)) {
keyboardSize = [beginValue CGRectValue].size;
} else {
keyboardSize.height = [beginValue CGRectValue].size.width;
keyboardSize.width = [beginValue CGRectValue].size.height;
}
// We rotated
} else if (UIDeviceOrientationIsPortrait(orientation)) {
keyboardSize.height = [beginValue CGRectValue].size.width;
keyboardSize.width = [beginValue CGRectValue].size.height;
} else {
keyboardSize = [beginValue CGRectValue].size;
}
}
return keyboardSize;
}
عملت هكذا
هذا هو قيود أسفل زر حفظ
@IBOutlet weak var saveBtnBottom: NSLayoutConstraint!
@IBOutlet weak var nameText: UITextField!
Inside ViewDidload
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
nameText.delegate = self
هذه هي الوظائف التي نحتاجها
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
nameText.resignFirstResponder()
return true
}
@objc func keyBoardWillShow(notification: Notification){
if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
let keyBoardRect = frame?.cgRectValue
if let keyBoardHeight = keyBoardRect?.height {
self.saveBtnBottom.constant = keyBoardHeight
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})
}
}
}
@objc func keyBoardWillHide(notification: Notification){
self.saveBtnBottom.constant = 30.0
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})
}