Metin alanı seçildiğinde UITableView kaydırma yapma


251

Bir çok deneme yanılma sonrasında pes ediyorum ve soruyu soruyorum. Benzer sorunları olan birçok insan gördüm ama tüm cevapların doğru çalışmasını sağlayamıyorum.

UITableViewÖzel hücrelerden oluşan bir tane var . Hücreler yan yana 5 metin alanından oluşur (bir tür ızgara gibi).

Altındaki hücreleri kaydırmaya ve düzenlemeye çalıştığımda, hücrelerimin UITableViewklavyenin üzerine düzgün bir şekilde yerleştirilmesini sağlayamıyorum.

Görünüm boyutlarını değiştirme, vb hakkında konuşurken birçok cevap gördüm ... ama hiçbiri şimdiye kadar güzel çalıştı.

Herkes bunu somut bir kod örneği ile yapmanın "doğru" yolunu açıklığa kavuşturabilir mi?



@ChrisP Bu bağlantı, iOS 4.0
Bae

Bu kod yardımcı olabilir: gist.github.com/TimMedcalf/9505416
landonandrey

Aşağıdaki URL'yi takip edin, işe yarayacak: stackoverflow.com/questions/48922266/…
Venkatesh G

Yanıtlar:


126

UIViewController yerine UITableViewController kullanırsanız, bunu otomatik olarak yapar.


13
Bunu denedin mi ve işe yaramadı mı? Yoksa çözüm inanmak için çok mu basit? UIViewController yerine UITableViewController'ı uzatmanız yeterlidir; metin alanlarını içeren hücre, metin alanları ilk yanıt verdiğinde klavyenin üzerinde kayar. Ek kod gerekmez.
Sam Ho

3
Evet, ancak özellikle iPad'de UITableViewController'ı içermeyen bunu yapmanın bir yoluna ihtiyacımız var.
Bob Spryn

13
Açıklamak gerekirse, bir tablo görünümünü her kullandığınızda, özellikle bir iPad'de tam ekran olması gerektiğini söylemek makul bir cevap değildir. Bunu yapmayan harika uygulama örnekleri vardır. Örneğin, iPad'deki Kişiler uygulaması da dahil olmak üzere Apple'ın birçoğu.
Bob Spryn

32
[Super viewWillAppear: YES] değerini geçersiz kılarsanız çalışmaz. Bunun dışında işe yaramalı.
Rambatino

18
ViewWillAppear: (BOOL) animasyonu geçersiz kılarsanız, [super viewWillAppear: animated]; :)
Médéric Petit

93

Kaydırma yapan işlev çok daha basit olabilir:

- (void) textFieldDidBeginEditing:(UITextField *)textField {
    UITableViewCell *cell;

    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
        cell = (UITableViewCell *) textField.superview.superview;

    } else {
        // Load resources for iOS 7 or later
        cell = (UITableViewCell *) textField.superview.superview.superview; 
       // TextField -> UITableVieCellContentView -> (in iOS 7!)ScrollView -> Cell!
    }
    [tView scrollToRowAtIndexPath:[tView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

Bu kadar. Hiç hesaplama yok.


2
Ve neden olmasın?! Sadece UITableViewScrollPositionTop yerine UITableViewScrollPositionMiddle yazın. Elbette görünür alanı ayarlamak için UITableView'ı yeniden ölçeklendirmeniz yeterlidir.
Mihai Damian

3
Bir UITableViewController, klavye gösterildiğinde tablo görünümünü yeniden boyutlandırmaya özen göstermişse işe yaramıyor gibi görünüyor: denetleyici görünür boyutu a ile küçültür; bu contentInset, visibleRowsveya sorarken görünüşte dikkate alınmaz indexPathsForVisibleRows.
Julian D.

16
Tablo görünümündeki son birkaç satır için çalışmaz. Klavye hala klavyenin üzerinde kaydırılamayan tüm satırları gizleyecektir.
Alex Zavatone

3
Otomatik kaydırma davranışının tablonun son birkaç satırında çalışmasını sağlamak için, bu satırların ne zaman düzenlenmeye başladığını tespit edin ve tablo görünümünün sonuna belirli bir yükseklikte boş bir görünümle bir altbilgi ekleyin. Bu, tablo görünümünün hücreleri doğru yere kaydırmasına izin verecektir.
Sammio2

10
Hücreye gerçekten ulaştığınızdan emin olmadıkça, denetlemek için bir çağrı zincirinden hücreye gitmek güvenilmezdir. Bkz. Stackoverflow.com/a/17757851/1371070 ve stackoverflow.com/a/17758021/1371070
Cezar

70

Ben çok benzer bir şey yapıyorum genel, kod için özel bir şey hesaplamak gerek yok. Sadece koddaki açıklamaları kontrol edin:

MyUIViewController.h içinde

@interface MyUIViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
{
     UITableView *myTableView;
     UITextField *actifText;
}

@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet UITextField *actifText;

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField;
- (IBAction)textFieldDidEndEditing:(UITextField *)textField;

-(void) keyboardWillHide:(NSNotification *)note;
-(void) keyboardWillShow:(NSNotification *)note;

@end

MyUIViewController.m içinde

@implementation MyUIViewController

@synthesize myTableView;
@synthesize actifText;

- (void)viewDidLoad 
{
    // Register notification when the keyboard will be show
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillShow:)
                                          name:UIKeyboardWillShowNotification
                                          object:nil];

    // Register notification when the keyboard will be hide
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillHide:)
                                          name:UIKeyboardWillHideNotification
                                          object:nil];
}

// To be link with your TextField event "Editing Did Begin"
//  memoryze the current TextField
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.actifText = textField;
}

// To be link with your TextField event "Editing Did End"
//  release current TextField
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.actifText = nil;
}

-(void) keyboardWillShow:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    // Start animation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Reduce size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height -= keyboardBounds.size.height;
    else 
        frame.size.height -= keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    // Scroll the table view to see the TextField just above the keyboard
    if (self.actifText)
      {
        CGRect textFieldRect = [self.myTableView convertRect:self.actifText.bounds fromView:self.actifText];
        [self.myTableView scrollRectToVisible:textFieldRect animated:NO];
      }

    [UIView commitAnimations];
}

-(void) keyboardWillHide:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Increase size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height += keyboardBounds.size.height;
    else 
        frame.size.height += keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    [UIView commitAnimations];
}

@end

Swift 1.2+ sürümü:

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var activeText: UITextField!
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillShow:"),
            name: UIKeyboardWillShowNotification,
            object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillHide:"),
            name: UIKeyboardWillHideNotification,
            object: nil)
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        activeText = textField
    }

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

    func keyboardWillShow(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height -= keyboardSize.height
            tableView.frame = frame
            if activeText != nil {
                let rect = tableView.convertRect(activeText.bounds, fromView: activeText)
                tableView.scrollRectToVisible(rect, animated: false)
            }
            UIView.commitAnimations()
        }
    }

    func keyboardWillHide(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height += keyboardSize.height
            tableView.frame = frame
            UIView.commitAnimations()
        }
    }
}

bildirimleri kullanmak ve cihaz yönünü dahil ederken klavye yüksekliğini elde etmek harikaydı, bunun için teşekkürler! kaydırma kısmı nedense benim için çalışmadı, bu yüzden bunu kullanmak zorunda kaldı:[tableView scrollToRowAtIndexPath: indexPath atScrollPosition: UITableViewScrollPositionMiddle animated: YES];
taber

7
Sanırım burada en iyi cevap bu. Çok temiz. Sadece iki şey: 1) viewDidLoad [süper viewDidLoad] çağırmıyor ve 2) frame.size.height satırlarında bazı tabbar matematik vardı. Aksi takdirde mükemmel! Teşekkürler.
toxaq

3
Toxaq'da yapılan değişiklik şu şekildedir: MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate]; CGFloat tabBarHeight = appDelegate.tabBarController.tabBar.frame.size.height; Ardından, klavye yüksekliğini kullandığınız her yerde tabBarHeight'ı klavye yüksekliğinden çıkarın.
Steve N

1
Kullanıcı metin alanına dokunursanız mükemmel çalışır. ancak kullanıcı dönüş tuşuna basmadan başka bir metin alanına dokunursa, tablo görünümünü küçültür.
Bhavin Ramani

1
@BhavinRamani kabul etti. Klavyenin görüntülenip görüntülenmediğini hatırlamak için basit bir boolean özelliği ekledim ve gereksiz olduğunda kodun yeniden yürütülmesini atladım.
Kirli Henry

46

Bartłomiej Semańczyk çözümüne dayanan Swift 3 için en basit çözüm :

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

// MARK: Keyboard Notifications

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.2, animations: {
        // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
        self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    })
}

Küçük bir detay ... NotificationBunun yerine kullanmak NSNotificationdaha fazla "Swift 3-y" :-)
Nicolas Miari

Bu, bir navbar - surround UIView.animate varsa yeniden konumlandırmaya yardımcı olur, eğer let - if let frame = self.navigationController? .NavigationBar.frame {let y = frame.size.height + frame.origin.y}
Sean Dev

rotasyon gerçekleştiğinde yükleme sırasında bir aksaklık olur ve
tablo görünümü manully

İyi çözüm teşekkürler! Not - artık removeObserver yapmanıza gerek yok.
Nick McConnell

44

Aynı sorunu yaşadım ama sadece bir görünümde göründüğünü fark ettim. Bu yüzden denetleyicilerdeki farklılıkları aramaya başladım.

Kaydırma davranışının - (void)viewWillAppear:(BOOL)animatedsüper örnekte ayarlandığını öğrendim .

Bu yüzden böyle uyguladığınızdan emin olun:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // your code
}

Kullanmak Ve o önemli değil UIViewControllerya UITableViewController; UITableViewbir self.view alt görünümü koyarak koyarak kontrol etti UIViewController. Aynı davranıştı. Arama [super viewWillAppear:animated];eksikse görünüm kaymaya izin vermedi .


1
Bu mükemmel çalıştı. İnsanların neden UITableView'ın bunu benim için yapacağını söylediğini merak ediyordum ve bu çözdü. Teşekkürler!
olivaresF

5
Ben de bu problemi yaşadım, bu cevap en üste çıkmalı!
Amiel Martin

Kendi başıma anlamaya çalışırken çok zaman kaybettim ... teşekkürler;)
budidino

+1 biraz ağlamaya başlamıştı, ben bu hatta vardı ama aynı zamanda gerekli [tableViewController viewWillAppear: animated]; çünkü bir UIViewController UITableViewController ekliyorum. artık gözyaşı yok :)
colin lamarre

41

Burada tüm yazıyı okumadım gibi, bu kaçırmış olabilir, ama ben geldi ne aldatıcı basit görünüyor. Ben her durumda test, sıkıcı aracılığıyla koymak değil, ama sadece iyi çalışması gerektiği gibi görünüyor.

tablo görünümünün içeriğini klavye yüksekliğine göre ayarlayın ve ardından hücreyi alta kaydırın:

- (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.myTableView.contentInset = contentInsets;
    self.myTableView.scrollIndicatorInsets = contentInsets;

    [self.myTableView scrollToRowAtIndexPath:self.currentField.indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

ve tabi ki

- (void)keyboardWasHidden:(NSNotification *)aNotification
{
    [UIView animateWithDuration:.3 animations:^(void) 
    {
        self.myTableView.contentInset = UIEdgeInsetsZero;
        self.myTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
    }];
}

bu çok basit mi? bir şey mi kaçırıyorum? şu ana kadar benim için iyi çalışıyor, ama dediğim gibi, sıkıcıdan geçirmedim ...


IMO, bu en iyi çözüm. Değiştireceğim tek şey sabit kodlanmış sürenizdir[aNotification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
Andy

O çok basit. Ama bulduğum bir konu, değişikliği canlandırmayacak contentInsetve kaydırma sınırlarını keskin bir şekilde değiştirmeyecek.
Geek

Bu benim için en iyi çalıştı, ancak birkaç sorun. 1) Nerede "currentField.indexPath" alabilirim bilmiyorum, bu yüzden alan etiketi olarak indexPath.row kaydetmek ve daha sonra indexPath oluşturmak zorunda kaldı. 2) Tablonun üst kısmındaki satırlar için çalışmaz, bunları ekran dışına kaydırır. Sadece currentField'ın indexPath'i ekrana sığabilecek boyuttan daha büyükse kaydırmak için bazı kodlar eklemek zorunda kaldım. 3) manzara ise iPad'de kbSize.Width (yükseklik yerine) kullanmak zorundaydı
Travis M.

üzgünüm, kendi kodumuza öyle alıştık ki bazen unutuyoruz, ha? currentField i ile çalışıyorum geçerli metin alanıdır ve ben bu olduğunu Hücre biliyorum bu yüzden sadece bir NSIndexPath eklediği indexPath i sınıfa eklenen bu bir uzantısıdır.
mickm

Bu, çerçeveleri yalnızca tablo özelliklerini değiştirerek hareket ettirmemek için bir yoldur.
Nextorlg

35

Bence Apple'ın uygulamalarının davranışlarına uygun bir çözüm buldum.

İlk olarak, görünümünüzdeWillAppear: klavye bildirimlerine abone olun, böylece klavyenin ne zaman görüneceğini ve gizleneceğini bilirsiniz ve sistem size klavyenin boyutunu söyler, ancak görünümünüzde kaydını silmeyi unutmayın:.

[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillShow:)
           name:UIKeyboardWillShowNotification
         object:nil];
[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillHide:)
           name:UIKeyboardWillHideNotification
         object:nil];

Aşağıdakine benzer yöntemleri uygulayın, böylece klavye gösterildikten sonra tablonuzun boyutunu görünür alanla eşleşecek şekilde ayarlayın. Burada, klavyenin durumunu ayrı ayrı izliyorum, böylece tabloyu ne zaman ayarlayacağımı kendim seçebilirim, çünkü bu bildirimleri her alan değişikliğinde alırsınız. KeyboardWillHide: uygulamasını unutmayın ve tableView boyutunuzu düzeltmek için uygun bir yer seçin.

-(void) keyboardWillShow:(NSNotification *)note
{
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
    keyboardHeight = keyboardBounds.size.height;
    if (keyboardIsShowing == NO)
    {
        keyboardIsShowing = YES;
        CGRect frame = self.view.frame;
        frame.size.height -= keyboardHeight;

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationDuration:0.3f];
        self.view.frame = frame;
        [UIView commitAnimations];
    }
}

Şimdi kaydırma biti, önce birkaç boyut üzerinde çalışıyoruz, sonra görünür alanda nerede olduğumuzu görüyoruz ve kaydırmak istediğimiz rektifi, metin alanının orta veya üst kısmındaki yarım görünüm olarak ayarlıyoruz. görünümde nerede olduğunu. Bu durumda, bir dizi UITextFields ve bunların kaydını tutan bir numaralandırma vardır, bu nedenle rowHeight'ın satır numarasıyla çarpılması bize bu dış görünümdeki çerçevenin gerçek ofsetini verir.

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame = textField.frame;
    CGFloat rowHeight = self.tableView.rowHeight;
    if (textField == textFields[CELL_FIELD_ONE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_ONE;
    }
    else if (textField == textFields[CELL_FIELD_TWO])
    {
        frame.origin.y += rowHeight * CELL_FIELD_TWO;
    }
    else if (textField == textFields[CELL_FIELD_THREE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_THREE;
    }
    else if (textField == textFields[CELL_FIELD_FOUR])
    {
        frame.origin.y += rowHeight * CELL_FIELD_FOUR;
    }
    CGFloat viewHeight = self.tableView.frame.size.height;
    CGFloat halfHeight = viewHeight / 2;
    CGFloat midpoint = frame.origin.y + (textField.frame.size.height / 2);
    if (midpoint < halfHeight)
    {
        frame.origin.y = 0;
        frame.size.height = midpoint;
    }
    else
    {
        frame.origin.y = midpoint;
        frame.size.height = midpoint;
    }
    [self.tableView scrollRectToVisible:frame animated:YES];
}

Bu oldukça iyi çalışıyor.


Güzel çözüm. Gönderdiğiniz için teşekkürler.
Alex Reynolds

2
UIKeyboardBoundsUserInfoKeyiOS 3.2'den itibaren kullanımdan kaldırılmıştır. Aşağıda mevcut tüm iOS sürümleri ≥ 3.0'da çalışan çözümüme bakın. / @ iPhoneDev
Ortwin Gentz

Bu, olması gerekenden daha karmaşıktı. @ user91083'ün cevabı basitti ve çalışıyor.
Richard Brightwell

1
Bu çözümde küçük bir sorun var. keyboardWillShow AFTER textFieldDidBeginEditing olarak adlandırılır, bu nedenle bazı hücrelere kaydırmak istediğimizde, tableView'in çerçevesi henüz değişmedi, bu yüzden çalışmaz
HiveHicks

35

Kullanabiliyorsanız UITableViewController, işlevselliği ücretsiz olarak alırsınız. Bununla birlikte, bazen, bu sadece bir seçenek değildir, özellikle de yalnızcaUITableView .

Burada sunulan çözümlerin bazıları iOS on4'te, bazıları iPad'de veya yatay modda çalışmıyor, bazıları Bluetooth klavyelerde (kaydırma istemediğimiz yerlerde) çalışmıyor, bazıları çalışmıyor birden çok metin alanı arasında geçiş yaparken çalışır. Herhangi bir çözüm seçerseniz, bu durumları test ettiğinizden emin olun. Bu, çözüm kullanın kullanıldığı içinde InAppSettingsKit :

- (void)_keyboardWillShow:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
        NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
        if (!keyboardFrameValue) {
            keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
        }

        // Reduce the tableView height by the part of the keyboard that actually covers the tableView
        CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            windowRect = IASKCGRectSwap(windowRect);
        }
        CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        }
        CGRect frame = _tableView.frame;
        frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = frame;
        [UIView commitAnimations];

        UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
        NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

        // iOS 3 sends hide and show notifications right after each other
        // when switching between textFields, so cancel -scrollToOldPosition requests
        [NSObject cancelPreviousPerformRequestsWithTarget:self];

        [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)_keyboardWillHide:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = self.view.bounds;
        [UIView commitAnimations];

        [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
    }
}   

İşte InAppSettingsKit'teki sınıfın tam kodu . Test etmek için, yukarıda belirtilen senaryoları test edebileceğiniz "Tam Liste" alt panelini kullanın.


Sabitleri yerine dizeleri kullanmanın yararlı olup olmadığını bilmiyorum, çünkü Apple bazı nedenlerden dolayı dahili olarak String'i değiştirme fikrine gelirse, çözümünüz artık çalışmıyor. Aynı şekilde kullanımdan kaldırıldığında bir uyarı

@iPortable: ideal değil, biliyorum. Tüm sürümler .03.0 üzerinde çalışan daha iyi bir çözüm önerebilir misiniz?
Ortwin Gentz

1
Cazibe gibi çalışır, ancak UIInterfaceOrientationPortraitUpsideDown için değildir. Daha sonra yükseklik küçültme hesaplaması da baş aşağı olmalıdır: CGFloat reduceHeight = keyboardRect.size.height - (CGRectGetMinY (viewRectAbsolute) - CGRectGetMinY (windowRect));
Klaas

Bu, iPad'imde ve Simülatörde (4.3) çok belirgin görsel hatalara sahip. Kullanımı çok dikkat çekicidir. :(
Bob Spryn

Bu çözüm, ekranın altındaki bir araç çubuğunu açıklayacaktır.
pdemarest

24

Swift için en basit çözüm :

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar?.becomeFirstResponder()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
            tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    UIView.animateWithDuration(0.2, animations: { self.table_create_issue.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) })
    // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
    }

Mükemmel çalışıyor, minimum hesaplamalar gerekli. Bu cevabı bitirmek için tablo eklerini geri yükleyen bazı kod ekledim.
Vitalii

En iyi çözüm teşekkürler. Burada bir Swift 3 sürümü
yayınladım

Gördüğüm süper mükemmel çözüm, başkalarını denedim ama bazı sorunları var. Sen ios 10.2 üzerinde mükemmel çözüm.
Wangdu Lin

8

Umarım zaten bunları okuyan bir çözümünüz vardır. Ama çözümümü şu şekilde buldum. Zaten bir hücreniz olmasını bekliyorum UITextField. Hazırlanırken satır dizini metin alanının etiketine tutulur.

cell.textField.tag = IndexPath.row;

Aşağıdaki gibi global kapsamda bir activeTextFieldörnek oluşturun UITextField:

@interface EditViewController (){

    UITextField *activeTextField;

}

Yani, şimdi sadece kodumu kopyala sonunda yapıştır. Ayrıca eklemeyi de unutmayınUITextFieldDelegate

#pragma mark - TextField Delegation

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{

    activeTextField = textField;

    return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField{

    activeTextField = nil;

}

Kayıt klavyesi notifications

#pragma mark - Keyboard Activity

- (void)registerForKeyboardNotifications

{

    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWasShown:)

                                             name:UIKeyboardDidShowNotification object:nil];



    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWillBeHidden:)

                                             name:UIKeyboardWillHideNotification object:nil];



}

Kolları Klavye Notifications:

UIKeyboardDidShowNotificationGönderildiğinde çağrılır .

- (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.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

    NSIndexPath *currentRowIndex = [NSIndexPath indexPathForRow:activeTextField.tag inSection:0];

    [self.tableView scrollToRowAtIndexPath:currentRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

}

UIKeyboardWillHideNotificationGönderildiğinde çağrılır

- (void)keyboardWillBeHidden:(NSNotification*)aNotification

{

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

}

Şimdi bir şey bırakılır, Çağrı registerForKeyboardNotificationsgiriş yöntemini ViewDidLoadşöyle yöntemle:

- (void)viewDidLoad {

    [super viewDidLoad];

    // Registering keyboard notification

    [self registerForKeyboardNotifications];

    // Your codes here...

}

İşiniz bitti, umarım textFieldsartık klavye tarafından gizlenmeyeceksiniz.


6

Birkaç cevaptan (özellikle Ortwin Gentz, kullanıcı 98013) ve başka bir gönderiden boşlukları birleştirip doldurmak, bu, Portre veya Manzara modunda bir iPad'de bir SDK 4.3 için kutudan çıkar:

@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
  if (self.isFirstResponder) {        
    return self;     
  }

  for (UIView *subView in self.subviews) {
    UIResponder *firstResponder = [subView findFirstResponder];
    if (firstResponder != nil) {
      return firstResponder;
    }
  }

  return nil;
}
@end

@implementation MyViewController

- (UIResponder *)currentFirstResponder {
  return [self.view findFirstResponder];
}

- (IBAction)editingEnded:sender {
  [sender resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
  [textField resignFirstResponder];
  return NO;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
  UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
  [_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillShow:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {
    NSDictionary* userInfo = [notification userInfo];

    // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
    NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
    if (!keyboardFrameValue) {
      keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
    }

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect frame = _tableView.frame;
    if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
      windowRect = CGRectMake(windowRect.origin.y, windowRect.origin.x, windowRect.size.height, windowRect.size.width);
      viewRectAbsolute = CGRectMake(viewRectAbsolute.origin.y, viewRectAbsolute.origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
    }
    frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = frame;
    [UIView commitAnimations];

    UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
    NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

    // iOS 3 sends hide and show notifications right after each other
    // when switching between textFields, so cancel -scrollToOldPosition requests
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    _topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
    [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillHide:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {

    NSDictionary* userInfo = [notification userInfo];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = self.view.bounds;
    [UIView commitAnimations];

    [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
  }
}   

@end

Bu kodu iOS 4.x'te iyi kullandım, ancak iOS5'te scrolltoOldPosition'da çöküyor çünkü _topmostRowBeforeKeyboardWasShown o anda zaten serbest. Çözümün henüz ne olduğundan emin değilim. Muhtemelen nesne yerine dizini hatırlayın.
Thomas Tempelmann

5

Metin alanlarınızı yerleştirmek için uitableview kullanıyorsanız ( Jeff Lamarche'dan ), temsilci yöntemini kullanarak tablo görünümünü kaydırmanız yeterlidir.

(Not: Metin alanlarım, tablo görünümündeki satırla aynı dizine sahip bir dizide saklanır)

- (void) textFieldDidBeginEditing:(UITextField *)textField
    {

        int index;
        for(UITextField *aField in textFields){

            if (textField == aField){
                index = [textFields indexOfObject:aField]-1;
            }
        }

         if(index >= 0) 
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];

        [super textFieldDidBeginEditing:textField];
    }

TableView çerçevesini güncellemezsiniz. Ardından, klavye gösterildiğinde scrollBars ve kaydırma davranışı yanlış olur. Benim çözümüme bakın.
Ortwin Gentz

5

Klavye bildirimleri çalışır, ancak Apple'ın örnek kodu, kaydırma görünümünün pencerenin kök görünümü olduğunu varsayar. Bu genellikle böyle değildir. Doğru ofseti elde etmek için sekme çubuklarını vb. Telafi etmeniz gerekir.

Göründüğünden daha kolaydır. İşte bir UITableViewController kullandığım kod. HiddenRect ve keyboardShown olmak üzere iki örnek değişkeni vardır.

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification {
    if (keyboardShown)
        return;

    NSDictionary* info = [aNotification userInfo];

    // Get the frame of the keyboard.
    NSValue *centerValue = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
    NSValue *boundsValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    CGPoint keyboardCenter = [centerValue CGPointValue];
    CGRect keyboardBounds = [boundsValue CGRectValue];
    CGPoint keyboardOrigin = CGPointMake(keyboardCenter.x - keyboardBounds.size.width / 2.0,
                                         keyboardCenter.y - keyboardBounds.size.height / 2.0);
    CGRect keyboardScreenFrame = { keyboardOrigin, keyboardBounds.size };


    // Resize the scroll view.
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = scrollView.frame;
    CGRect keyboardFrame = [scrollView.superview convertRect:keyboardScreenFrame fromView:nil];
    hiddenRect = CGRectIntersection(viewFrame, keyboardFrame);

    CGRect remainder, slice;
    CGRectDivide(viewFrame, &slice, &remainder, CGRectGetHeight(hiddenRect), CGRectMaxYEdge);
    scrollView.frame = remainder;

    // Scroll the active text field into view.
    CGRect textFieldRect = [/* selected cell */ frame];
    [scrollView scrollRectToVisible:textFieldRect animated:YES];

    keyboardShown = YES;
}


// Called when the UIKeyboardDidHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
    // Reset the height of the scroll view to its original value
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = [scrollView frame];
    scrollView.frame = CGRectUnion(viewFrame, hiddenRect);

    keyboardShown = NO;
}

UIKeyboardCenterEndUserInfoKeyve UIKeyboardBoundsUserInfoKeyiOS 3.2'den itibaren kullanımdan kaldırılmıştır. Aşağıda mevcut tüm iOS sürümleri ≥ 3.0'da çalışan çözümüme bakın.
Ortwin Gentz

5

Kullanıyorsanız Three20, autoresizesForKeyboardözelliği kullanın . Sadece görünüm denetleyicinizin -initWithNibName:bundleyöntemini ayarlayın

self.autoresizesForKeyboard = YES

Bu şunlarla ilgilenir:

  1. Klavye bildirimlerini dinleme ve tablo görünümünün çerçevesini ayarlama
  2. İlk yanıtlayıcıya kaydırma

Bitti ve bitti.


Burada Three20 nedir? Bunu belirtebilir misiniz?
Mubin Mall

5

Benim yaklaşımım:

Önce UITextField alt sınıfı ve bir indexPath özelliği ekleyin. CellFor ... Yönteminde i indexPath özelliğini teslim eder.

Sonra aşağıdaki kodu ekleyin:

UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:textField.indexPath];

CGPoint cellPoint = [cell convertPoint:textField.center toView:self.tableView];
[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, cellPoint.y-50);}];

textFieldShould / WillBegin ... vb.

Klavye kaybolduğunda, aşağıdakileri tersine çevirmeniz gerekir:

[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, 0);}];

4

Daha akışlı bir çözüm. UITextField delege yöntemlerine kayar, bu nedenle UIKeyboard bildirimleriyle karışıklık gerektirmez.

Uygulama notları:

kSettingsRowHeight - bir UITableViewCell'in yüksekliği.

offsetTarget ve offsetThreshold, kSettingsRowHeight öğesinden çıkarılmıştır. Farklı bir satır yüksekliği kullanıyorsanız, bu değerleri point'in y özelliğine ayarlayın. [alt: satır ofsetini farklı bir şekilde hesaplayın.]

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
CGFloat offsetTarget    = 113.0f; // 3rd row
CGFloat offsetThreshold = 248.0f; // 6th row (i.e. 2nd-to-last row)

CGPoint point = [self.tableView convertPoint:CGPointZero fromView:textField];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
if (point.y > offsetThreshold) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y + kSettingsRowHeight,
                      frame.size.width,
                      frame.size.height);
} else if (point.y > offsetTarget) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y,
                      frame.size.width,
                      frame.size.height);
} else {
    self.tableView.frame = CGRectMake(0.0f,
                      0.0f,
                      frame.size.width,
                      frame.size.height);
}

[UIView commitAnimations];

return YES;

}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
self.tableView.frame = CGRectMake(0.0f,
                  0.0f,
                  frame.size.width,
                  frame.size.height);

[UIView commitAnimations];

return YES;

}


4

UITextField's delegateYöntemi kullanın :

hızlı

func textFieldShouldBeginEditing(textField: UITextField) -> bool {
  let txtFieldPosition = textField.convertPoint(textField.bounds.origin, toView: yourTableViewHere)
  let indexPath = yourTablViewHere.indexPathForRowAtPoint(txtFieldPosition)
  if indexPath != nil {
     yourTablViewHere.scrollToRowAtIndexPath(indexPath!, atScrollPosition: .Top, animated: true)
  }
  return true
}

Objective-C

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
  CGPoint txtFieldPosition = [textField convertPoint:CGPointZero toView: yourTablViewHere];
  NSLog(@"Begin txtFieldPosition : %@",NSStringFromCGPoint(txtFieldPosition));
  NSIndexPath *indexPath = [yourTablViewHere indexPathForRowAtPoint:txtFieldPosition];

  if (indexPath != nil) {
     [yourTablViewHere scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
  return YES;
}

Merhaba, Swift üzerinde çalışmak için bu sorunu yaşıyorum. UITextField'lerim UITableViewCell'e bağlı. Bu kodu benim UIViewController içinde uygulamak, ben UITextFields erişimim yok. Herhangi bir fikir?
Vetuka

4

Swift 4.2 komple çözüm

Protokol seti ile GIST oluşturdum klavye gösterildiğinde, gizlendiğinde veya değiştirildiğinde ek alan eklemekle çalışmayı basitleştiren .

Özellikler :

  • Klavye çerçevesi değişiklikleriyle doğru şekilde çalışır (örn. Emojii → normal klavye gibi klavye yüksekliği değişiklikleri).
  • UITableView örneği için TabBar ve Araç Çubuğu desteği (diğer örneklerde yanlış ekler alırsınız).
  • Dinamik animasyon süresi (sabit kodlanmamış).
  • Sizin için kolayca değiştirilebilen protokole yönelik yaklaşım.

kullanım

Bazı kaydırma görünümü içeren görünüm denetleyicisindeki temel kullanım örneği (tablo görünümü elbette desteklenmektedir).

class SomeViewController: UIViewController {
  @IBOutlet weak var scrollView: UIScrollView!

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    addKeyboardFrameChangesObserver()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeKeyboardFrameChangesObserver()
  }
}

extension SomeViewController: ModifableInsetsOnKeyboardFrameChanges {
  var scrollViewToModify: UIScrollView { return scrollView }
}

Çekirdek: çerçeve değişiklikleri gözlemcisi

KeyboardChangeFrameObserverKlavye çerçevesi her değiştiğinde protokol gösterilecektir (gösterme, gizleme, çerçeve değiştirme dahil).

  1. Çağrı addKeyboardFrameChangesObserver()de viewWillAppear()ya da benzer bir yöntem.
  2. Çağrı removeKeyboardFrameChangesObserver()de viewWillDisappear()ya da benzer bir yöntem.

Uygulama: kaydırma görünümü

ModifableInsetsOnKeyboardFrameChangesprotokol UIScrollViewçekirdek protokole destek ekler . Klavye çerçevesi değiştirildiğinde kaydırma görünümünün iç metinlerini değiştirir.

Sınıfınızın kaydırma görünümünü ayarlaması gerekiyor, kişinin klavye çerçeveleri değiştiğinde ekleri artırılacak / azaltılacak.

var scrollViewToModify: UIScrollView { get }

3

Bir tabloda metin alanlarınız olduğundan, en iyi yol gerçekten tabloyu yeniden boyutlandırmaktır - tableView.frame'i klavyenin boyutuna göre yüksekliği daha küçük olacak şekilde ayarlamanız gerekir (165 piksel civarında olduğunu düşünüyorum) ve ardından klavye kapatıldı.

Ayrıca, kullanıcının kaydırmasını istemiyorsanız, isteğe bağlı olarak tableView için kullanıcı etkileşimini de devre dışı bırakabilirsiniz.


Ben ikinci, ve dinamik olarak klavyenin boyutunu bulmak için UIKeyboardWillShowNotification için kayıt.
benzado

Bildirim nesnesi tarafından döndürülen sayı yine de çalışmıyor. Ya da en azından 2.2 içinde olmadık, döndürülen hatalı bir numara ve (beş ila on piksel kapalı) doğru sabit bir şekilde kodlama yüksekliğini ayarlamak için 165 değeri vardı
Kendall Helmstetter Gelner

2

Bu mükemmel ve iPad'de de çalışır.

- (BOOL)textFieldShouldReturn:(UITextField *)textField 
{

    if(textField == textfield1){
            [accountName1TextField becomeFirstResponder];
        }else if(textField == textfield2){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield3 becomeFirstResponder];

        }else if(textField == textfield3){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield4 becomeFirstResponder];

        }else if(textField == textfield4){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield5 becomeFirstResponder];

        }else if(textField == textfield5){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield6 becomeFirstResponder];

        }else if(textField == textfield6){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield7 becomeFirstResponder];

        }else if(textField == textfield7){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield8 becomeFirstResponder];

        }else if(textField == textfield8){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:6 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield9 becomeFirstResponder];

        }else if(textField == textfield9){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textField resignFirstResponder];
        }

Neden her metin alanı için özel durumlar kullanıyorsunuz ve kullanıyorsunuz? Hücrenin NSIndexPath'inden her metin alanını tanımlayın ve bu if if if ifadesini 2 kod satırına değiştirin. Gerçekten bir cellForRowAtIndexPath çağrısı istersiniz ve sonra hücreden textField öğesini alırsınız.
Alex Zavatone

Aslında bu durumun iOS'ta ne kadar inanılmaz bir şekilde düştüğünü düşünürsek, bu durum için "tamamen yaralanmamış, gülünç derecede gerçek anlamda" kod yazmanın sorun olmadığını düşünüyorum.
Fattie

Bu cevap göz önüne alındığında 6 yıl önce verildi.
WrightsCS

2

Neredeyse aynı yaklaşımı denedim ve aynı şey için daha basit ve daha küçük bir kod buldum. Bir IBOutlet iTextView oluşturdum ve IB'deki UITextView ile ilişkilendirdim.

 -(void)keyboardWillShow:(NSNotification *)notification
    {
        NSLog(@"Keyboard");
        CGRect keyFrame = [[[notification userInfo]objectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue];

        [UIView beginAnimations:@"resize view" context:nil];
        [UIView setAnimationCurve:1];
        [UIView setAnimationDuration:1.0];
        CGRect frame = iTableView.frame;
        frame.size.height = frame.size.height -  keyFrame.size.height;
        iTableView.frame = frame;
        [iTableView scrollRectToVisible:frame animated:YES];
        [UIView commitAnimations];

    }

2

Dolayısıyla, bu mevcut çözümleri kullanmaya çalışan (ve tamamen başarısız olan) saatlerce süren zorlu çalışmalardan sonra nihayet bir şeyler iyi çalıştım ve yeni animasyon bloklarını kullanacak şekilde güncelledim. Cevabım tamamen Ortwin'in yukarıdaki cevabına dayanıyor .

Bu nedenle, yukarıdaki kod her ne olursa olsun benim için işe yaramıyordu. Kurulumum diğerlerine oldukça benziyordu, ama belki bir iPad veya 4.3'te olduğum için ... hiçbir fikrim yok. Biraz tuhaf bir matematik yapıyordum ve masa görüntümü ekrandan çekiyordum.

Çözümümün son sonucuna bakın: http://screencast.com/t/hjBCuRrPC (Lütfen fotoğrafı dikkate almayın. :-P)

Bu yüzden Ortwin'in ne yaptığının özüne gittim, ancak orijin.y & size.height'ı masa görünümümün yüksekliğini klavyenin yüksekliğiyle toplamak için nasıl matematik yaptığını değiştirdim. Pencerenin yüksekliğini bu sonuçtan çıkardığımda, ne kadar kavşak olduğumu anlatıyor. Eğer 0'dan büyükse (aka bazı çakışmalar varsa) kare yüksekliğinin animasyonunu gerçekleştiririm.

Ayrıca, 1) Animasyon bitene kadar hücreye ilerlemek için beklemek ve 2) klavyeyi gizlerken UIViewAnimationOptionBeginFromCurrentState seçeneğini kullanarak yeniden çizme sorunları vardı.

Unutulmaması gereken birkaç şey.

  • _topmostRowBeforeKeyboardWasShown & _originalFrame, başlıkta bildirilen örnek değişkenlerdir.
  • self.guestEntryTableView benim tableView (harici bir dosyadayım)
  • IASKCGRectSwap, Ortwin'in bir çerçevenin koordinatlarını çevirme yöntemidir
  • Yalnızca en az 50 piksel gösterilecekse tableView yüksekliğini güncelleyeceğim
  • UIViewController'da olmadığım için self.view'im yok, bu yüzden sadece tableView'i orijinal çerçevesine döndürüyorum

Yine, eğer Ortwin bu soruna cevap vermemiş olsaydım, bu cevaba yaklaşamazdım. İşte kod:

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.activeTextField = textField;

    if ([self.guestEntryTableView indexPathsForVisibleRows].count) {
        _topmostRowBeforeKeyboardWasShown = (NSIndexPath*)[[self.guestEntryTableView indexPathsForVisibleRows] objectAtIndex:0];
    } else {
        // this should never happen
        _topmostRowBeforeKeyboardWasShown = [NSIndexPath indexPathForRow:0 inSection:0];
        [textField resignFirstResponder];
    }
}

- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.activeTextField = nil;
}

- (void)keyboardWillShow:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];

    NSValue* keyboardFrameValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [self.guestEntryTableView convertRect:self.guestEntryTableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
    if (UIInterfaceOrientationLandscapeLeft == orientation ||UIInterfaceOrientationLandscapeRight == orientation ) {
        windowRect = IASKCGRectSwap(windowRect);
        viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        keyboardFrame = IASKCGRectSwap(keyboardFrame);
    }

    // fix the coordinates of our rect to have a top left origin 0,0
    viewRectAbsolute = FixOriginRotation(viewRectAbsolute, orientation, windowRect.size.width, windowRect.size.height);

    CGRect frame = self.guestEntryTableView.frame;
    _originalFrame = self.guestEntryTableView.frame;

    int remainder = (viewRectAbsolute.origin.y + viewRectAbsolute.size.height + keyboardFrame.size.height) - windowRect.size.height;

    if (remainder > 0 && !(remainder > frame.size.height + 50)) {
        frame.size.height = frame.size.height - remainder;
        float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        [UIView animateWithDuration: duration
                        animations:^{
                            self.guestEntryTableView.frame = frame;
                        }
                        completion:^(BOOL finished){
                            UITableViewCell *textFieldCell = (UITableViewCell*) [[self.activeTextField superview] superview];
                            NSIndexPath *textFieldIndexPath = [self.guestEntryTableView indexPathForCell:textFieldCell];
                            [self.guestEntryTableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
                        }];
    }

}

- (void)keyboardWillHide:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];
    float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration: duration
                          delay: 0.0
                        options: (UIViewAnimationOptionBeginFromCurrentState)
                     animations:^{
                         self.guestEntryTableView.frame = _originalFrame;
                     }
                     completion:^(BOOL finished){
                         [self.guestEntryTableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
                     }];

}   

#pragma mark CGRect Utility function
CGRect IASKCGRectSwap(CGRect rect) {
    CGRect newRect;
    newRect.origin.x = rect.origin.y;
    newRect.origin.y = rect.origin.x;
    newRect.size.width = rect.size.height;
    newRect.size.height = rect.size.width;
    return newRect;
}

CGRect FixOriginRotation(CGRect rect, UIInterfaceOrientation orientation, int parentWidth, int parentHeight) {
    CGRect newRect;
    switch(orientation)
    {
        case UIInterfaceOrientationLandscapeLeft:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), rect.origin.y, rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationLandscapeRight:
            newRect = CGRectMake(rect.origin.x, parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationPortrait:
            newRect = rect;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
            break;
    }
    return newRect;
}

Çerçevesini vb. Güncellemeden önce görünümün koordinat sistemini düzelten FixOriginRotation işlevimi ekledim. İOS Pencere Koordinat Sisteminin cihazla birlikte döndürüldüğünün farkında değildi!
Bob Spryn

2

Bu çözüm benim için çalışıyor, LÜTFEN satırı not edin

[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];

160 değerini, sizinle çalışacak şekilde değiştirebilirsiniz

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
                        bkgndRect.size.height += kbSize.height;
     [activeField.superview setFrame:bkgndRect];
     [tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
   activeField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
 {
     activeField = nil;
 }
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    tableView.contentInset = contentInsets;
    tableView.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
    //bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES];
}

2

Çok ilginç tartışma iş parçacığı, ben de aynı sorun daha kötü olabilir çünkü karşı karşıya

  1. Özel bir hücre kullanıyordum ve metin alanı bunun içindeydi.
  2. UITableViewController yararlanmak olamaz böylece benim gereksinimleri karşılamak için UIViewController kullanmak zorunda kaldı.
  3. Tablo hücremde filtre / sıralama ölçütleri vardı, yani ur hücreleri değişmeye ve dizin yolunu izlemeye devam ediyor ve hepsi yardımcı olmayacak.

Buradaki konuları okuyun ve iPad'de içeriklerimi manzara modunda yukarı itmeme yardımcı olan sürümümü uyguladım . İşte kod (bu aptal geçirmez ve hepsi değil, ama benim sorunum düzeltildi) İlk u düzenleme başlar, metin alanı ur viewcontroller için gönderir ve activefield = theTextField orada ayarlamak için özel hücre sınıfınızda bir temsilci olması gerekir

// SADECE KOLU PEYZAJ MODUNA UYGULANDI

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect aRect = myTable.frame;

    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);

    aRect.size.height -= kbSize.height+50;
// This will the exact rect in which your textfield is present
        CGRect rect =  [myTable convertRect:activeField.bounds fromView:activeField];
// Scroll up only if required
    if (!CGRectContainsPoint(aRect, rect.origin) ) {


            [myTable setContentOffset:CGPointMake(0.0, rect.origin.y) animated:YES];

    }


}

// UIKeyboardWillHideNotification gönderildiğinde çağrılır

- (void)keyboardWillHide:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    myTable.contentInset = contentInsets;
    myTable.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);
    CGRect bkgndRect = activeField.superview.frame;
    bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [myTable setContentOffset:CGPointMake(0.0, 10.0) animated:YES];
}

-anoop4real


2

Google ve Stack Overflow aracılığıyla bulunan bir dizi çözümden bahsettikten sonra böyle bir sorunu kendim çözdüm.

Öncelikle, lütfen UIScrollView cihazınızın bir IBOutlet'ini ayarladığınızdan emin olun, sonra lütfen Apple Doc: Klavye Yönetimi'ne yakından bakın . Son olarak, arka planı kaydırabilir, ancak klavye hala Metin Alanlarını kapsıyorsa, lütfen bu kod parçasına bir göz atın:

// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;

if (aRect.size.height < activeField.frame.origin.y+activeField.frame.size.height) {

    CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y+activeField.frame.size.height-aRect.size.height);

    [scrollView setContentOffset:scrollPoint animated:YES];

Bu parça ve Apple'ın arasındaki temel fark if durumunda yatmaktadır. Apple'ın kaydırma mesafesi ve klavyeyle kaplı metin alanının doğru olup olmadığının hesaplanmasına inanıyorum, bu yüzden yukarıdaki gibi değişiklik yaptım.

Çalışırsa beni bilgilendir


2

Swift ile UITableViewCell'de UITextField'in indexPath'ini Al'dan metin alanının tam noktasını kullanan bir örnek :

func textFieldDidBeginEditing(textField: UITextField) {
    let pointInTable = textField.convertPoint(textField.bounds.origin, toView: self.accountsTableView)
    let textFieldIndexPath = self.accountsTableView.indexPathForRowAtPoint(pointInTable)
    accountsTableView.scrollToRowAtIndexPath(textFieldIndexPath!, atScrollPosition: .Top, animated: true)
}

1

Başka bir kolay yöntem (sadece bir bölümle çalışır)

//cellForRowAtIndexPath
UItextField *tf;
[cell addSubview:tf];
tf.tag = indexPath.row;
tf.delegate = self;

//textFieldDidBeginEditing:(UITextField *)text
[[self.tableView scrollToRowsAtIndexPath:[NSIndexPath indexPathForRow:text.tag in section:SECTIONINTEGER] animated:YES];

1

UITableView'ınız UITableView tarafından değil, bir UITableViewController alt sınıfı tarafından yönetiliyorsa ve metin alanı temsilcisi UITableViewController ise, tüm kaydırmayı otomatik olarak yönetmelidir - diğer tüm yorumların pratikte uygulanması çok zordur.

İyi bir örnek için apple örnek kod projesine bakın: TaggedLocations.

Otomatik olarak kaydırıldığını görebilirsiniz, ancak bunu yapan herhangi bir kod yok gibi görünüyor. Bu proje ayrıca özel tablo görünümü hücrelerine sahiptir, bu nedenle uygulamanızı bir rehber olarak oluşturursanız, istenen sonucu almalısınız.


1

Sam Ho ve Marcel W'nin cevaplarının bir karışımı olan bu işi nasıl yaptım ve berbat koduma yapılan bazı hata düzeltmelerim. Bir UITableViewController kullanıyordum. Klavye gösterildiğinde tablo artık doğru şekilde yeniden boyutlandırılıyor.

1) viewDidLoadEklediğimde:

self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

2) ve içindeki superbenzerleri aramayı unutmuştum . Bunları tekrar ekledim.viewWillAppearawakeFromNib


1

UITableViewControllergerçekten Kaydırma otomatik olarak yapar. A ile karşılaştırıldığında UIViewControlleraradaki fark NavigationController, a kullanırken, kullanarak programlı olarak Navbar-Buttonitems oluşturmanızdır TableViewController.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.