как я могу заставить uitextfield двигаться вверх при наличии клавиатуры - при начале редактирования?

<p>с ios sdk:</p><p>у меня есть <code>uiview</code> с <code>uitextfield</code>s, которые вызывают клавиатуру. мне нужно, чтобы я мог:</p><ol> <li><p>разрешить прокрутку содержимого <code>uiscrollview</code>, чтобы увидеть другие текстовые поля после запуска клавиатуры</p></li> <li><p>автоматически «прыгать» (путем прокрутки вверх) или сокращения</p></li> </ol><p>я знаю, что мне нужно <code>uiscrollview</code>. я попытался изменить класс моего <code>uiview</code> на <code>uiscrollview</code>, но я все еще не могу прокрутить текстовые поля вверх или вниз. </p><p>нужно ли мне <code>uiview</code> и <code>uiscrollview</code>? один входит в другой?</p><p>что необходимо реализовать, чтобы автоматически прокручивать активное текстовое поле?</p><p>в идеале, максимально возможная настройка компонентов будет выполняться в интерфейсном разработчике. я хотел бы написать код только для того, что нужно.</p><p>примечание: <code>uiview</code> (или <code>uiscrollview</code>), с которым я работаю, вызывается панелью вкладок (<code>uitabbar</code>), которая должна функционировать как обычно.</p><hr><p>правка: я добавляю полосу прокрутки только для того, когда клавиатура появляется. хотя это и не нужно, но мне кажется, что он обеспечивает лучший интерфейс, потому что тогда пользователь может, например, прокручивать и изменять текстовые поля. </p><p>у меня это работает, когда я меняю размер кадра <code>uiscrollview</code>, когда клавиатура поднимается и опускается. я просто использую: </p><pre><code>-(void)textfielddidbeginediting:(uitextfield *)textfield { //keyboard becomes visible scrollview.frame = cgrectmake(scrollview.frame.origin.x, scrollview.frame.origin.y, scrollview.frame.size.width, scrollview.frame.size.height - 215 + 50); //resize } -(void)textfielddidendediting:(uitextfield *)textfield { //keyboard will hide scrollview.frame = cgrectmake(scrollview.frame.origin.x, scrollview.frame.origin.y, scrollview.frame.size.width, scrollview.frame.size.height + 215 - 50); //resize } </code></pre><p>однако, это не автоматически «двигает вверх» или центрирует нижние текстовые поля в видимой области, что мне бы очень хотелось.</p>

<ol> <li><p><code>scrollview</code> вам понадобится только в том случае, если имеющееся у вас содержимое не помещается на экране iphone ... (. если вы добавляете <code>scrollview</code> в качестве супервизора компонентов. просто для того, чтобы <code>textfield</code> прокручивался вверх при появлении клавиатуры, тогда это не нужно.)</p></li> <li><p>для отображения <code>textfields</code>, не будучи скрытым клавиатурой, стандартным способом является перемещение вверх/вниз представления, имеющего текстовые поля, всякий раз, когда отображается клавиатура.</p></li> </ol><p>вот пример кода:</p><pre><code>#define koffset\_for\_keyboard 80.0 -(void)keyboardwillshow { // animate the current view out of the way if (self.view.frame.origin.y >= 0) { [self setviewmovedup:yes]; } else if (self.view.frame.origin.y < 0) { [self setviewmovedup:no]; } } -(void)keyboardwillhide { if (self.view.frame.origin.y >= 0) { [self setviewmovedup:yes]; } else if (self.view.frame.origin.y < 0) { [self setviewmovedup:no]; } } -(void)textfielddidbeginediting:(uitextfield *)sender { if ([sender isequal:mailtf]) { //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y >= 0) { [self setviewmovedup:yes]; } } } //method to move the view up/down whenever the keyboard is shown/dismissed -(void)setviewmovedup:(bool)movedup { [uiview beginanimations:nil context:null]; [uiview setanimationduration:0.3]; // if you want to slide up the view cgrect rect = self.view.frame; if (movedup) { // 1. move the view's origin up so that the text field that will be hidden come above the keyboard // 2. increase the size of the view so that the area behind the keyboard is covered up. rect.origin.y -= koffset\_for\_keyboard; rect.size.height += koffset\_for\_keyboard; } else { // revert back to the normal state. rect.origin.y += koffset\_for\_keyboard; rect.size.height -= koffset\_for\_keyboard; } self.view.frame = rect; [uiview commitanimations]; } - (void)viewwillappear:(bool)animated { [super viewwillappear:animated]; // register for keyboard notifications [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillshow) name:uikeyboardwillshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillhide) name:uikeyboardwillhidenotification object:nil]; } - (void)viewwilldisappear:(bool)animated { [super viewwilldisappear:animated]; // unregister for keyboard notifications while not visible. [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboardwillshownotification object:nil]; [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboardwillhidenotification object:nil]; } </code></pre>

<p>у меня также было много проблем с <code>uiscrollview</code> составлением нескольких <code>uitextfields</code>, из которых один или несколько из них были бы скрыты клавиатурой при редактировании. </p><p>вот несколько вещей, которые следует учитывать, если ваша <code>uiscrollview</code> неправильно прокручивается. </p><p>1) убедитесь, что ваш contentsize больше размера фрейма <code>uiscrollview</code>. способ понять <code>uiscrollviews</code> состоит в том, что <code>uiscrollview</code> похож на окно просмотра контента, определенного в contentsize. поэтому, когда <code>uiscrollview</code> прокручивается куда-либо, contentsize должен быть больше, чем <code>uiscrollview</code>. иначе, прокрутка не требуется, так как все, что определено в contentsize, уже видно. кстати, по умолчанию contentsize = <code>cgsizezero</code>.</p><p>2) теперь, когда вы понимаете, что <code>uiscrollview</code> действительно является окном в вашем «контенте», способ гарантировать, что клавиатура не заслоняет ваше «окно» просмотра <code>uiscrollview's</code>, состоит в изменении размера <code>uiscrollview</code>, чтобы при наличии клавиатуры вы могли размер окна <code>uiscrollview</code> соответствует исходному значению <code>uiscrollview</code> frame.size.height минус высота клавиатуры. это гарантирует, что ваше окно будет только этой маленькой видимой областью.</p><p>3) вот подвох: когда я впервые реализовал это, я подумал, что мне нужно получить <code>cgrect</code> отредактированного текстового поля и вызвать <code>uiscrollview's</code> метод scrollrectovisible. я реализовал метод <code>uitextfielddelegate</code> <code>textfielddidbeginediting</code> с помощью вызова метода <code>scrollrectovisible</code>. это на самом деле работало со странным побочным эффектом, что прокрутка<em> оснастила </em><code>uitextfield</code> в положение. долгое время я не мог понять, что это было. затем я прокомментировал метод <code>textfielddidbeginediting</code> delegate, и все это работает !! (???). как оказалось, я полагаю, что <code>uiscrollview</code> неявно выводит отредактированную в настоящее время <code>uitextfield</code> в видимое окно. моя реализация метода <code>uitextfielddelegate</code> и последующий вызов <code>scrollrectovisible</code> были излишними и стали причиной странного побочного эффекта.</p><p>итак, вот шаги для правильной прокрутки <code>uitextfield</code> в <code>uiscrollview</code> на место, когда появляется клавиатура.</p><pre><code>// implement viewdidload to do additional setup after loading the view, typically from a nib. - (void)viewdidload { [super viewdidload]; // register for keyboard notifications [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillshow:) name:uikeyboardwillshownotification object:self.view.window]; // register for keyboard notifications [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillhide:) name:uikeyboardwillhidenotification object:self.view.window]; keyboardisshown = no; //make contentsize bigger than your scrollsize (you will need to figure out for your own use case) cgsize scrollcontentsize = cgsizemake(320, 345); self.scrollview.contentsize = scrollcontentsize; } - (void)keyboardwillhide:(nsnotification *)n { nsdictionary* userinfo = [n userinfo]; // get the size of the keyboard cgsize keyboardsize = [[userinfo objectforkey:uikeyboardframeenduserinfokey] cgrectvalue].size; // resize the scrollview cgrect viewframe = self.scrollview.frame; // i'm also subtracting a constant ktabbarheight because my uiscrollview was offset by the uitabbar so really only the portion of the keyboard that is leftover pass the uitabbar is obscuring my uiscrollview. viewframe.size.height += (keyboardsize.height - ktabbarheight); [uiview beginanimations:nil context:null]; [uiview setanimationbeginsfromcurrentstate:yes]; [self.scrollview setframe:viewframe]; [uiview commitanimations]; keyboardisshown = no; } - (void)keyboardwillshow:(nsnotification *)n { // this is an ivar i'm using to ensure that we do not do the frame size adjustment on the `uiscrollview` if the keyboard is already shown. this can happen if the user, after fixing editing a `uitextfield`, scrolls the resized `uiscrollview` to another `uitextfield` and attempts to edit the next `uitextfield`. if we were to resize the `uiscrollview` again, it would be disastrous. note: the keyboard notification will fire even when the keyboard is already shown. if (keyboardisshown) { return; } nsdictionary* userinfo = [n userinfo]; // get the size of the keyboard cgsize keyboardsize = [[userinfo objectforkey:uikeyboardframeenduserinfokey] cgrectvalue].size; // resize the noteview cgrect viewframe = self.scrollview.frame; // i'm also subtracting a constant ktabbarheight because my uiscrollview was offset by the uitabbar so really only the portion of the keyboard that is leftover pass the uitabbar is obscuring my uiscrollview. viewframe.size.height -= (keyboardsize.height - ktabbarheight); [uiview beginanimations:nil context:null]; [uiview setanimationbeginsfromcurrentstate:yes]; [self.scrollview setframe:viewframe]; [uiview commitanimations]; keyboardisshown = yes; } </code></pre><ol> <li>зарегистрируйтесь для получения уведомлений клавиатуры на <code>viewdidload</code></li> <li>отмените регистрацию для клавиатурных сообщений на <code>viewdidunload</code></li> <li>убедитесь, что <code>contentsize</code> установлен и больше, чем ваш <code>uiscrollview</code> в <code>viewdidload</code></li> <li><em> shrink </em><code>uiscrollview</code>, когда клавиатура присутствует</li> <li><em> возврат назад </em><code>uiscrollview</code>, когда клавиатура исчезнет.</li> <li>используйте ivar, чтобы определить, отображается ли уже клавиатура на экране, поскольку уведомления клавиатуры отправляются каждый раз, когда вкладка <code>uitextfield</code> присутствует, даже если клавиатура уже присутствует, чтобы избежать<em> сокращения </em><code>uiscrollview</code>, когда она уже<em> уменьшена </em></li> </ol><p>следует отметить, что <code>uikeyboardwillshownotification</code> будет срабатывать, даже если клавиатура уже находится на экране, когда вы нажимаете на другую <code>uitextfield</code>. я позаботился об этом, используя ivar, чтобы избежать изменения размера <code>uiscrollview</code>, когда клавиатура уже находится на экране. непреднамеренное изменение размера <code>uiscrollview</code>, когда клавиатура уже есть, будет катастрофическим!</p><p>надеюсь, этот код избавит некоторых из вас от головной боли. </p>

<p>на самом деле лучше всего использовать реализацию apple, как указано в <a href="http://developer.apple.com/library/ios/#documentation/stringstextfonts/conceptual/textandwebiphoneos/keyboardmanagement/keyboardmanagement.html%23//apple\_ref/doc/uid/tp40009542-ch5-sw7">docs</a> . однако код, который они предоставляют, неисправен. замените часть, найденную в <code>keyboardwasshown:</code> чуть ниже комментариев, на следующую:</p><pre><code>nsdictionary* info = [anotification userinfo]; cgrect keypadframe=[[uiapplication sharedapplication].keywindow convertrect:[[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue] fromview:self.view]; cgsize kbsize =keypadframe.size; cgrect activerect=[self.view convertrect:activefield.frame fromview:activefield.superview]; cgrect arect = self.view.bounds; arect.size.height -= (kbsize.height); cgpoint origin = activerect.origin; origin.y -= backscrollview.contentoffset.y; if (!cgrectcontainspoint(arect, origin)) { cgpoint scrollpoint = cgpointmake(0.0,cgrectgetmaxy(activerect)-(arect.size.height)); [backscrollview setcontentoffset:scrollpoint animated:yes]; } </code></pre><p>проблемы с кодом apple заключаются в следующем: (1) они всегда вычисляют, находится ли точка в рамке представления, но это <code>scrollview</code>, поэтому она, возможно, уже прокрутилась, и вам необходимо учитывать это смещение:</p><pre><code>origin.y -= scrollview.contentoffset.y </code></pre><p>(2) они смещают contentoffset на высоту клавиатуры, но мы хотим наоборот (мы хотим сместить <code>contentoffset</code> на высоту, которая видна на экране, а не на то, что нет):</p><pre><code>activefield.frame.origin.y-(arect.size.height) </code></pre>

<p>в <code>textfielddidbegineditting</code> и в <code>textfielddidendediting</code> вызовите функцию <code>[self animatetextfield:textfield up:yes]</code> так: </p><pre><code>-(void)textfielddidbeginediting:(uitextfield *)textfield { [self animatetextfield:textfield up:yes]; } - (void)textfielddidendediting:(uitextfield *)textfield { [self animatetextfield:textfield up:no]; } -(void)animatetextfield:(uitextfield*)textfield up:(bool)up { const int movementdistance = -130; // tweak as needed const float movementduration = 0.3f; // tweak as needed int movement = (up ? movementdistance : -movementdistance); [uiview beginanimations: @"animatetextfield" context: nil]; [uiview setanimationbeginsfromcurrentstate: yes]; [uiview setanimationduration: movementduration]; self.view.frame = cgrectoffset(self.view.frame, 0, movement); [uiview commitanimations]; } </code></pre><p>я надеюсь, что этот код поможет вам. </p><p>в свифт 2</p><pre><code>func animatetextfield(textfield: uitextfield, up: bool) { let movementdistance:cgfloat = -130 let movementduration: double = 0.3 var movement:cgfloat = 0 if up { movement = movementdistance } else { movement = -movementdistance } uiview.beginanimations("animatetextfield", context: nil) uiview.setanimationbeginsfromcurrentstate(true) uiview.setanimationduration(movementduration) self.view.frame = cgrectoffset(self.view.frame, 0, movement) uiview.commitanimations() } func textfielddidbeginediting(textfield: uitextfield) { self.animatetextfield(textfield, up:true) } func textfielddidendediting(textfield: uitextfield) { self.animatetextfield(textfield, up:false) } </code></pre><p>свифт 3</p><pre><code> func animatetextfield(textfield: uitextfield, up: bool) { let movementdistance:cgfloat = -130 let movementduration: double = 0.3 var movement:cgfloat = 0 if up { movement = movementdistance } else { movement = -movementdistance } uiview.beginanimations("animatetextfield", context: nil) uiview.setanimationbeginsfromcurrentstate(true) uiview.setanimationduration(movementduration) self.view.frame = self.view.frame.offsetby(dx: 0, dy: movement) uiview.commitanimations() } func textfielddidbeginediting(textfield: uitextfield) { self.animatetextfield(textfield: textfield, up:true) } func textfielddidendediting(textfield: uitextfield) { self.animatetextfield(textfield: textfield, up:false) } </code></pre>

<p><strong> просто с помощью textfields: </strong></p><p>1a) использование <code>interface builder</code>: выберите все textfields => edit => embed in => scrollview</p><p>1b) внедрение textfields в uiscrollview, называемое scrollview.</p><p>2) установите <code>uitextfielddelegate</code></p><p>3) установите каждый <code>textfield.delegate = self;</code> (или создайте соединения в <code>interface builder</code>)</p><p>4)<strong> копировать/вставить: </strong></p><pre><code>- (void)textfielddidbeginediting:(uitextfield *)textfield { cgpoint scrollpoint = cgpointmake(0, textfield.frame.origin.y); [scrollview setcontentoffset:scrollpoint animated:yes]; } - (void)textfielddidendediting:(uitextfield *)textfield { [scrollview setcontentoffset:cgpointzero animated:yes]; } </code></pre>

<p>для <strong>universal solution</strong>, здесь был мой подход к реализации <a href="http://github.com/hackiftekhar/iqkeyboardmanager">iqkeyboardmanager</a> .</p><p><img src="https://i.stack.imgur.com/gym7k.png" alt="enter image description here"></p><p><strong>step1: -</strong> я добавил глобальные уведомления о <code>uitextfield</code>, <code>uitextview</code> и <code>uikeyboard</code> в одноэлементном классе. я называю это <a href="http://github.com/hackiftekhar/iqkeyboardmanager">iqkeyboardmanager</a> .</p><p><strong>step2: -</strong> если найдены уведомления <code>uikeyboardwillshownotification</code>, <code>uitextfieldtextdidbegineditingnotification</code> или <code>uitextviewtextdidbegineditingnotification</code>, я пытаюсь получить экземпляр <code>topmostviewcontroller</code> из иерархии <code>uiwindow.rootviewcontroller</code>. для того, чтобы правильно раскрыть <code>uitextfield</code><strong><code>uitextview</code> на нем, необходимо отрегулировать кадр <code>topmostviewcontroller.view</code>.</p><p>\_/step3: -</strong> я рассчитал ожидаемое расстояние перемещения <code>topmostviewcontroller.view</code> относительно первого ответившего <code>uitextfield</code><strong><code>uitextview</code>.</p><p>\_/step4: -</strong> я переместил <code>topmostviewcontroller.view.frame</code> вверх/вниз в соответствии с ожидаемым расстоянием перемещения.</p><p><strong>step5: -</strong> если найдено уведомление <code>uikeyboardwillhidenotification</code>, <code>uitextfieldtextdidendeditingnotification</code> или <code>uitextviewtextdidendeditingnotification</code>, я снова пытаюсь получить экземпляр <code>topmostviewcontroller</code> из иерархии <code>uiwindow.rootviewcontroller</code>.</p><p><strong>step6: -</strong> я вычислил нарушенное расстояние <code>topmostviewcontroller.view</code>, которое необходимо восстановить в исходное положение.</p><p><strong>step7: -</strong> я восстановил <code>topmostviewcontroller.view.frame</code> в соответствии с нарушенным расстоянием.</p><p><strong>step8: -</strong> я создал экземпляр singleton <a href="http://github.com/hackiftekhar/iqkeyboardmanager">iqkeyboardmanager</a> экземпляр класса при загрузке приложения, поэтому каждое <code>uitextfield</code><strong><code>uitextview</code> в приложении будет автоматически корректироваться в соответствии с ожидаемым расстоянием перемещения.</p><p>это все <a href="http://github.com/hackiftekhar/iqkeyboardmanager">iqkeyboardmanager</a> сделать для вас с \_/нет line of code</strong> действительно! нужно только перетащить связанный исходный файл в проект. <a href="http://github.com/hackiftekhar/iqkeyboardmanager">iqkeyboardmanager</a> также поддерживает <strong>ориентация устройства</strong>, <strong>автоматическое управление uitoolbar</strong>, <strong>keybkeyboarddistancefromtextfield</strong> и многое другое, чем вы думаете.</p>

<p>я собрал универсальный раскрывающийся подкласс <code>uiscrollview</code>, <code>uitableview</code> и даже <code>uicollectionview</code>, который заботится о перемещении всех текстовых полей внутри него с клавиатуры.</p><p>когда клавиатура должна появиться, подкласс найдет подпредставление, которое должно быть отредактировано, и отрегулирует его фрейм и смещение содержимого, чтобы убедиться, что представление является видимым, с анимацией, соответствующей всплывающему окну клавиатуры. когда клавиатура исчезает, она восстанавливает свой прежний размер.</p><p>он должен работать практически с любой настройкой, либо с интерфейсом на основе <code>uitableview</code>, либо с интерфейсом, состоящим из представлений, размещенных вручную.</p><p>вот это: <a href="http://atastypixel.com/blog/a-drop-in-universal-solution-for-moving-text-fields-out-of-the-way-of-the-keyboard/">решение для перемещения текстовых полей с клавиатуры</a> </p>

<blockquote> <p>для<strong> swift </strong>программисты:</p> </blockquote><p>это все сделает за вас, просто поместите их в ваш класс контроллера представления и реализуйте <code>uitextfielddelegate</code> для вашего контроллера представления и установите делегата textfield равным <code>self</code> </p><pre><code>textfield.delegate = self // setting delegate of your uitextfield to self </code></pre><p>реализуйте методы обратного вызова делегата:</p><pre><code>func textfielddidbeginediting(textfield: uitextfield) { animateviewmoving(true, movevalue: 100) } func textfielddidendediting(textfield: uitextfield) { animateviewmoving(false, movevalue: 100) } // lifting the view up func animateviewmoving (up:bool, movevalue :cgfloat){ let movementduration:nstimeinterval = 0.3 let movement:cgfloat = ( up ? -movevalue : movevalue) uiview.beginanimations( "animateview", context: nil) uiview.setanimationbeginsfromcurrentstate(true) uiview.setanimationduration(movementduration ) self.view.frame = cgrectoffset(self.view.frame, 0, movement) uiview.commitanimations() } </code></pre>

<p>уже есть много ответов, но все же ни одно из вышеприведенных решений не имело всех причудливых средств позиционирования, необходимых для «идеальной» безошибочной, обратно совместимой и не мерцающей анимации. (ошибка при анимации frame/bounds и contentoffset вместе, различные ориентации интерфейса, разделенная клавиатура ipad, ...)<br/> позвольте мне поделиться своим решением: <br/> (при условии, что вы установили <code>uikeyboardwill(show|hide)notification</code>)</p><pre><code>// called when uikeyboardwillshownotification is sent - (void)keyboardwillshow:(nsnotification*)notification { // if we have no view or are not visible in any window, we don't care if (!self.isviewloaded || !self.view.window) { return; } nsdictionary *userinfo = [notification userinfo]; cgrect keyboardframeinwindow; [[userinfo objectforkey:uikeyboardframeenduserinfokey] getvalue:&keyboardframeinwindow]; // the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view cgrect keyboardframeinview = [self.view convertrect:keyboardframeinwindow fromview:nil]; cgrect scrollviewkeyboardintersection = cgrectintersection(\_scrollview.frame, keyboardframeinview); uiedgeinsets newcontentinsets = uiedgeinsetsmake(0, 0, scrollviewkeyboardintersection.size.height, 0); // this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userinfo-dictionary. [uiview beginanimations:nil context:null]; [uiview setanimationduration:[[userinfo objectforkey:uikeyboardanimationdurationuserinfokey] doublevalue]]; [uiview setanimationcurve:[[userinfo objectforkey:uikeyboardanimationcurveuserinfokey] intvalue]]; \_scrollview.contentinset = newcontentinsets; \_scrollview.scrollindicatorinsets = newcontentinsets; /* * depending on visual layout, \_focusedcontrol should either be the input field (uitextfield,..) or another element * that should be visible, e.g. a purchase button below an amount text field * it makes sense to set \_focusedcontrol in delegates like -textfieldshouldbeginediting: if you have multiple input fields */ if (\_focusedcontrol) { cgrect controlframeinscrollview = [\_scrollview convertrect:\_focusedcontrol.bounds fromview:\_focusedcontrol]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview controlframeinscrollview = cgrectinset(controlframeinscrollview, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view. cgfloat controlvisualoffsettotopofscrollview = controlframeinscrollview.origin.y - \_scrollview.contentoffset.y; cgfloat controlvisualbottom = controlvisualoffsettotopofscrollview + controlframeinscrollview.size.height; // this is the visible part of the scroll view that is not hidden by the keyboard cgfloat scrollviewvisibleheight = \_scrollview.frame.size.height - scrollviewkeyboardintersection.size.height; if (controlvisualbottom > scrollviewvisibleheight) { // check if the keyboard will hide the control in question // scroll up until the control is in place cgpoint newcontentoffset = \_scrollview.contentoffset; newcontentoffset.y += (controlvisualbottom - scrollviewvisibleheight); // make sure we don't set an impossible offset caused by the "nice visual offset" // if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies newcontentoffset.y = min(newcontentoffset.y, \_scrollview.contentsize.height - scrollviewvisibleheight); [\_scrollview setcontentoffset:newcontentoffset animated:no]; // animated:no because we have created our own animation context around this code } else if (controlframeinscrollview.origin.y < \_scrollview.contentoffset.y) { // if the control is not fully visible, make it so (useful if the user taps on a partially visible input field cgpoint newcontentoffset = \_scrollview.contentoffset; newcontentoffset.y = controlframeinscrollview.origin.y; [\_scrollview setcontentoffset:newcontentoffset animated:no]; // animated:no because we have created our own animation context around this code } } [uiview commitanimations]; } // called when the uikeyboardwillhidenotification is sent - (void)keyboardwillhide:(nsnotification*)notification { // if we have no view or are not visible in any window, we don't care if (!self.isviewloaded || !self.view.window) { return; } nsdictionary *userinfo = notification.userinfo; [uiview beginanimations:nil context:null]; [uiview setanimationduration:[[userinfo valueforkey:uikeyboardanimationdurationuserinfokey] doublevalue]]; [uiview setanimationcurve:[[userinfo valueforkey:uikeyboardanimationcurveuserinfokey] intvalue]]; // undo all that keyboardwillshow-magic // the scroll view will adjust its contentoffset apropriately \_scrollview.contentinset = uiedgeinsetszero; \_scrollview.scrollindicatorinsets = uiedgeinsetszero; [uiview commitanimations]; } </code></pre>

<p>шиун сказал: «как выяснилось, я считаю, что uiscrollview фактически неявно переносит редактируемый в настоящий момент uitextfield в видимое окно». это похоже на ios 3.1.3, но не 3.2, 4.0 или 4.1. мне пришлось добавить явный scrollrecttovisible, чтобы сделать uitextfield видимым на ios> = 3.2.</p>

<p>необходимо учитывать, хотите ли вы когда-нибудь использовать <code>uitextfield</code> самостоятельно. я не сталкивался ни с какими хорошо разработанными приложениями для iphone, которые фактически используют <code>uitextfields</code> вне <code>uitableviewcells</code>.</p><p>это будет некоторая дополнительная работа, но я рекомендую вам реализовать все представления ввода данных в виде таблицы. добавьте <code>uitextview</code> к вашему <code>uitableviewcells</code>.</p>

<p> <a href="http://developer.apple.com/library/ios/#documentation/stringstextfonts/conceptual/textandwebiphoneos/keyboardmanagement/keyboardmanagement.html">этот</a> документ подробно описывает решение этой проблемы. посмотрите на исходный код в разделе «перемещение содержимого, расположенного под клавиатурой». это довольно просто.</p><p>правка: заметил, что в примере есть крошечный глюк. возможно, вы захотите прослушать <code>uikeyboardwillhidenotification</code> вместо <code>uikeyboarddidhidenotification</code>. в противном случае представление прокрутки позади клавиатуры будет обрезано на время анимации закрытия клавиатуры.</p>

<p><strong> самое простое решение найдено </strong> </p><pre><code>- (void)textfielddidbeginediting:(uitextfield *)textfield { [self animatetextfield: textfield up: yes]; } - (void)textfielddidendediting:(uitextfield *)textfield { [self animatetextfield: textfield up: no]; } - (void) animatetextfield: (uitextfield*) textfield up: (bool) up { const int movementdistance = 80; // tweak as needed const float movementduration = 0.3f; // tweak as needed int movement = (up ? -movementdistance : movementdistance); [uiview beginanimations: @"anim" context: nil]; [uiview setanimationbeginsfromcurrentstate: yes]; [uiview setanimationduration: movementduration]; self.view.frame = cgrectoffset(self.view.frame, 0, movement); [uiview commitanimations]; } </code></pre>

<p>небольшое исправление, которое работает для многих uitextfields</p><pre><code>#pragma mark uikeyboard handling #define kmin 150 -(void)textfielddidbeginediting:(uitextfield *)sender { if (currtextfield) { [currtextfield release]; } currtextfield = [sender retain]; //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y + currtextfield.frame.origin. y >= kmin) { [self setviewmovedup:yes]; } } //method to move the view up/down whenever the keyboard is shown/dismissed -(void)setviewmovedup:(bool)movedup { [uiview beginanimations:nil context:null]; [uiview setanimationduration:0.3]; // if you want to slide up the view cgrect rect = self.view.frame; if (movedup) { // 1. move the view's origin up so that the text field that will be hidden come above the keyboard // 2. increase the size of the view so that the area behind the keyboard is covered up. rect.origin.y = kmin - currtextfield.frame.origin.y ; } else { // revert back to the normal state. rect.origin.y = 0; } self.view.frame = rect; [uiview commitanimations]; } - (void)keyboardwillshow:(nsnotification *)notif { //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately if ([currtextfield isfirstresponder] && currtextfield.frame.origin.y + self.view.frame.origin.y >= kmin) { [self setviewmovedup:yes]; } else if (![currtextfield isfirstresponder] && currtextfield.frame.origin.y + self.view.frame.origin.y < kmin) { [self setviewmovedup:no]; } } - (void)keyboardwillhide:(nsnotification *)notif { //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately if (self.view.frame.origin.y < 0 ) { [self setviewmovedup:no]; } } - (void)viewwillappear:(bool)animated { // register for keyboard notifications [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillshow:) name:uikeyboardwillshownotification object:self.view.window]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillhide:) name:uikeyboardwillhidenotification object:self.view.window]; } - (void)viewwilldisappear:(bool)animated { // unregister for keyboard notifications while not visible. [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboardwillshownotification object:nil]; } </code></pre>

<p>код rpdp успешно перемещает текстовое поле с клавиатуры. но когда вы прокручиваете до верха после использования и отклонения клавиатуры, верхняя часть прокручивается вверх из вида. это верно для симулятора и устройства. чтобы прочитать содержимое в верхней части этого представления, необходимо перезагрузить представление.</p><p>разве его следующий код не должен вернуть представление вниз?</p><pre><code>else { // revert back to the normal state. rect.origin.y += koffset\_for\_keyboard; rect.size.height -= koffset\_for\_keyboard; } </code></pre>

<p>я не уверен, что перемещение представления вверх является правильным подходом, я сделал это другим способом, изменив размер uiscrollview. я объяснил это в деталях на небольшой <a href="http://www.iphonesampleapps.com/2009/12/adjust-uitextfield-hidden-behind-keyboard-with-uiscrollview/">статья</a> </p>

<p>чтобы вернуть исходное состояние просмотра, добавьте:</p><pre><code>-(void)textfielddidendediting:(uitextfield *)sender { //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y < 0) { [self setviewmovedup:no]; } } </code></pre>

<p>там так много решений, но я потратил несколько часов, прежде чем начать работать. итак, я поместил этот код здесь (просто вставьте в проект, никаких изменений не нужно):</p><pre><code>@interface registrationviewcontroller : uiviewcontroller <uitextfielddelegate>{ uitextfield* activefield; uiscrollview *scrollview; } @end - (void)viewdidload { [super viewdidload]; scrollview = [[uiscrollview alloc] initwithframe:self.view.frame]; //scrool view must be under main view - swap it uiview* natview = self.view; [self setview:scrollview]; [self.view addsubview:natview]; cgsize scrollviewcontentsize = self.view.frame.size; [scrollview setcontentsize:scrollviewcontentsize]; [self registerforkeyboardnotifications]; } - (void)viewdidunload { activefield = nil; scrollview = nil; [self unregisterforkeyboardnotifications]; [super viewdidunload]; } - (void)registerforkeyboardnotifications { [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillshown:) name:uikeyboardwillshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillbehidden:) name:uikeyboardwillhidenotification object:nil]; } -(void)unregisterforkeyboardnotifications { [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboardwillshownotification object:nil]; // unregister for keyboard notifications while not visible. [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboardwillhidenotification object:nil]; } - (void)keyboardwillshown:(nsnotification*)anotification { nsdictionary* info = [anotification userinfo]; cgsize kbsize = [[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue].size; cgrect frame = self.view.frame; frame.size.height -= kbsize.height; cgpoint forigin = activefield.frame.origin; forigin.y -= scrollview.contentoffset.y; forigin.y += activefield.frame.size.height; if (!cgrectcontainspoint(frame, forigin) ) { cgpoint scrollpoint = cgpointmake(0.0, activefield.frame.origin.y + activefield.frame.size.height - frame.size.height); [scrollview setcontentoffset:scrollpoint animated:yes]; } } - (void)keyboardwillbehidden:(nsnotification*)anotification { [scrollview setcontentoffset:cgpointzero animated:yes]; } - (void)textfielddidbeginediting:(uitextfield *)textfield { activefield = textfield; } - (void)textfielddidendediting:(uitextfield *)textfield { activefield = nil; } -(bool) textfieldshouldreturn:(uitextfield *)textfield { [textfield resignfirstresponder]; return yes; } </code></pre><p>п.с .: надеюсь, код поможет кому-то быстро добиться желаемого эффекта. (xcode 4.5)</p>

<p>@ user271753</p><p>чтобы вернуться к исходному виду, добавьте:</p><pre><code>-(bool)textfieldshouldreturn:(uitextfield *)textfield{ [textfield resignfirstresponder]; [self setviewmovedup:no]; return yes; } </code></pre>

<p>попробуйте этот короткий трюк.</p><pre><code>- (void)textfielddidbeginediting:(uitextfield *)textfield { [self animatetextfield: textfield up: yes]; } - (void)textfielddidendediting:(uitextfield *)textfield { [self animatetextfield: textfield up: no]; } - (void) animatetextfield: (uitextfield*) textfield up: (bool) up { const int movementdistance = textfield.frame.origin.y / 2; // tweak as needed const float movementduration = 0.3f; // tweak as needed int movement = (up ? -movementdistance : movementdistance); [uiview beginanimations: @"anim" context: nil]; [uiview setanimationbeginsfromcurrentstate: yes]; [uiview setanimationduration: movementduration]; self.view.frame = cgrectoffset(self.view.frame, 0, movement); [uiview commitanimations]; } </code></pre>

<p>для перемещения рамки просмотра не требуется представление с прокруткой. вы можете изменить кадр представления <code>viewcontroller's</code> так, чтобы весь вид перемещался вверх настолько, чтобы поместить текстовое поле первого респондента над клавиатурой. когда я столкнулся с этой проблемой, я создал подкласс <code>uiviewcontroller</code>, который делает это. он наблюдает за тем, чтобы на клавиатуре появлялось уведомление, и обнаруживал первое подпредставление респондента и (при необходимости) он анимировал основной вид вверх настолько, чтобы первый респондент находился над клавиатурой. когда клавиатура прячется, она оживляет вид назад, где она была.</p><p>чтобы использовать этот подкласс, сделайте свой пользовательский контроллер представления подклассом <a href="https://github.com/progrmr/sdk\_utilities/blob/master/gm\_subclasses/gmkeyboardvc.m">gmkeyboardvc</a> , и он наследует эту функцию (просто убедитесь, что вы реализуете <code>viewwillappear</code> и <code>viewwilldisappear</code>, они должны вызывать super). класс на <a href="https://github.com/progrmr/sdk\_utilities/tree/master/gm\_subclasses">github</a> .</p>

<p>в соответствии с <a href="http://developer.apple.com/library/ios/#documentation/stringstextfonts/conceptual/textandwebiphoneos/keyboardmanagement/keyboardmanagement.html#//apple\_ref/doc/uid/tp40009542-ch5-sw7">документами</a> , начиная с ios 3.0, класс <code>uitableviewcontroller</code> автоматически изменяет размеры и перемещает свое табличное представление, когда есть встроенное редактирование текстовых полей. я думаю, что недостаточно поместить текстовое поле внутри <code>uitableviewcell</code>, как указали некоторые.</p><p>от <a href="http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/tableview\_iphone/tableviewanddatamodel/tableviewanddatamodel.html#//apple\_ref/doc/uid/tp40007451-ch5-sw7">документы</a> :</p><blockquote> <p>контроллер табличного представления поддерживает встроенное редактирование строк табличного представления; если, например, строки имеют встроенные текстовые поля в режиме редактирования, это прокручивает редактируемую строку над виртуальной клавиатурой отображается.</p> </blockquote>

<p>вот хакерское решение, которое я придумал для конкретного макета. это решение похоже на решение мэтта галлахера в том, что оно прокручивает раздел в поле зрения. я все еще новичок в разработке для iphone и не знаю, как работают макеты. таким образом, это взломать.</p><p>моя реализация должна была поддерживать прокрутку при нажатии на поле, а также прокрутку, когда пользователь выбирает следующий на клавиатуре.</p><p>у меня был uiview с высотой 775. элементы управления распределены в основном группами по 3 на большом пространстве. я закончил со следующим макетом ib.</p><pre><code>uiview -> uiscrollview -> [ui components] </code></pre><p>здесь приходит взломать</p><p>я установил высоту uiscrollview на 500 единиц больше, чем фактический макет (1250). затем я создал массив с абсолютными позициями, к которым нужно прокрутиться, и простой функцией, чтобы получить их на основе номера тега ib.</p><pre><code>static nsinteger steprange[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410 }; nsinteger getscrollpos(nsinteger i) { if (i < txt\_field\_index\_min || i > txt\_field\_index\_max) { return 0 ; return steprange[i] ; } </code></pre><p>теперь все, что вам нужно сделать, это использовать следующие две строки кода в textfielddidbeginediting и textfieldshouldreturn (последняя, если вы создаете навигацию по следующему полю)</p><pre><code>cgpoint point = cgpointmake(0, getscrollpos(textfield.tag)) ; [self.scrollview setcontentoffset:point animated:yes] ; </code></pre><p>пример.</p><pre><code>- (void) textfielddidbeginediting:(uitextfield *)textfield { cgpoint point = cgpointmake(0, getscrollpos(textfield.tag)) ; [self.scrollview setcontentoffset:point animated:yes] ; } - (bool)textfieldshouldreturn:(uitextfield *)textfield { nsinteger nexttag = textfield.tag + 1; uiresponder* nextresponder = [textfield.superview viewwithtag:nexttag]; if (nextresponder) { [nextresponder becomefirstresponder]; cgpoint point = cgpointmake(0, getscrollpos(nexttag)) ; [self.scrollview setcontentoffset:point animated:yes] ; } else{ [textfield resignfirstresponder]; } return yes ; } </code></pre><p>этот метод не «прокручивает назад», как другие методы. это не было требованием. опять же, это было для довольно «высокого» uiview, и у меня не было дней, чтобы изучить механизмы внутреннего макета.</p>

<blockquote> <p>здесь <strong>я нашел самое простое решение для обработки клавиатуры.</strong></p> </blockquote><p>вам нужно просто скопировать и вставить ниже пример кода и изменить текстовое поле или любое представление, которое вы хотите переместить вверх.</p><p><strong>шаг 1</strong> </p><blockquote> <p>просто скопируйте и вставьте ниже два метода в свой контроллер</p> </blockquote><pre><code>- (void)registerforkeyboardnotifications { [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwasshown:) name:uikeyboarddidshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillbehidden:) name:uikeyboardwillhidenotification object:nil]; } - (void)deregisterfromkeyboardnotifications { [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboarddidhidenotification object:nil]; [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboardwillhidenotification object:nil]; } </code></pre><p><strong>шаг 2</strong> </p><blockquote> <p>зарегистрировать и отменить регистрацию уведомлений клавиатуры в <strong>viewwillappear</strong> и методы <strong>viewwilldisappear</strong> соответственно.</p> </blockquote><pre><code>- (void)viewwillappear:(bool)animated { [super viewwillappear:animated]; [self registerforkeyboardnotifications]; } - (void)viewwilldisappear:(bool)animated { [self deregisterfromkeyboardnotifications]; [super viewwilldisappear:animated]; } </code></pre><p><strong>шаг 3</strong> </p><blockquote> <p>здесь идет часть души, просто замени свое текстовое поле и измени высота, на сколько вы хотите двигаться вверх.</p> </blockquote><pre><code>- (void)keyboardwasshown:(nsnotification *)notification { nsdictionary* info = [notification userinfo]; cgsize currentkeyboardsize = [[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue].size; //you need replace your textfield instance here cgpoint textfieldorigin = self.tokenforplacefield.frame.origin; cgfloat textfieldheight = self.tokenforplacefield.frame.size.height; cgrect visiblerect = self.view.frame; visiblerect.size.height -= currentkeyboardsize.height; if (!cgrectcontainspoint(visiblerect, textfieldorigin)) { //you can add yor desired height how much you want move keypad up, by replacing "textfieldheight" below cgpoint scrollpoint = cgpointmake(0.0, textfieldorigin.y - visiblerect.size.height + textfieldheight); //replace textfieldheight to currentkeyboardsize.height, if you want to move up with more height [self.scrollview setcontentoffset:scrollpoint animated:yes]; } } - (void)keyboardwillbehidden:(nsnotification *)notification { [self.scrollview setcontentoffset:cgpointzero animated:yes]; } </code></pre><p><strong>reference</strong>: хорошо, <a href="http://ios-blog.co.uk/tutorials/how-to-make-uitextfield-move-up-when-keyboard-is-present/"><strong>пожалуйста, оцените этого парня</strong></a> , который поделился этим прекрасным фрагментом кода, чистым решением.</p><p>надеюсь, это кому-то очень поможет.</p>

<p><strong>swift 4</strong>. </p><p><strong>вы можете легко перемещаться вверх и вниз <code>uitextfield</code> или <code>uiview</code> с <code>uikeyboard</code> с <code>animation</code></strong> <a href="https://i.stack.imgur.com/7xukg.png"> <img src="https://i.stack.imgur.com/7xukg.png" alt="enter image description here"> </a> </p><pre><code>import uikit class viewcontroller: uiviewcontroller, uitextfielddelegate { @iboutlet var textfield: uitextfield! @iboutlet var chatview: uiview! override func viewdidload() { super.viewdidload() notificationcenter.default.addobserver(self, selector: #selector(keyboardwillchange), name: .uikeyboardwillchangeframe, object: nil) } override func touchesbegan(\_ touches: set<uitouch>, with event: uievent?) { textfield.resignfirstresponder() } @objc func keyboardwillchange(notification: nsnotification) { let duration = notification.userinfo![uikeyboardanimationdurationuserinfokey] as! double let curve = notification.userinfo![uikeyboardanimationcurveuserinfokey] as! uint let curframe = (notification.userinfo![uikeyboardframebeginuserinfokey] as! nsvalue).cgrectvalue let targetframe = (notification.userinfo![uikeyboardframeenduserinfokey] as! nsvalue).cgrectvalue let deltay = targetframe.origin.y - curframe.origin.y print("deltay",deltay) uiview.animatekeyframes(withduration: duration, delay: 0.0, options: uiviewkeyframeanimationoptions(rawvalue: curve), animations: { self.chatview.frame.origin.y+=deltay // here you can change uiview to uitextfield },completion: nil) } func textfieldshouldreturn(\_ textfield: uitextfield) -> bool { textfield.resignfirstresponder() return true } } </code></pre>

<p>в поисках хорошего учебника для начинающих по этому вопросу, нашел лучший учебник <a href="http://www.mobisoftinfotech.com/blog/iphone/iphone-uitextfield-tutorial-handling-keyboard-interactions/">здесь</a> .</p><p>в примере <code>miscrollview.h</code> внизу урока обязательно ставьте пробел в</p><pre><code>@property (nonatomic, retain) id backgroundtapdelegate; </code></pre><p>как вы видите.</p>

<p>когда <code>uitextfield</code> находится в <code>uitableviewcell</code>, прокрутка должна быть установлена автоматически.</p><p>если это не так, вероятно, из-за неправильного кода/настройки таблицы.</p><p>например, когда я перезагрузил свою длинную таблицу с одним <code>uitextfield</code> внизу, как показано ниже, </p><pre><code>-(void) viewwillappear:(bool)animated { [self.tableview reloaddata]; } </code></pre><p>затем мое текстовое поле внизу было скрыто клавиатурой, которая появилась, когда я щелкнул внутри текстового поля.</p><p>чтобы исправить это, я должен был сделать это -</p><pre><code>-(void) viewwillappear:(bool)animated { //add the following line to fix issue [super viewwillappear:animated]; [self.tableview reloaddata]; } </code></pre>

<p>используйте это третье лицо, вам не нужно писать даже одну строку</p><p> <a href="https://github.com/hackiftekhar/iqkeyboardmanager">https://github.com/hackiftekhar/iqkeyboardmanager</a> </p><p>загрузите проект и перетащите iqkeyboardmanager в свой проект . если вы обнаружите какую-либо проблему, прочтите документ readme.</p><p>ребята действительно убрать головную боль, чтобы управлять клавиатурой ..</p><p>спасибо и удачи!</p>

<p><strong> примечание </strong>: этот ответ предполагает, что ваш textfield находится в scrollview.</p><p>я предпочитаю иметь дело с этим, используя scrollcontentinset и scrollcontentoffset вместо того, чтобы возиться с кадрами моего представления.</p><p>сначала давайте послушаем уведомления клавиатуры </p><pre><code>//call this from viewwillappear -(void)addkeyboardnotifications { [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillshow:) name:uikeyboardwillshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillhide:) name:uikeyboardwillhidenotification object:nil]; } //call this from viewwilldisappear -(void)removekeyboardnotifications{ [[nsnotificationcenter default center] removeobserver:self name:uikeyboardwillshownotification object:nil]; [[nsnotificationcenter defaultcenter] removeobserver:self name:uikeyboardwillhidenotification object:nil]; } </code></pre><p>следующим шагом является сохранение свойства, которое представляет текущий первый респондент (uitextfield/uitextview, который в настоящее время имеет клавиатуру).</p><p>мы используем методы делегата, чтобы установить это свойство. если вы используете другой компонент, вам понадобится нечто подобное.</p><p>обратите внимание, что для текстового поля мы устанавливаем его в didbeginediting, а для textview - в mustbeginediting. это происходит потому, что textviewdidbeginediting вызывается после uikeyboardwillshownotification по какой-то причине. </p><pre><code>-(bool)textviewshouldbeginediting:(uitextview * )textview{ self.currentfirstresponder = textview; return yes; } -(void)textfielddidbeginediting:(uitextfield *)textfield{ self.currentfirstresponder = textfield; } </code></pre><p>наконец, вот волшебство</p><pre><code>- (void)keyboardwillshow:(nsnotification*)anotification{ nsdictionary* info = [anotification userinfo]; cgrect kbframe = [[info objectforkey:uikeyboardframeenduserinfokey] cgrectvalue]; /*if currentfirstresponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/ if(self.currentfirstresponder){ //keyboard origin in currentfirstresponderframe cgpoint keyboardorigin = [self.currentfirstresponder convertpoint:kbframe.origin fromview:nil]; float spacebetweenfirstresponderandkeyboard = abs(self.currentfirstresponder.frame.size.height-keyboardorigin.y); //only scroll the scrollview if keyboard overlays the first responder if(spacebetweenfirstresponderandkeyboard>0){ //if i call setcontentoffset:animate:yes it behaves differently, not sure why [uiview animatewithduration:0.25 animations:^{ [self.scrollview setcontentoffset:cgpointmake(0,self.scrollview.contentoffset.y+spacebetweenfirstresponderandkeyboard)]; }]; } } //set bottom inset to the keyboard height so you can still scroll the whole content uiedgeinsets contentinsets = uiedgeinsetsmake(0.0, 0.0, kbframe.size.height, 0.0); \_scrollview.contentinset = contentinsets; \_scrollview.scrollindicatorinsets = contentinsets; } - (void)keyboardwillhide:(nsnotification*)anotification{ uiedgeinsets contentinsets = uiedgeinsetszero; \_scrollview.contentinset = contentinsets; \_scrollview.scrollindicatorinsets = contentinsets; } </code></pre>

<p>это решение с использованием swift.<br></p><pre><code>import uikit class exampleviewcontroller: uiviewcontroller, uitextfielddelegate { @iboutlet var scrollview: uiscrollview! @iboutlet var textfield1: uitextfield! @iboutlet var textfield2: uitextfield! @iboutlet var textfield3: uitextfield! @iboutlet var textfield4: uitextfield! @iboutlet var textfield5: uitextfield! var activetextfield: uitextfield! // mark: - view override func viewdidload() { super.viewdidload() self.textfield1.delegate = self self.textfield2.delegate = self self.textfield3.delegate = self self.textfield4.delegate = self self.textfield5.delegate = self } override func viewwillappear(animated: bool) { super.viewwillappear(animated) self.registerforkeyboardnotifications() } override func viewwilldisappear(animated: bool) { super.viewwilldisappear(animated) self.unregisterfromkeyboardnotifications() } // mark: - keyboard // call this method somewhere in your view controller setup code. func registerforkeyboardnotifications() { let center: nsnotificationcenter = nsnotificationcenter.defaultcenter() center.addobserver(self, selector: "keyboardwasshown:", name: uikeyboarddidshownotification, object: nil) center.addobserver(self, selector: "keyboardwillbehidden:", name: uikeyboardwillhidenotification, object: nil) } func unregisterfromkeyboardnotifications () { let center: nsnotificationcenter = nsnotificationcenter.defaultcenter() center.removeobserver(self, name: uikeyboarddidshownotification, object: nil) center.removeobserver(self, name: uikeyboardwillhidenotification, object: nil) } // called when the uikeyboarddidshownotification is sent. func keyboardwasshown (notification: nsnotification) { let info : nsdictionary = notification.userinfo! let kbsize = (info.objectforkey(uikeyboardframebeginuserinfokey)?.cgrectvalue() as cgrect!).size let contentinsets: uiedgeinsets = uiedgeinsetsmake(0.0, 0.0, kbsize.height, 0.0); scrollview.contentinset = contentinsets; scrollview.scrollindicatorinsets = contentinsets; // if active text field is hidden by keyboard, scroll it so it's visible // your app might not need or want this behavior. var arect = self.view.frame arect.size.height -= kbsize.height; if (!cgrectcontainspoint(arect, self.activetextfield.frame.origin) ) { self.scrollview.scrollrecttovisible(self.activetextfield.frame, animated: true) } } // called when the uikeyboardwillhidenotification is sent func keyboardwillbehidden (notification: nsnotification) { let contentinsets = uiedgeinsetszero; scrollview.contentinset = contentinsets; scrollview.scrollindicatorinsets = contentinsets; } // mark: - text field func textfielddidbeginediting(textfield: uitextfield) { self.activetextfield = textfield } func textfielddidendediting(textfield: uitextfield) { self.activetextfield = nil } } </code></pre>

<p>вы должны добавить прокрутку программно с определенным размером кадра. вы должны добавить uiscrollviewdelegate в файл .h. вы должны включить scrollview, для чего вам нужно написать следующее в viewdidload ().</p><pre><code>scrollview.scrollenabled=yes; scrollview.delegate=self; scrollview.frame = cgrectmake(x,y,width,height); //---set the content size of the scroll view--- [scrollview setcontentsize:cgsizemake(height,width)]; </code></pre><p>таким образом, вы можете добавить свои значения x, y, width и height . я думаю, что это поможет вам.</p>

<p>попробуй это:</p><pre><code>-(void)textfielddidbeginediting:(uitextfield *)sender { if ([sender isequal:self.m\_sp\_contact]) { [self.m\_scroller setcontentoffset:cgpointmake(0, 105)animated:yes]; } } </code></pre>

<p><strong> swift 2.0: </strong></p><p>добавьте uiscrollview и добавьте textfields сверху этого. сделайте раскадровку ссылок на вк.</p><pre><code>@iboutlet weak var username: uitextfield! @iboutlet weak var password: uitextfield! @iboutlet weak var scrollview: uiscrollview! </code></pre><p>добавьте эти методы: uitextfielddelegate & uiscrollviewdelegate.</p><pre><code>//mark:- textfield methods func textfieldshouldreturn(textfield: uitextfield) -> bool { if(username.returnkeytype == uireturnkeytype.default) { password.becomefirstresponder() } textfield.resignfirstresponder() return true } func textfielddidbeginediting(textfield: uitextfield) { dispatch\_async(dispatch\_get\_main\_queue()) { let scrollpoint:cgpoint = cgpointmake(0,textfield.frame.origin.y/4) self.scrollview!.setcontentoffset(scrollpoint, animated: true); } } func textfieldshouldendediting(textfield: uitextfield) -> bool { dispatch\_async(dispatch\_get\_main\_queue()) { uiview.animatewithduration(0, animations: { self.scrollview!.setcontentoffset(cgpointzero,animated: true) }) } return true } override func touchesbegan(touches: set<uitouch>, withevent event: uievent?) { self.view.endediting(true) } func scrollviewwillbegindragging(scrollview: uiscrollview) { self.scrollview.scrollenabled = true dispatch\_async(dispatch\_get\_main\_queue()) { uiview.animatewithduration(0, animations: { self.scrollview!.setcontentoffset(cgpointzero,animated: true) }) } } </code></pre>

<p>вот бесплатная библиотека для работы с клавиатурой <a href="http://www.codeproject.com/tips/509810/keyboard-handling-in-iphone-applications">keyboard-handling-in-iphone-applications</a> . вам нужно написать только одну строку кода:</p><pre><code>[autoscroller addautoscrollto:scrollview]; </code></pre><p>это здорово обрабатывать клавиатуру в формах</p>

<p>я думаю, что лучший подход - это использовать протоколно-ориентированное программирование, если вы используете swift.</p><p>прежде всего, вы должны создать протокол <code>keyboardcapable</code>, который дает любому uiviewcontroller, соответствующему ему, возможность регистрировать и отменять регистрацию наблюдателей с клавиатуры:</p><pre><code>import foundation import uikit protocol keyboardcapable: keyboardanimatable { func keyboardwillshow(notification: nsnotification) func keyboardwillhide(notification: nsnotification) } extension keyboardcapable where self: uiviewcontroller { func registerkeyboardnotifications() { nsnotificationcenter.defaultcenter().addobserver(self, selector: selector("keyboardwillshow:"), name:uikeyboardwillshownotification, object: nil) nsnotificationcenter.defaultcenter().addobserver(self, selector: selector("keyboardwillhide:"), name:uikeyboardwillhidenotification, object: nil) } func unregisterkeyboardnotifications() { nsnotificationcenter.defaultcenter().removeobserver(self, name: uikeyboardwillshownotification, object: nil) nsnotificationcenter.defaultcenter().removeobserver(self, name: uikeyboardwillhidenotification, object: nil) } } </code></pre><p>вы заметили постороннее ключевое слово <code>keyboardanimatable</code> в приведенном выше фрагменте кода. это просто название следующего протокола, который нам нужно создать:</p><pre><code>import foundation import uikit protocol keyboardanimatable { } extension keyboardanimatable where self: uiviewcontroller { func performkeyboardshowfullviewanimation(withkeyboardheight height: cgfloat, andduration duration: nstimeinterval) { uiview.animatewithduration(duration, animations: { () -> void in self.view.frame = cgrectmake(view.frame.origin.x, -height, view.bounds.width, view.bounds.height) }, completion: nil) } func performkeyboardhidefullviewanimation(withduration duration: nstimeinterval) { uiview.animatewithduration(duration, animations: { () -> void in self.view.frame = cgrectmake(view.frame.origin.x, 0.0, view.bounds.width, view.bounds.height) }, completion: nil) } } </code></pre><p>этот протокол <code>keyboardanimatable</code> предоставляет всем uiviewcontroller, соответствующим ему, два метода, которые будут анимировать весь вид вверх и вниз соответственно.</p><p>хорошо, если <code>keyboardcapable</code> соответствует <code>keyboardanimatable</code>, все uiviewcontroller, соответствующие <code>keyboardcapable</code>, также соответствуют <code>keyboardanimatable</code>. это круто.</p><p>давайте посмотрим, что <code>uiviewcontroller</code> соответствует <code>keyboardcapable</code> и реагирует на события клавиатуры:</p><pre><code>import foundation import uikit class transferconfirmviewcontroller: uiviewcontroller, keyboardcapable { //mark: - life cycle override func viewwillappear(animated: bool) { super.viewwillappear(animated) registerkeyboardnotifications() } override func viewwilldisappear(animated: bool) { super.viewwilldisappear(animated) unregisterkeyboardnotifications() } //mark: - notifications //mark: keyboard func keyboardwillshow(notification: nsnotification) { let keyboardheight = (notification.userinfo![uikeyboardframeenduserinfokey] as! nsvalue).cgrectvalue().height let animationduration = notification.userinfo![uikeyboardanimationdurationuserinfokey] as! double performkeyboardshowfullviewanimation(withkeyboardheight: keyboardheight, andduration: animationduration) } func keyboardwillhide(notification: nsnotification) { let animationduration = notification.userinfo![uikeyboardanimationdurationuserinfokey] as! double performkeyboardhidefullviewanimation(withduration: animationduration) } } </code></pre><p>теперь ваш <code>uiviewcontroller</code> будет реагировать на события клавиатуры и, соответственно, анимировать.</p><p>примечание. если вы хотите использовать пользовательскую анимацию вместо push или pull-представления, вы должны определить пользовательские методы в протоколе <code>keyboardanimatable</code> или выполнить их для функций <code>keyboardcapable</code>. тебе решать.</p>

<p>гораздо более элегантное решение - использовать подкласс <code>uiview</code> (хотя это не всегда уместно) и пересчитать все ваши подпредставления при смене кадра родителя (и быть умным: пересчитывать их только в том случае, если изменился новый размер кадра, т.е. использовать <code>cgrectequaltorect</code> для сравнения нового кадра при переопределении <code>setframe</code> и до того, как вы вызовете <code>[super setframe:frame\_]</code>). единственный улов - это то, что <code>uiviewcontroller</code>, который вы намереваетесь использовать, вероятно, должен прослушивать события клавиатуры (или, вы можете сделать это в самой <code>uiview</code>, для удобной инкапсуляции). но только <code>uikeyboardwillshownotification</code> и <code>uikeyboardwillhidenotification</code>. это так, чтобы все выглядело гладко (если вы подождете, пока cg позвонит, вы получите момент прерывистости).</p><p>это имеет преимущество в создании подкласса <code>uiview</code>, который в любом случае делает правильные вещи.</p><p>наивной реализацией было бы переопределение <code>drawrect:</code> (не), лучше было бы просто использовать <code>layoutsubviews</code> (а затем в <code>uiviewcontroller</code>, или еще что-то, что вы можете вызвать [view <code>setneedslayout</code>] в методе single, который вызывается для show или скрывать).</p><p>это решение позволяет избежать жесткого кодирования смещения клавиатуры (которое изменится, если они не разделены и т.д.), а также означает, что ваше представление может быть подпредставлением многих других представлений и при этом реагировать правильно.</p><p>не кодируйте что-то подобное, если нет другого решения. ос дает вам достаточно информации, если вы все сделали правильно, что вам просто нужно перерисовать с умом (в зависимости от вашего нового размера <code>frame</code>). это намного чище и как ты <i>должен</i> заниматься вещами. (может быть, даже лучший подход.)</p><p>приветствия.</p>

<p>это очень просто, просто поместите следующий код в свой класс и настройте, если вам нужно.</p><pre><code>-(void)textfielddidbeginediting:(uitextfield *)textfield { //show keyboard self.view.frame = cgrectmake(self.view.frame.origin.x, self.view.frame.origin.y-50, self.view.frame.size.width, self.view.frame.size.height); } -(void)textfielddidendediting:(uitextfield *)textfield { // hide keyboard self.view.frame = cgrectmake(self.view.frame.origin.x, self.view.frame.origin.y+50, self.view.frame.size.width, self.view.frame.size.height); } </code></pre>

<p>вы можете сделать это, используя методы делегата текстового поля. проверьте ниже код. это работает для меня, когда помещается текстовое поле в представлении прокрутки.</p><pre><code>- (void)textfielddidbeginediting:(uitextfield *)textfield { if(textfield == answer) { cgpoint cpoint = textfield.frame.origin; [scrollview setcontentoffset:cgpointmake(0, cpoint.y - 100) animated:yes]; } } </code></pre><blockquote> <p><strong> примечание: </strong>вы должны изменить значение cpoint.y - 100 согласно вашему мнению.</p> </blockquote>

<p>вот моя версия с использованием autolayout:</p><p>идея состоит в том, чтобы просто встроить ваше представление, содержащее текстовые поля/текстовое представление, в uiscrollview, установить ограничение снизу к его суперпредставлению, создать выход и обновить его константу в соответствии с высотой клавиатуры с помощью уведомлений .... это основано на примере apple <a href="https://developer.apple.com/library/ios/documentation/stringstextfonts/conceptual/textandwebiphoneos/keyboardmanagement/keyboardmanagement.html">здесь</a> и техническая заметка apple по uiscrollview с использованием autolayout <a href="https://developer.apple.com/library/ios/technotes/tn2154/\_index.html">здесь</a> .</p><p>1) вставьте ваш view v в uiscrollview s: если вы уже установили свои константы и подпредставления, вы можете скопировать/вставить свое представление и подпредставления в представление viewcontroller, а затем внедрить его с помощью editor -> embed menu и, наконец, удалить скопированные представления.)</p><p>2) установите следующие ограничения:</p><ul> <li>s к началу руководство по макету: 0</li> <li>s к нижнему плану размещения: 0</li> <li>s ведет к супервизору: 0</li> <li><p>s тянется к superview: 0</p></li> <li><p>v верхнее пространство для просмотра: 0</p></li> <li>v нижнее пространство для просмотра: 0</li> <li>v тянущееся пространство к superview: 0</li> <li><p>v ведущее место для супервидения: 0</p></li> <li><p>v равна ширине s</p></li> <li><p>последний нижний v подвид для superview: 20</p></li> </ul><p>3) создайте выход из последних ограничений для вашего контроллера представления</p><p>4) используйте следующий код:</p><pre><code>@property (weak, nonatomic) iboutlet nslayoutconstraint *bottomspacetocontentview; // ... - (void)viewdidload { [super viewdidload]; // do any additional setup after loading the view. // ... [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwasshown:) name:uikeyboarddidshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillbehidden:) name:uikeyboardwillhidenotification object:nil]; } - (void)didreceivememorywarning { [super didreceivememorywarning]; // dispose of any resources that can be recreated. } #pragma mark - handle keyboard // called when the uikeyboarddidshownotification is sent. - (void)keyboardwasshown:(nsnotification*)anotification { nsdictionary* info = [anotification userinfo]; cgsize kbsize = [[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue].size; self.bottomspacetocontentview.constant = kbottommargin + kbsize.height; [self.view layoutifneeded]; } // called when the uikeyboardwillhidenotification is sent - (void)keyboardwillbehidden:(nsnotification*)anotification { self.bottomspacetocontentview.constant = kbottommargin; [self.view layoutifneeded]; } </code></pre><p>и тадааааа, это работает!</p>

<p>есть много доступных ответов, рассказывающих о подходе. я использовал тот же подход, но реализация не очень хорошая.</p><p>вот эта <a href="https://developer.apple.com/library/ios/documentation/stringstextfonts/conceptual/textandwebiphoneos/keyboardmanagement/keyboardmanagement.html#//apple\_ref/doc/uid/tp40009542-ch5-sw7">базовая идея</a> . я внес изменения в метод клавиатурыwasshown.</p><pre><code>{ // obtain keyboard info nsdictionary* info = [notification userinfo]; cgrect keyboardrect = [[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue]; keyboardrect = [self.view convertrect:keyboardrect fromview:nil]; // obtain scrollview info w.r.t. top view cgrect scrollviewrect = [self.view convertrect:self.scrollview.frame fromview:nil]; // depending upon your screen ui, scroll view's bottom edge might be at some offset from screen's bottom // calculate the exact offset int scrollviewbottomoffset = self.view.frame.size.height - (scrollviewrect.origin.y + scrollviewrect.size.height); int heighttobeadjusted = keyboardrect.size.height - scrollviewbottomoffset; // we may also need to consider the insets if already present with scrollview. let's keep it simple for now // but we should store these, so that we can restore the insets when keyboard is gone // originsets = self.scrollview.contentinset; // set the new insets for scrollview uiedgeinsets contentinsets = uiedgeinsetsmake(0.0, 0.0, heighttobeadjusted, 0.0); self.scrollview.contentinset = contentinsets; self.scrollview.scrollindicatorinsets = contentinsets; // visible frame (not overlapped by keyboard) cgrect visibleframe = self.view.frame; visibleframe.size.height -= keyboardrect.size.height; // get the rect for textfield w.r.t self.view cgrect activefieldframe = self.activefield.frame; activefieldframe = [self.view convertrect:activefieldframe fromview:self.scrollview]; // check if the textfield is visible or not if (!cgrectcontainsrect(visibleframe, activefieldframe) ) { // scroll to make it visible but for scrolling use the activefield frame w.r.t. to scroll view [self.scrollview scrollrecttovisible:self.activefield.frame animated:yes]; } </code></pre><p>}</p><p>и добавьте этот метод для инициализации activefield</p><pre><code>- (ibaction)textfielddidbeginediting:(uitextfield *)sender { self.activefield = sender; } </code></pre>

<p>это вычисление смещения независимо от устройства. получает перекрытую высоту между клавиатурой и текстовым полем:</p><pre><code>func keyboardshown(notification: nsnotification) { let info = notification.userinfo! let value: anyobject = info[uikeyboardframeenduserinfokey]! let rawframe = value.cgrectvalue let keyboardframe = view.convertrect(rawframe, fromview: nil) let screenheight = uiscreen.mainscreen().bounds.size.height; let ylimit = screenheight - keyboardframe.size.height let textboxorigininsuperview:cgpoint = self.view.convertpoint(cgpointzero, fromcoordinatespace: lasttextfield!) self.keyboardheight = (textboxorigininsuperview.y+self.lasttextfield!.frame.size.height) - ylimit if(self.keyboardheight>0){ self.animateviewmoving(true, movevalue: keyboardheight!) }else{ keyboardheight=0 } } </code></pre><p>keyboardheight - это смещение.</p>

<p> <a href="https://github.com/michaeltyson/tpkeyboardavoiding">https://github.com/michaeltyson/tpkeyboardavoiding</a> скачайте этот файл и добавьте пользовательский класс, так как в вашем табличном представлении он будет управлять всеми вещами, потому что вам не нужно ничего делать ... избегать клавиатуры</p>

<p>вот категория uitextfield (и других аналогичных полей), которую я сделал, чтобы текстовое поле избегало клавиатуры, вы должны иметь возможность оставить это в вашем контроллере представления как есть, и оно должно работать. он перемещает весь экран вверх, поэтому текущее текстовое поле находится над клавиатурой с анимацией.</p><pre><code>#import "uiview+avoidkeyboard.h" #import "appdelegate.h" @implementation uiview (avoidkeyboard) - (void) becomefirstresponder { if(self.isfirstresponder) return; [super becomefirstresponder]; if ([self iskindofclass:[uisearchbar class]] || [self iskindofclass:[uitextfield class]] || [self iskindofclass:[uitextview class]]) { appdelegate *appdelegate = [uiapplication sharedapplication].delegate; cgrect screenbounds = appdelegate.window.frame; cgfloat keyboardheight; cgfloat keyboardy; cgfloat viewslowesty; cgpoint origin = [self.superview convertpoint:self.frame.origin toview:appdelegate.window]; //get this views origin in terms of the main screens bounds if(uiinterfaceorientationisportrait([[uiapplication sharedapplication] statusbarorientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the origin instead of the y keyboardheight = 216; keyboardy = screenbounds.size.height - keyboardheight; //find the keyboards y coord relative to how much the main window has moved up viewslowesty = origin.y + self.frame.size.height; //find the lowest point of this view } else { keyboardheight = 162; keyboardy = screenbounds.size.width - keyboardheight; viewslowesty = origin.x + self.frame.size.height; } cgfloat difference = viewslowesty - keyboardy + 20; //find if this view overlaps with the keyboard with some padding if (difference > 0){ //move screen up if there is an overlap [uiview animatewithduration:0.3 delay:0.0 options:uiviewanimationoptionbeginfromcurrentstate animations:^{ cgrect frame = appdelegate.window.frame; if(uiinterfaceorientationisportrait([[uiapplication sharedapplication] statusbarorientation])){ frame.origin.y -= difference; } else { frame.origin.x -= difference; } appdelegate.window.frame = frame; } completion:nil]; } } } //look at appdelegate to see when the keyboard is hidden @end </code></pre><p>в вашем приложении delegate добавьте эту функцию</p><pre><code>[[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardhides:) name:uikeyboardwillhidenotification object:nil]; //add in didfinishlaunchingwithoptions ... - (void)keyboardhides:(nsnotification *)notification { [uiview animatewithduration:0.3 animations:^{ [window setframe: cgrectmake(0, 0, window.frame.size.width, window.frame.size.height)]; } completion:nil]; } </code></pre>

<p>пожалуйста, следуйте этим шагам. </p><p>1) объявите следующую переменную в файле .h.</p><pre><code> { cgfloat animateddistance; } </code></pre><p>2) объявите следующие константы в файле .m.</p><pre><code> static const cgfloat keyboard\_animation\_duration = 0.3; static const cgfloat minimum\_scroll\_fraction = 0.2; static const cgfloat maximum\_scroll\_fraction = 0.8; static const cgfloat portrait\_keyboard\_height = 216; static const cgfloat landscape\_keyboard\_height = 162; </code></pre><p>3) используйте делегат uitextfield для перемещения вверх/вниз клавиатуры.</p><pre><code> -(void) textfielddidbeginediting:(uitextfield *)textfield { if(ui\_user\_interface\_idiom() == uiuserinterfaceidiomphone) { cgrect textfieldrect = [self.view.window convertrect:textfield.bounds fromview:textfield]; cgrect viewrect = [self.view.window convertrect:self.view.bounds fromview:self.view]; cgfloat midline = textfieldrect.origin.y + 0.5 * textfieldrect.size.height; cgfloat numerator = midline - viewrect.origin.y - minimum\_scroll\_fraction * viewrect.size.height; cgfloat denominator = (maximum\_scroll\_fraction - minimum\_scroll\_fraction) * viewrect.size.height; cgfloat heightfraction = numerator / denominator; if (heightfraction < 0.0) { heightfraction = 0.0; } else if (heightfraction > 1.0) { heightfraction = 1.0; } uiinterfaceorientation orientation = [[uiapplication sharedapplication] statusbarorientation]; if (orientation == uiinterfaceorientationportrait) { animateddistance = floor(portrait\_keyboard\_height * heightfraction); } else { animateddistance = floor(landscape\_keyboard\_height * heightfraction); } cgrect viewframe = self.view.frame; viewframe.origin.y -= animateddistance; [uiview beginanimations:nil context:null]; [uiview setanimationbeginsfromcurrentstate:yes]; [uiview setanimationduration:keyboard\_animation\_duration]; [self.view setframe:viewframe]; [uiview commitanimations]; } } -(void) textfielddidendediting:(uitextfield *)textfield { if(ui\_user\_interface\_idiom()==uiuserinterfaceidiomphone) { cgrect viewframe = self.view.frame; viewframe.origin.y += animateddistance; [uiview beginanimations:nil context:null]; [uiview setanimationbeginsfromcurrentstate:yes]; [uiview setanimationduration:keyboard\_animation\_duration]; [self.view setframe:viewframe]; [uiview commitanimations]; } } </code></pre>

<p>я упаковываю все в один класс. просто вызовите эти строки кода, когда ваш viewcontroller загружен:</p><pre><code>- (void)viewdidload { [super viewdidload]; keyboardinsetscrollview *injectview = [[keyboardinsetscrollview alloc] init]; [injectview injecttoview:self.view withrootview:self.view]; } </code></pre><p>вот ссылка на пример проекта:<br> <a href="https://github.com/caohuuloc/keyboardinsetscrollview">https://github.com/caohuuloc/keyboardinsetscrollview</a> </p>

<p>недавно я оказался в похожем сценарии, работая над приложением для обмена сообщениями. я создал пользовательский uiview, который прилипает к верхней части клавиатуры и автоматически выполняет большую часть того, что вам нужно</p><p> <a href="https://github.com/oseparovic/messagecomposerview">messagecomposerview</a> </p><p> <a href="http://www.thegameengine.org/wp-content/uploads/2013/11/message\_composer\_quad\_1.jpg">http://www.thegameengine.org/wp-content/uploads/2013/11/message\_composer\_quad\_1.jpg</a> </p><p>идея этого проекта состояла в том, чтобы создать что-то, что функционировало бы аналогично представлению композиции imessage aka:</p><ul> <li>прилипает к верхней части клавиатуры и перемещается к нижней части экрана при отклонении клавиатуры</li> <li>обрабатывает изменения в тексте</li> <li>обрабатывает повороты</li> </ul><p>для изменения размера/реконфигурации вашего uiscrollview вы захотите использовать следующий необязательный метод делегата:</p><p><code>- (void)messagecomposerframedidchange:(cgrect)frame withanimationduration:(float)duration;</code></p><p>он будет вызываться всякий раз, когда кадр изменяется (изменен размер, перемещен, повернут), а также будет указывать продолжительность анимации. вы можете использовать эту информацию для изменения размера рамки uiscrollview и вставок содержимого по мере необходимости.</p>

<p>просто добавьте это в ваш файл pod -> <code>pod 'iqkeyboardmanager'</code></p><p>вот и все, обрабатывает все клавиатуры, прокрутки и все!</p><p>вам не нужно ничего кодировать, не может найти лучшего решения!</p><p>он имеет расширение, которое управляет отображением текстовых полей, смещением экрана, стрелками вперед и назад, если имеется несколько текстовых полей.</p><p>он также имеет пользовательскую кнопку «готово», которую можно удалить.</p><p>ссылка -> <a href="https://github.com/hackiftekhar/iqkeyboardmanager">https://github.com/hackiftekhar/iqkeyboardmanager</a> </p>

<p>я считаю, что это лучшее решение, следуйте приведенному ниже коду: </p><p>прикрепите ниже к вашему ограничению <code>vertical space - bottom layout guide - textfield</code>. </p><pre><code>@property (weak, nonatomic) iboutlet nslayoutconstraint *textviewbottomconst; </code></pre><p>во-вторых, добавьте наблюдателей для уведомлений клавиатуры.</p><pre><code>- (void)observekeyboard { [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillshow:) name:uikeyboardwillshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillhide:) name:uikeyboardwillhidenotification object:nil]; } </code></pre><p>добавьте это к вашему <code>viewdidload</code> </p><pre><code>[self observekeyboard]; </code></pre><p>наконец методы, которые обрабатывают изменения клавиатуры.</p><pre><code>- (void)keyboardwillshow:(nsnotification *)notification { //this will make sure keyboard doesnt jump when opening quicktype/emoji or other keyboards. kbheight = 0; height = 0; self.textviewbottomconst.constant = height; self.btnviewbottomconst.constant = height; nsdictionary *info = [notification userinfo]; nsvalue *kbframe = [info objectforkey:uikeyboardframeenduserinfokey]; nstimeinterval animationduration = [[info objectforkey:uikeyboardanimationdurationuserinfokey] doublevalue]; cgrect keyboardframe = [kbframe cgrectvalue]; cgrect finalkeyboardframe = [self.view convertrect:keyboardframe fromview:self.view.window]; int kbheight = finalkeyboardframe.size.height; int height = kbheight + self.textviewbottomconst.constant; self.textviewbottomconst.constant = height; [uiview animatewithduration:animationduration animations:^{ [self.view layoutifneeded]; }]; } - (void)keyboardwillhide:(nsnotification *)notification { nsdictionary *info = [notification userinfo]; nstimeinterval animationduration = [[info objectforkey:uikeyboardanimationdurationuserinfokey] doublevalue]; self.textviewbottomconst.constant = 10; [uiview animatewithduration:animationduration animations:^{ [self.view layoutifneeded]; }]; } </code></pre>

<p>гораздо более простой, но в то же время обобщенный способ, как это делает apple, учитывает высоту клавиатуры, что очень полезно, когда мы используем настраиваемую панель инструментов над клавиатурой ........ хотя подход apple <a href="https://developer.apple.com/library/ios/documentation/stringstextfonts/conceptual/textandwebiphoneos/keyboardmanagement/keyboardmanagement.html">здесь</a> имеет несколько проблем.</p><p>вот мой подход (слегка измененный путь apple) - </p><pre><code>// uikeyboarddidshownotification - (void)keyboardwasshown:(nsnotification*)anotification { nsdictionary* info = [anotification userinfo]; cgsize kbsize = [[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue].size; uiedgeinsets contentinsets = uiedgeinsetsmake(0.0, 0.0, kbsize.height, 0.0); self.scrollview.contentinset = contentinsets; self.scrollview.scrollindicatorinsets = contentinsets; } // uikeyboardwillhidenotification - (void)keyboardwillbehidden:(nsnotification*)anotification { uiedgeinsets contentinsets = uiedgeinsetszero; self.scrollview.contentinset = contentinsets; self.scrollview.scrollindicatorinsets = contentinsets; } </code></pre>

<p>я знаю, что уже слишком поздно, но я хотел поделиться с будущими посетителями, особенно о том, как это сделать. было опубликовано много хороших методов, но мне не понравилось, как интерфейс стал совершенно плохим. есть простой метод, который состоит из двух частей:</p><ol> <li><strong>добавьте textfield и, что бы вы ни хотели, чтобы он находился над клавиатурой во время редактирования, в представление, чтобы они стали дочерними элементами представления. и тогда будет легко сохранить внешний вид и не повлиять на интерфейс.</strong></li> <li><strong>используйте отличный инструмент</strong> <code>cgaffinetransform(translationx: x, translationy: y)</code> <strong>, чтобы переместить созданный вид над клавиатурой.</strong> </li> </ol><p>я знаю, что это кажется очень простым, но это действительно эффективно и аккуратно . <a href="https://i.stack.imgur.com/qrrsj.gif"> <img src="https://i.stack.imgur.com/qrrsj.gif" alt="enter image description here"> </a> </p>

<p>простое решение, расширяющее uiviewcontroller</p><p> <a href="https://github.com/damienromito/visibleformviewcontroller">https://github.com/damienromito/visibleformviewcontroller</a> </p><p><img src="https://i.stack.imgur.com/ymopq.jpg" alt="enter image description here"></p>

<p>простое решение и с последней анимацией api. изменив origin.y на 215, вы можете настроить его так, как вам удобно.</p><pre><code>- (void)textfielddidbeginediting:(uitextfield *)textfield { if (self.view.frame.origin.y >= 0) { [uiview animatewithduration:0.5 animations:^{ self.view.frame = cgrectmake(self.view.frame.origin.x, self.view.frame.origin.y-215, self.view.frame.size.width, self.view.frame.size.height); }]; } } - (void)textfielddidendediting:(uitextfield *)textfield { if (self.view.frame.origin.y < 0) { [uiview animatewithduration:0.5 animations:^{ self.view.frame = cgrectmake(self.view.frame.origin.x, self.view.frame.origin.y+215, self.view.frame.size.width, self.view.frame.size.height); }]; } } </code></pre>

<p>я хотел бы расширить ответ @sumanthkodi.</p><p>как утверждают некоторые люди, его подход не работает в более новых реализациях, потому что uiview не может двигаться, когда вы используете<strong> constraints </strong>.</p><p>я отредактировал код следующим образом (и перенес на swift 2.0) и надеюсь, что он поможет некоторым людям:</p><hr><p>1) ссылка на вертикальное ограничение вида, который вы хотели бы переместить вверх:</p><pre><code>@iboutlet var viewconstraint: nslayoutconstraint! </code></pre><p>убедитесь, что вы ссылаетесь на эту переменную в вашей раскадровке с ограничением.</p><p>2) добавить делегата и реализовать слушателей. это та же реализация, что и раньше:</p><pre><code>class yourviewcontroller: uiviewcontroller, uitextfielddelegate { ... func textfielddidbeginediting(textfield: uitextfield) { animatetextfield(textfield, up: true) } func textfielddidendediting(textfield: uitextfield) { animatetextfield(textfield, up: false) } ... } </code></pre><p>3) добавьте свой метод анимации <code>animatetextfield</code> в класс <code>yourviewcontroller</code>. установите значение временного ограничения по мере необходимости.</p><pre><code>func animatetextfield(textfield: uitextfield, up: bool) { let originalconstraint = 50 let temporaryconstraint = 0 let movementduration = 0.3 let constraint = cgfloat(up ? temporaryconstraint : originalconstraint) containerviewconstraint.constant = constraint uiview.animatewithduration(movementduration) { self.view.layoutifneeded() } } </code></pre>

<p>это будет работать отлично. вид прокрутки автоматически настраивается по позиции текстового поля. я уверен, что вы будете чувствовать себя хорошо</p><pre><code>static const cgfloat keyboard\_animation\_duration = 0.25; static const cgfloat minimum\_scroll\_fraction = 0.2; static const cgfloat maximum\_scroll\_fraction = 0.8; static const cgfloat portrait\_keyboard\_height = 216; static const cgfloat landscape\_keyboard\_height = 162; @interface loginvc () { cgfloat animateddistance; cgrect viewframekey; } //in viewdidload viewframekey=self.view.frame; - (void)textfielddidbeginediting:(uitextfield *)textfield { cgrect textfieldrect = [self.view.window convertrect:textfield.bounds fromview:textfield]; cgrect viewrect = [self.view.window convertrect:self.view.bounds fromview:self.view]; cgfloat midline = textfieldrect.origin.y + 0.5 * textfieldrect.size.height; cgfloat numerator = midline - viewrect.origin.y - minimum\_scroll\_fraction * viewrect.size.height; cgfloat denominator = (maximum\_scroll\_fraction - minimum\_scroll\_fraction) * viewrect.size.height; cgfloat heightfraction = numerator / denominator; if (heightfraction < 0.0) { heightfraction = 0.0; } else if (heightfraction > 1.0) { heightfraction = 1.0; } uiinterfaceorientation orientation = [[uiapplication sharedapplication] statusbarorientation]; if (orientation == uiinterfaceorientationportrait || orientation == uiinterfaceorientationportraitupsidedown) { animateddistance = floor(portrait\_keyboard\_height * heightfraction); } else { animateddistance = floor(landscape\_keyboard\_height * heightfraction); } cgrect viewframe = self.view.frame; viewframe.origin.y -= animateddistance; [uiview beginanimations:nil context:null]; [uiview setanimationbeginsfromcurrentstate:yes]; [uiview setanimationduration:keyboard\_animation\_duration]; [self.view setframe:viewframe]; [uiview commitanimations]; } - (void)textfielddidendediting:(uitextfield *)textfield { [uiview beginanimations:nil context:null]; [uiview setanimationbeginsfromcurrentstate:yes]; [uiview setanimationduration:keyboard\_animation\_duration]; [self.view setframe:viewframekey]; [uiview commitanimations]; } </code></pre>

<p>просто нашел этот класс:</p><p> <a href="https://github.com/oliverletterer/slscrollviewkeyboardsupport">https://github.com/oliverletterer/slscrollviewkeyboardsupport</a> </p><p>и до сих пор он очень хорошо работает на iphone, включая анимацию и правильное смещение.</p><p>чтобы использовать его, просто добавьте в <code>viewdidload</code>:</p><pre><code>self.support = [[slscrollviewkeyboardsupport alloc] initwithscrollview:self.scrollview]; </code></pre>

<p>очень легким решением может быть использование <a href="https://github.com/ratulsharker/keyboard-animator">keyboardanimator</a> . </p><p>проект получил образец реализации, документация еще продолжается ...</p><p><strong>соответствующее использование ::</strong> у него есть особая реализация для uitextfield & uitextview</p><p><strong>limitation ::</strong> он полностью соответствует цели-c, скоро будет доступна версия swift.</p>

<p>этот фрагмент кода вычислит, сколько нужно продвинуться, основываясь на высоте клавиатуры и глубине пропущенного текстового поля. не забудьте добавить делегат и наследовать uitextfielddelegate в своем заголовке.</p><pre><code>- (void)touchesbegan:(nsset *)touches withevent:(uievent *)event { [\_tbxusername resignfirstresponder]; [\_tbxpassword resignfirstresponder]; } - (void)textfielddidbeginediting:(uitextfield *) textfield { [self animatetextfield:textfield up:yes]; } - (void)textfielddidendediting:(uitextfield *) textfield { [self animatetextfield:textfield up:no]; } - (void) animatetextfield: (uitextfield*) textfield up: (bool) up { int animateddistance; int moveupvalue = textfield.frame.origin.y+ textfield.frame.size.height; uiinterfaceorientation orientation = [[uiapplication sharedapplication] statusbarorientation]; if (orientation == uiinterfaceorientationportrait || orientation == uiinterfaceorientationportraitupsidedown) { animateddistance = 236-(460-moveupvalue-5); } else { animateddistance = 182-(320-moveupvalue-5); } if(animateddistance>0) { const int movementdistance = animateddistance; const float movementduration = 0.3f; int movement = (up ? -movementdistance : movementdistance); [uiview beginanimations: nil context: nil]; [uiview setanimationbeginsfromcurrentstate: yes]; [uiview setanimationduration: movementduration]; self.view.frame = cgrectoffset(self.view.frame, 0, movement); [uiview commitanimations]; } } </code></pre><p>делегат для добавления в viewdidload</p><pre><code>\_tbxusername.delegate = self; \_tbxpassword.delegate = self; </code></pre>

<ol> <li>скачать tpkeyboardavoiding по этой ссылке: <a href="https://github.com/michaeltyson/tpkeyboardavoiding">https://github.com/michaeltyson/tpkeyboardavoiding</a> . </li> <li>разверните zip-папку и найдите папку tpkeyboardavoiding.</li> <li>выберите все файлы .h и .m и поместите их в свой проект. убедитесь, что при необходимости помечены элементы.</li> <li>перетащите uiscrollview в storyboard и свяжите его с tpkeyboardavoidingscrollview.</li> <li>теперь вы можете добавить элементы пользовательского интерфейса в верхней части прокрутки. обратите внимание, что этот класс обнаруживает прикосновения элементов пользовательского интерфейса даже после перетаскивания scrollview.</li> </ol><p>на вашем viewcontroller:</p><pre><code>@iboutlet weak var usernametextfield: uitextfield! @iboutlet weak var passwordtextfield: uitextfield! @iboutlet weak var loginscrollview: uiscrollview! override func viewwillappear(animated: bool) { loginscrollview.scrollenabled = false } </code></pre><p>добавить делегатов textfield.</p><pre><code>//mark:- textfield methods func textfieldshouldreturn(textfield: uitextfield) -> bool { if (usernametextfield.resignfirstresponder()) { passwordtextfield.becomefirstresponder() } textfield.resignfirstresponder(); loginscrollview!.setcontentoffset(cgpoint.zero, animated: true); loginscrollview.scrollenabled = false return true } func textfielddidbeginediting(textfield: uitextfield) { loginscrollview.scrollenabled = true if (textfield.tag == 1 && (device == "iphone" || device == "iphone simulator" || device == "ipod touch")) { let scrollpoint:cgpoint = cgpointmake(0, passwordtextfield.frame.origin.y/6.4); loginscrollview!.setcontentoffset(scrollpoint, animated: true); } else if (textfield.tag == 2 && (device == "iphone" || device == "iphone simulator" || device == "ipod touch")) { let scrollpoint:cgpoint = cgpointmake(0, passwordtextfield.frame.origin.y/6.0); loginscrollview!.setcontentoffset(scrollpoint, animated: true); } } func textfielddidendediting(textfield: uitextfield) { loginscrollview!.setcontentoffset(cgpointzero,animated: true); } </code></pre>

<p><strong> установить scrollview в представлении </strong> </p><pre><code> - (void)textfielddidbeginediting:(uitextfield *)textfield { cgpoint point; if(textfield == txtemail){ // -90 is for my you can change as per your postion point = cgpointmake(0, textfield.frame.origin.y - 90); } else if (textfield == txtcontact){ point = cgpointmake(0, textfield.frame.origin.y - 90); } [scrollv setcontentoffset:point animated:yes]; } </code></pre>

<p>пожалуйста, добавьте эти строки в метод делегата текстового поля, чтобы прокрутить вверх в ipad. </p><pre><code>- (void)textfielddidbeginediting:(uitextfield *)textfield { activetextfield = textfield; cgpoint pt; cgrect rc = [textfield bounds]; rc = [textfield convertrect:rc toview:scrlview]; pt = rc.origin; pt.x = 0; pt.y -= 100; [scrlview setcontentoffset:pt animated:yes]; scrlview.contentsize = cgsizemake(scrlview.frame.size.width, button.frame.origin.y+button.frame.size.height + 8 + 370); } </code></pre>

<p>попробуйте библиотеку iqkeyboard.</p><p>это автоматически переместит текстовое поле вверх.</p>

<p>это может быть просто достигнуто с помощью приведенных ниже строк кода с использованием ограничений</p><pre><code>- (void)viewdidappear:(bool)animated { [super viewdidappear:animated]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillshow:) name:uikeyboardwillshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillhide:) name:uikeyboardwillhidenotification object:nil]; } - (void)keyboardwillshow:(nsnotification *)notification { [self adjusttextviewbykeyboardstate:yes keyboardinfo:[notification userinfo]]; } - (void)keyboardwillhide:(nsnotification *)notification { [self adjusttextviewbykeyboardstate:no keyboardinfo:[notification userinfo]]; } - (void)viewdiddisappear:(bool)animated { [[nsnotificationcenter defaultcenter] removeobserver:self]; [super viewdiddisappear:animated]; } - (void)adjusttextviewbykeyboardstate:(bool)showkeyboard keyboardinfo:(nsdictionary *)info { cgrect keyboardframe = [[info objectforkey:uikeyboardframeenduserinfokey] cgrectvalue]; cgfloat height = keyboardframe.size.height; self.constrainttoadjust.constant = height; uiviewanimationcurve animationcurve = [info[uikeyboardanimationcurveuserinfokey] unsignedintegervalue]; uiviewanimationoptions animationoptions = uiviewanimationoptionbeginfromcurrentstate; if (animationcurve == uiviewanimationcurveeasein) { animationoptions |= uiviewanimationoptioncurveeasein; } else if (animationcurve == uiviewanimationcurveeaseinout) { animationoptions |= uiviewanimationoptioncurveeaseinout; } else if (animationcurve == uiviewanimationcurveeaseout) { animationoptions |= uiviewanimationoptioncurveeaseout; } else if (animationcurve == uiviewanimationcurvelinear) { animationoptions |= uiviewanimationoptioncurvelinear; } [uiview animatewithduration:[[info objectforkey:uikeyboardanimationdurationuserinfokey] doublevalue] delay:0 options:animationoptions animations:^{ [self.view layoutifneeded]; } completion:nil]; } </code></pre>

<ul> <li>если текстовое поле не полностью или частично скрыто, мы не должны ничего менять.</li> <li><p>мы должны вычислить точную область пересечения (рамка клавиатуры и рамка текстового поля), которая скрыта, а затем мы должны изменить рамку вида.</p></li> <li><p>здесь я приведу полный пример.</p> <p>объявление 3 переменных</p></li> </ul><blockquote> <p>#define padding 10</p> <pre><code>@interface pkviewcontroller () @property (nonatomic, assign) cgrect originalviewframe; //original view's frame @property (nonatomic, strong) uitextfield *activetextfield; // current text field @property (nonatomic, assign) cgrect keyboardrect; // covered area by keaboard @end </code></pre> </blockquote><p>хранить оригинальную рамку</p><pre><code>- (void)viewdidload { [super viewdidload]; \_originalviewframe = self.view.frame; } </code></pre><p>добавьте свой контроллер представления в качестве наблюдателя для уведомления клавиатуры</p><pre><code>- (void)viewwillappear:(bool)animated{ [super viewwillappear:animated]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwasshown:) name:uikeyboarddidshownotification object:nil]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(keyboardwillhide:) name:uikeyboardwillhidenotification object:nil]; } </code></pre><p>удалить наблюдателя</p><pre><code>- (void)viewwilldisappear:(bool)animated{ [super viewwilldisappear:animated]; [[nsnotificationcenter defaultcenter] removeobserver:self]; } </code></pre><p>сохраните область, покрытую клавиатурой, когда она появляется, и установите ее на cgrectzero, когда она исчезнет. </p><pre><code>- (void)keyboardwasshown:(nsnotification *)notification{ cgsize keyboardsize = [[[notification userinfo] objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue].size; \_keyboardrect = cgrectmake(0, \_originalviewframe.size.height - keyboardsize.height, keyboardsize.width, keyboardsize.height); [self movetextfieldup]; } - (void) keyboardwillhide:(nsnotification *)notification{ \_keyboardrect = cgrectzero; [self setdefaultframe]; } </code></pre><p>сохранить активное текстовое поле </p><pre><code>- (bool)textfieldshouldbeginediting:(uitextfield *)textfield { \_activetextfield = textfield; //when keyboard is already present but the textfield is hidden. case:when return key of keyboard makes the next textfield as first responder if (!cgrectisempty(\_keyboardrect)) { [self movetextfieldup]; } return yes; } - (bool)textfieldshouldreturn:(uitextfield *)textfield{ [textfield resignfirstresponder]; return yes; } </code></pre><p>теперь мы должны изменить кадр зрения</p><pre><code>- (void)movetextfieldup{ cgrect virtualtextfieldrect = cgrectmake(0, self.view.frame.origin.y, \_activetextfield.frame.size.width, \_activetextfield.frame.origin.y+\_activetextfield.frame.size.height); if (cgrectintersectsrect(\_keyboardrect, virtualtextfieldrect)) { cgrect intersectrect = cgrectintersection(\_keyboardrect, virtualtextfieldrect); cgfloat newy = \_originalviewframe.origin.y - intersectrect.size.height; cgfloat newheight = \_originalviewframe.size.height + intersectrect.size.height; cgrect newframe = cgrectmake(0, newy-padding, \_originalviewframe.size.width, newheight+padding); [uiview animatewithduration:0.3 animations:^{ [self.view setframe:newframe]; }]; nslog(@"intersect"); } } - (void)setdefaultframe { [uiview animatewithduration:0.3 animations:^{ [self.view setframe:\_originalviewframe]; }]; } </code></pre>

<p>здесь много ответов, но это работает и намного короче большинства:</p><pre><code>- (void)textfielddidbeginediting:(uitextfield *)sender { uiscrollview *scrollview = (uiscrollview *)self.view; // assuming this method is pasted into the uiscrollview's controller const double donthardcodethekeyboardheight = 162; double texty = [sender convertpoint:cgpointmake(0, 0) toview:scrollview].y; if (texty - scrollview.contentoffset.y + sender.frame.size.height > self.view.frame.size.height - donthardcodethekeyboardheight) [scrollview setcontentoffset:cgpointmake(0.0, texty - 10) animated:yes]; } </code></pre>

<p>это можно сделать<strong> легко и автоматически </strong>, если это текстовое поле находится в ячейке таблицы (даже когда table.scrollable = no).</p><ul> <li><strong>note</strong>that: позиция и размер стола должны быть разумными . например: <ul> <li>если позиция y таблицы 100 отсчитывается от нижней части представления, то клавиатура высотой 300 будет перекрывать всю таблицу.</li> <li>если высота таблицы = 10, а текстовое поле в ней должно быть прокручено на 100, когда клавиатура появляется, чтобы быть видимой, то это текстовое поле будет вне границы таблицы. </li> </ul></li> </ul>

<pre><code>-(bool) textfieldshouldbeginediting:(uitextfield *)textfield { [self slideup]; return yes; } -(bool) textfieldshouldendediting:(uitextfield *)textfield { [self slidedown]; return yes; } #pragma mark - slide up and down animation - (void) slideup { [uiview beginanimations:nil context:nil]; layoutview.frame = cgrectmake(0.0, -70.0, layoutview.frame.size.width, layoutview.frame.size.height); [uiview commitanimations]; } - (void) slidedown { [uiview beginanimations:nil context:nil]; [uiview setanimationdelay: 0.01]; layoutview.frame = cgrectmake(0.0, 0.0, layoutview.frame.size.width, layoutview.frame.size.height); [uiview commitanimations]; } </code></pre>

<p>хотя в этой теме достаточно ответов, я хотел бы предложить гораздо более простой, но в то же время обобщенный способ, как это делает apple, учитывающий высоту клавиатур, что очень полезно, когда мы используем настраиваемую панель инструментов над клавиатурой ........ хотя и подход apple <a href="https://developer.apple.com/library/ios/documentation/stringstextfonts/conceptual/textandwebiphoneos/keyboardmanagement/keyboardmanagement.html">здесь</a> есть несколько вопросов.</p><p>вот мой подход (слегка измененный путь apple) - </p><pre><code>// called when the uikeyboarddidshownotification is sent. - (void)keyboardwasshown:(nsnotification*)anotification { nsdictionary* info = [anotification userinfo]; cgsize kbsize = [[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue].size; uiedgeinsets contentinsets = uiedgeinsetsmake(0.0, 0.0, kbsize.height, 0.0); self.scrollview.contentinset = contentinsets; self.scrollview.scrollindicatorinsets = contentinsets; } // called when the uikeyboardwillhidenotification is sent - (void)keyboardwillbehidden:(nsnotification*)anotification { uiedgeinsets contentinsets = uiedgeinsetszero; self.scrollview.contentinset = contentinsets; self.scrollview.scrollindicatorinsets = contentinsets; } </code></pre>

<p>это просто:-</p><p>в textfielddidbeginediting: -</p><pre><code>self.view.frame=cgrectmake(self.view.frame.origin.x, self.view.frame.origin.y-150, self.view.frame.size.width, self.view.frame.size.height); </code></pre><p>в textfieldshouldendediting: -</p><pre><code>self.view.frame=cgrectmake(self.view.frame.origin.x, self.view.frame.origin.y+150, self.view.frame.size.width, self.view.frame.size.height); </code></pre>

<p>используя iqkeyboardmanager, uitextfield и uitextview автоматически прокручиваются при появлении клавиатуры. ссылка git: <a href="https://github.com/hackiftekhar/iqkeyboardmanager">https://github.com/hackiftekhar/iqkeyboardmanager</a> .</p><p>pod: pod 'iqkeyboardmanager' # ios8 и более поздние версии</p><p>модуль 'iqkeyboardmanager', '3.3.7' # ios7</p>

<p>простое решение для scrollview с textfields ниже, не нужно никаких ограничений или активного текстового поля и т.д ... </p><pre><code> override func viewwillappear(\_ animated: bool){ super.viewwillappear(animated) registerforkeyboardnotifications(); } override func viewwilldisappear(\_ animated: bool) { super.viewwilldisappear(animated) deregisterfromkeyboardnotifications(); } //mark:- keyboard delegate methods func registerforkeyboardnotifications(){ //adding notifies on keyboard appearing notificationcenter.default.addobserver(self, selector: #selector(keyboardwasshown(notification:)), name: nsnotification.name.uikeyboardwillshow, object: nil) notificationcenter.default.addobserver(self, selector: #selector(keyboardwillbehidden(notification:)), name: nsnotification.name.uikeyboardwillhide, object: nil) } func deregisterfromkeyboardnotifications(){ //removing notifies on keyboard appearing notificationcenter.default.removeobserver(self, name: nsnotification.name.uikeyboardwillshow, object: nil) notificationcenter.default.removeobserver(self, name: nsnotification.name.uikeyboardwillhide, object: nil) } func keyboardwasshown(notification: nsnotification){ var info = notification.userinfo! let keyboardsize = (info[uikeyboardframebeginuserinfokey] as? nsvalue)?.cgrectvalue.size var contentinset:uiedgeinsets = self.scrregister.contentinset contentinset.bottom = (keyboardsize?.height)! scrregister.contentinset = contentinset } func keyboardwillbehidden(notification: nsnotification) { var contentinset:uiedgeinsets = self.scrregister.contentinset contentinset.bottom = 0 scrregister.contentinset = contentinset } </code></pre>

<p>пожалуйста, следуйте этим шагам, это может быть полезно .. поместите одно представление, затем поместите свое текстовое поле в это представление и определите событие делегатом, когда ваша клавиатура поднимается, в это время мгновенно оживите представление вверх (вы можете назначить некоторую позицию для этого представления также), то ваш вид будет подниматься до этой позиции. сделайте то же самое для анимации вида вниз.</p><p>спасибо</p>

<p> <a href="https://medium.com/@abhimuralidharan/ios-swift-3-0-keyboard-management-f3c35950b806#.x42dni1x9">версия swift 3.0</a> кода управления клавиатурой apple здесь: <a href="https://github.com/abhimuralidharan/floatingtf">floatingtf</a> используется в приведенном ниже коде - это текстовое поле, основанное на дизайне материала в ios.</p><pre><code>import uikit class signupviewcontroller: uiviewcontroller, uitextfielddelegate { //mark: - iboutlet: @iboutlet weak var emailtf: floatingtf! @iboutlet weak var passwordtf: floatingtf! @iboutlet weak var dobtf: floatingtf! @iboutlet weak var scrollview: uiscrollview! //mark: - variable: var activetextfield: uitextfield! //mark: - viewcontroller lifecycle: override func viewdidload() { super.viewdidload() emailtf.delegate = self passwordtf.delegate = self dobtf.delegate = self } override func viewwillappear(\_ animated: bool) { super.viewwillappear(animated) registerkeyboardnotifications() } override func viewwilldisappear(\_ animated: bool) { super.viewwilldisappear(animated) deregisterkeyboardnotifications() } //mark: - keyboard notification observer methods fileprivate func registerkeyboardnotifications() { notificationcenter.default.addobserver(self, selector: #selector(signupviewcontroller.keyboardwillshow), name: nsnotification.name.uikeyboardwillshow, object: nil) notificationcenter.default.addobserver(self, selector: #selector(signupviewcontroller.keyboardwillhide), name: nsnotification.name.uikeyboardwillhide, object: nil) } fileprivate func deregisterkeyboardnotifications() { notificationcenter.default.removeobserver(self, name: .uikeyboardwillshow, object: self.view.window) notificationcenter.default.removeobserver(self, name: .uikeyboarddidhide, object: self.view.window) } func keyboardwillshow(notification: nsnotification) { let info: nsdictionary = notification.userinfo! as nsdictionary let value: nsvalue = info.value(forkey: uikeyboardframebeginuserinfokey) as! nsvalue let keyboardsize: cgsize = value.cgrectvalue.size let contentinsets: uiedgeinsets = uiedgeinsetsmake(0.0, 0.0, keyboardsize.height, 0.0) scrollview.contentinset = contentinsets scrollview.scrollindicatorinsets = contentinsets // if active text field is hidden by keyboard, scroll it so it's visible // your app might not need or want this behavior. var arect: cgrect = self.view.frame arect.size.height -= keyboardsize.height let activetextfieldrect: cgrect? = activetextfield?.frame let activetextfieldorigin: cgpoint? = activetextfieldrect?.origin if (!arect.contains(activetextfieldorigin!)) { scrollview.scrollrecttovisible(activetextfieldrect!, animated:true) } } func keyboardwillhide(notification: nsnotification) { let contentinsets: uiedgeinsets = .zero scrollview.contentinset = contentinsets scrollview.scrollindicatorinsets = contentinsets } //mark: - uitextfield delegate methods func textfieldshouldreturn(\_ textfield: uitextfield) -> bool { if textfield == emailtf { passwordtf.becomefirstresponder() } else if textfield == passwordtf { dobtf.becomefirstresponder() } else { self.view.endediting(true) } return true } func textfielddidbeginediting(\_ textfield: uitextfield) { activetextfield = textfield scrollview.isscrollenabled = true } func textfielddidendediting(\_ textfield: uitextfield) { activetextfield = nil scrollview.isscrollenabled = false } } </code></pre>

<p>это сработало для меня:</p><pre><code>func setupkeyboardnotifications() { nsnotificationcenter.defaultcenter().addobserver(self, selector: selector("keyboardwasshown:"), name: uikeyboarddidshownotification, object: nil) nsnotificationcenter.defaultcenter().addobserver(self, selector: selector("keyboardwillbehidden:"), name: uikeyboardwillhidenotification, object: nil) } func keyboardwasshown(anotification:nsnotification) { let info = anotification.userinfo let infonsvalue = info![uikeyboardframebeginuserinfokey] as nsvalue let kbsize = infonsvalue.cgrectvalue().size uiview.beginanimations(nil, context: nil) uiview.setanimationduration(0.3) var rect : cgrect = self.view.frame rect.size.height -= kbsize.height self.view.frame = rect uiview.commitanimations() } func keyboardwillbehidden(anotification:nsnotification) { let info = anotification.userinfo let infonsvalue = info![uikeyboardframebeginuserinfokey] as nsvalue let kbsize = infonsvalue.cgrectvalue().size uiview.beginanimations(nil, context: nil) uiview.setanimationduration(0.3) var rect : cgrect = self.view.frame rect.size.height += kbsize.height self.view.frame = rect uiview.commitanimations() } </code></pre>

<p>если текстовое поле должно быть внизу экрана, то самым волшебным решением является переопределение на вашем контроллере вида:</p><pre><code>override var inputaccessoryview: uiview? { return <yourtextfield> } </code></pre>

<p>мы можем пользовательский код для swift 4.1</p><pre><code> let keyboardsize = 80.0 func keyboardwillshow() { if view.frame.origin.y >= 0 { viewmovedup = true } else if view.frame.origin.y < 0 { viewmovedup = false } } func keyboardwillhide() { if view.frame.origin.y >= 0 { viewmovedup = true } else if view.frame.origin.y < 0 { viewmovedup = false } } func textfielddidbeginediting(\_ textfield: uitextfield) { if sender.isequal(mailtf) { //move the main view, so that the keyboard does not hide it. if view.frame.origin.y >= 0 { viewmovedup = true } } } func setviewmovedup(\_ movedup: bool) { uiview.beginanimations(nil, context: nil) uiview.setanimationduration(0.3) // if you want to slide up the view let rect: cgrect = view.frame if movedup { rect.origin.y -= keyboardsize rect.size.height += keyboardsize } else { // revert back to the normal state. rect.origin.y += keyboardsize rect.size.height -= keyboardsize } view.frame = rect uiview.commitanimations() } func viewwillappear(\_ animated: bool) { super.viewwillappear(animated) notificationcenter.default.addobserver(self, selector:#selector(self.keyboardwillshow), name: .uikeyboardwillshow, object: nil) notificationcenter.default.addobserver(self, selector:#selector(self.keyboardwillhide), name: .uikeyboardwillhide, object: nil) } func viewwilldisappear(\_ animated: bool) { super.viewwilldisappear(animated) notificationcenter.default.removeobserver(self, name: .uikeyboardwillshow, object: nil) notificationcenter.default.removeobserver(self, name: .uikeyboardwillhide, object: nil) } </code></pre>

<p>в (bool) textfieldshouldbeginediting: (uitextfield *) textfield</p><pre><code>if (textfield.frame.origin.y > self.view.frame.size.height - 216) { if (screenheight>500) scrollview.contentsize = cgsizemake(0.0, scrollview.contentsize.height + 100); else scrollview.contentsize = cgsizemake(0.0, scrollview.contentsize.height + 216); cgpoint scrollpoint = cgpointmake(0.0,(textfield.frame.origin.y - (self.view.frame.size.height - 216 - textfield.frame.size.height - 20))); [scrollview setcontentoffset:scrollpoint animated:yes]; } [scrollview setscrollenabled:yes]; </code></pre><p>при отставке keyboard вам нужно написать ниже код</p><pre><code>scrollview.contentsize = cgsizemake(0.0, 640); cgpoint scrollpoint = cgpointmake(0.0,0.0); [scrollview setcontentoffset:scrollpoint animated:yes]; </code></pre>

<p>в ios перемещение клавиатуры вверх и возврат к текстовым полям в приложении немного сбивает с толку и требует реализации нескольких методов для одного и того же .. также вам нужно сделать делегат в текстовое поле и позаботиться об этом .. код для этого будет повторяться в каждый класс, где существуют текстовые поля.</p><p>я предпочитаю использовать этот элемент управления github. </p><p> <a href="https://github.com/hackiftekhar/iqkeyboardmanager">iqkeyboard</a> </p><p>в котором нам не нужно ничего делать. - <strong>просто перетащите элемент управления drop</strong> в ваш проект и соберите. - он сделает все для вашего приложения.</p><p>спасибо </p><p>может быть, это будет полезно.</p>

<p>я нашел @dk\_ решением, которое я начал использовать. однако есть предположение, что scrollview охватывает весь вид. это был не тот случай для меня. я только хотел scrollview на тот случай, если клавиатура закрыла нижнее текстовое поле на экране входа в систему. таким образом, мое представление контента было того же размера, что и мое представление прокрутки, которое было меньше, чем основное представление.</p><p>это также не учитывало ландшафтов, из-за чего у меня начались проблемы. после игры с ним в течение нескольких дней, это мой метод <code>keyboardwasshown:</code>.</p><pre><code>- (void)keyboardwasshown:(nsnotification*)anotification { // a lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602 cgfloat height = 0; nsdictionary* info = [anotification userinfo]; cgrect kbframerect = [[info objectforkey:uikeyboardframeenduserinfokey] cgrectvalue]; cgrect kbboundsrect = [self.view convertrect:kbframerect fromview:nil]; // convert frame from window to view coordinates. cgrect scrollrect = scrollview.frame; cgrect intersect = cgrectintersection(kbboundsrect, scrollrect); if (!cgrectisnull(intersect)) { height = intersect.size.height; uiedgeinsets contentinsets = uiedgeinsetsmake(0.0, 0.0, height, 0.0); scrollview.contentinset = contentinsets; scrollview.scrollindicatorinsets = contentinsets; } // figure out what the view rectangle is for the scrollview cgpoint contentoffset = scrollview.contentoffset; cgrect visiblerect = cgrectoffset(scrollrect, contentoffset.x, contentoffset.y); // i'm not 100% sure if this is needed/right. my scrollview was always at the top in testing. visiblerect.size.height -= height; cgrect activerect = activefield.frame; if (!cgrectcontainsrect(visiblerect, activerect)) { [self.scrollview scrollrecttovisible:activefield.frame animated:yes]; } } </code></pre><p>у меня также были некоторые трудности при работе с автоматической версткой. если у меня нет правильной раскладки, я не получаю ожидаемую прокрутку. одна вещь, которая облегчила жизнь, состояла в том, чтобы поместить все элементы, которые должны были быть прокручены, в один вид, и поместил это как единственный элемент в представлении прокрутки. я назвал это единственное представление «представлением содержания».</p><p>я думаю, что ключевым моментом было то, что представление контента имело заданную ширину и высоту. это позволило представлению прокрутки точно знать, сколько контента имело дело с. это немного отходит от обычных макетов. обычно представления пытаются занять как можно больше места. с содержимым представления прокрутки вы пытаетесь заставить представление максимально ограничиться. представление содержимого позволяет вам положить этому конец. поэтому я присвоил высоте 248 и использовал стандартную ширину экрана 320 в качестве ширины.</p><p>макеты, которые в конечном итоге работали для меня, были такими:</p><ul> <li>прокрутка от просмотра к суперпредставлению: в основном я дал ограничения сверху, слева и справа . <ul> <li><code>horizontal space - view - scroll view</code> (0)</li> <li><code>vertical space - view - scroll view</code> (0)</li> <li><code>horizontal space - scroll view - view</code> (0)</li> </ul></li> <li>высота вида прокрутки: я устанавливаю вид прокрутки с постоянной высотой. я не знаю, было ли это действительно необходимо, но оно получило границы самого представления прокрутки . <ul> <li><code>height - (248) - scroll view</code></li> </ul></li> <li>представление содержимого для представления прокрутки: я дал константы со всех сторон, сверху, слева, снизу и справа . <ul> <li><code>vertical space - view - scroll view</code> (0)</li> <li><code>vertical space - scroll view - view</code> (0)</li> <li><code>horizontal space - view - scroll view</code> (0)</li> <li><code>horizontal space - scroll view - view</code> (0)</li> </ul></li> <li>размеры представления содержимого. <ul> <li><code>height - (248) - view</code></li> <li><code>width - (320) - view</code></li> </ul></li> </ul>

<p>вы можете использовать этот простой git-репозиторий: <a href="https://github.com/hackiftekhar/iqkeyboardmanager">https://github.com/hackiftekhar/iqkeyboardmanager</a> </p><p>это библиотека, которая автоматически управляет всеми перемещениями полей.</p><p>согласно их readme, интеграция очень проста:</p><blockquote> <p><strong>без необходимости ввода какого-либо кода</strong> и никаких дополнительных настроек не требуется. чтобы использовать iqkeyboardmanager вам <strong>просто нужно добавить исходные файлы в ваш проект</strong></p> </blockquote><p>хотя это очень хороший элемент управления, в некоторых случаях он вызывает конфликт, как в контроллерах представления с представлением прокрутки. это иногда меняет размер контента. тем не менее, вы можете пойти на это, и попробовать это в соответствии с вашими требованиями, может быть, вы могли бы сделать то, что я пропустил.</p>

<p>смотрите <code>uicatalogview</code> примеры живого и загруженного iphone</p>

<p>у меня была проблема с возвратом к основному виду по умолчанию при изменении текстового поля или редактировании его содержимого (например, текстовое поле телефона и добавление знака «-», и представление возвращается к покрытию текстовых полей) я, наконец, преодолел это с помощью автоматического макета и постоянные изменения ограничений, а не размер кадра или положение в функциях делегатов уведомлений, например:</p><p>постскриптум я не использую scrollview, просто перемещаю взгляд вверх, но он должен работать аналогично</p><pre><code>func keyboardwillshow(notification: nsnotification) { if let keyboardsize = (notification.userinfo?[uikeyboardframebeginuserinfokey] as? nsvalue)?.cgrectvalue { if !keyboardisshown{ self.infoviewtopconstraint.constant -= keyboardsize.height self.infoviewbottomconstraint.constant += keyboardsize.height self.view.setneedslayout() self.view.layoutifneeded() keyboardisshown = true } } func keyboardwillhide(notification: nsnotification) { if keyboardisshown { self.infoviewtopconstraint.constant += keyboardsize.height self.infoviewbottomconstraint.constant -= keyboardsize.height self.view.setneedslayout() self.view.layoutifneeded() keyboardisshown = false } </code></pre>

<p>на этот вопрос уже есть много ответов, некоторые сказали, что используют представление прокрутки, некоторые сказали, что используют третью библиотеку.</p><p>но для меня решение идеи должно быть <code>uitableviewcontroller</code> со статическими ячейками.</p><p>вы разделяете ваш пользовательский интерфейс на несколько частей и помещаете их в tableviewcells один за другим, чем вам больше не нужно беспокоиться о клавиатуре, tableviewcontroller будет управлять вами автоматически. </p><p>может быть немного сложно рассчитать отступы, поля, высоту ячеек, но если с математикой все в порядке, все просто.</p>

<p>я использую swift и автоматический макет (но не могу комментировать предыдущий ответ swift); вот как я делаю это без просмотра прокрутки:</p><p>я размещаю свою форму в ib с вертикальными ограничениями между полями, чтобы разделить их. я добавляю вертикальное ограничение из самого верхнего поля в представление контейнера и создаю для него выход (topspaceforformconstraint в приведенном ниже коде). все, что нужно, это обновить это ограничение, которое я делаю в анимационном блоке для мягкого движения nice. проверка высоты не является обязательной, конечно, в этом случае мне нужно было сделать это только для наименьшего размера экрана.</p><p>это можно вызвать, используя любой из обычных методов textfielddidbeginediting или keyboardwillshow. </p><pre><code>func setformheight(top: cgfloat) { let height = uiscreen.mainscreen().bounds.size.height // restore text input fields for iphone 4/4s if (height < 568) { uiview.animatewithduration(0.2, delay: 0.0, options: nil, animations: { self.topspaceforformconstraint.constant = top self.view.layoutifneeded() }, completion: nil) } } </code></pre>

<p>я не видел этой возможности здесь, поэтому я добавляю ее, так как я попробовал методы в ответах, но спустя часы обнаружил, что в xcode 5 в ios6/7 есть <em>намного</em> более простой способ: используйте nslayoutconstraints.</p><p>смотрите: <a href="https://stackoverflow.com/questions/12924649/autolayout-constraint-keyboard">ограничение autolayout - клавиатура</a> </p><p>вот мой код:</p><p>.m файл:</p><pre><code>// called when the uikeyboardwillshownotification is sent. - (void)keyboardwillbeshown:(nsnotification*)anotification { nslog(@"keyboardwillbeshown:"); [self.phonenumberlabeloutlet sethidden:true]; cgfloat heightoflabel = self.phonenumberlabeloutlet.frame.size.height; for( nslayoutconstraint* thisconstraint in self.topelementsverticaldistancefromtoplayoutconstraint ) { thisconstraint.constant -= heightoflabel; } nsdictionary* info = [anotification userinfo]; cgsize kbsize = [[info objectforkey:uikeyboardframebeginuserinfokey] cgrectvalue].size; cgfloat oldconstant = [self.signinyconstraint constant]; self.signinyconstraint.constant = oldconstant + kbsize.height; [self.view setneedsupdateconstraints]; nstimeinterval duration = [[info objectforkey:uikeyboardanimationdurationuserinfokey] doublevalue]; [uiview animatewithduration:duration animations:^{ [self.view layoutifneeded]; }]; } </code></pre><p>.h файл:</p><pre><code>#import <uikit/uikit.h> @interface signinviewcontroller : uiviewcontroller { uitextfield* \_activefield; } - (void)signincallback:(nsobject*)object; @property (weak, nonatomic) iboutlet uilabel *phonenumberlabeloutlet; @property (weak, nonatomic) iboutlet uiactivityindicatorview *activityindicatoroutlet; @property (weak, nonatomic) iboutlet uitextfield *useridtextfieldoutlet; @property (weak, nonatomic) iboutlet uitextfield *passwordtextfieldoutlet; @property (weak, nonatomic) iboutlet uibutton *signinbutton; @property (weak, nonatomic) iboutlet nslayoutconstraint *signinyconstraint; @property (strong, nonatomic) iboutletcollection(nslayoutconstraint) nsarray *topelementsverticaldistancefromtoplayoutconstraint; @end </code></pre>

<p>я немного опоздал. вы должны добавить scrollview на ваш viewcontroller. </p><p>вы должны реализовать ниже 2 метод.</p><p>метод делегата textfield.</p><pre><code> - (void)textfielddidbeginediting:(uiview *)textfield { [self scrollviewfortextfield:reenterpintextfield]; } </code></pre><p>и затем вызовите ниже метон в методе делегата.</p><pre><code> - (void)scrollviewfortextfield:(uiview *)textfield { nsinteger keyboardheight = keyboard\_height; if ([textfield uitextfield.class]) { keyboardheight += ((uitextfield *)textfield).keyboardcontrol.activefield.inputaccessoryview.frame.size.height; } cgrect screenframe = [uiscreen mainscreen].bounds; cgrect arect = (cgrect){0, 0, screenframe.size.width, screenframe.size.height - ([uiapplication sharedapplication].statusbarhidden ? 0 : [uiapplication sharedapplication].statusbarframe.size.height)}; arect.size.height -= keyboardheight; cgpoint relativeorigin = [uiview getoriginrelativetoscreenbounds:textfield]; cgpoint bottompointoftextfield = cgpointmake(relativeorigin.x, relativeorigin.y + textfield.frame.size.height); if (!cgrectcontainspoint(arect, bottompointoftextfield) ) { cgpoint scrollpoint = cgpointmake(0.0, bottompointoftextfield.y -arect.size.height); [contentslidingview setcontentoffset:scrollpoint animated:yes]; } } </code></pre>

<p>добавьте мои 5 центов :)</p><p>я всегда предпочитаю использовать tableview для inputtextfield или scrollview. в сочетании с уведомлениями вы можете легко управлять таким поведением. (обратите внимание, если вы используете статические ячейки в tableview, такое поведение будет работать автоматически).</p><pre><code>// mark: - notifications fileprivate func registernotificaitions() { notificationcenter.default.addobserver(self, selector: #selector(addremotecontrolviewcontroller.keyboardwillappear(\_:)), name: nsnotification.name.uikeyboardwillshow, object: nil) notificationcenter.default.addobserver(self, selector: #selector(addremotecontrolviewcontroller.keyboardwilldisappear), name: nsnotification.name.uikeyboardwillhide, object: nil) } fileprivate func unregisternotifications() { notificationcenter.default.removeobserver(self) } @objc fileprivate func keyboardwillappear(\_ notification: notification) { if let keyboardheight = (notification.userinfo?[uikeyboardframeenduserinfokey] as? nsvalue)?.cgrectvalue.height { view.layoutifneeded() uiview.animate(withduration: 0.3, animations: { let heightinset = keyboardheight - self.adddevicebutton.frame.height self.tableview.contentinset = uiedgeinsets(top: 0, left: 0, bottom: heightinset, right: 0) self.view.layoutifneeded() }, completion: nil) } } @objc fileprivate func keyboardwilldisappear() { view.layoutifneeded() uiview.animate(withduration: 0.3, animations: { self.tableview.contentinset = uiedgeinsets.zero self.view.layoutifneeded() }, completion: nil) } </code></pre>