iOS 7 - Come visualizzare un selettore di date in posizione in una vista tabella?


121

Nel video WWDC 2013, Apple suggerisce di visualizzare il selettore in posizione in una vista tabella in iOS 7. Come inserire e animare una vista tra le celle della vista tabella?

In questo modo, dall'app del calendario Apple:

Selettore di date sul posto


Di quale video WWDC si tratta? Sto cercando di capire perché questo è specifico per iOS7 e se c'è un motivo per cui non è stato possibile farlo nelle versioni precedenti.
Clafou

4
Trovato, è "Novità nel design dell'interfaccia utente iOS" (grazie ASCIIwwdc). La logica è che il vecchio stile non sembrava in linea, ma il nuovo aspetto piatto sì.
Clafou

Risposte:


102

Con iOS7, Apple ha rilasciato il codice di esempio DateCell.

inserisci qui la descrizione dell'immagine

Dimostra la visualizzazione formattata degli oggetti data nelle celle della tabella e l'uso di UIDatePicker per modificare tali valori. Come delegato a questa tabella, l'esempio utilizza il metodo "didSelectRowAtIndexPath" per aprire il controllo UIDatePicker.

Per iOS 6.xe versioni precedenti, UIViewAnimation viene utilizzato per far scorrere l'UIDatePicker verso l'alto sullo schermo e verso il basso fuori dallo schermo. Per iOS 7.x, l'UIDatePicker viene aggiunto in linea alla visualizzazione tabella.

Il metodo di azione dell'UIDatePicker imposterà direttamente la proprietà NSDate della cella della tabella personalizzata. Inoltre, questo esempio mostra come usare la classe NSDateFormatter per ottenere l'aspetto formattato della data della cella personalizzata.

inserisci qui la descrizione dell'immagine

Puoi scaricare il codice di esempio qui: DateCell .


Il codice di Apple ha problemi. Vedi la mia risposta di seguito se vuoi mantenere il tuo tableView statico
Aaron Bratcher

1
@AaronBratcher ho appena introdotto Datecell nella mia risposta e non ti aspetti mai di ottenere il codice esatto che desideri. devi modificare e cambiare secondo le tue esigenze. anche la tua soluzione è buona, ma ricorda che non ottieni mai esattamente cosa da altro codice che richiedi.
Nitin Gohel

3
codice di esempio più orribile. Potrebbero fare con qualche consiglio su quando creare un metodo da Code Complete
Anirudha Agashe

2
Wow, il codice Apple è ... beh, diciamo che il focus è sull'effetto della vista tabella. Spero che nessuno si lasci ispirare dal proprio codice in questo progetto di esempio: s
Daniel

84

Puoi utilizzare la risposta che avevo fornito in precedenza di seguito o utilizzare questa nuova classe in Swift che ho creato per rendere questo compito molto più semplice e pulito: https://github.com/AaronBratcher/TableViewHelper


Trovo che il codice fornito da Apple sia problematico in un paio di modi:

  • Non puoi avere un tableView statico perché stanno usando il metodo tableView: cellForRowAtIndexPath
  • Il codice si arresta in modo anomalo se non sono presenti righe aggiuntive sotto l'ultima cella di selezione della data

Per le tabelle di celle statiche, definisco la mia cella di selezione della data sotto la cella di visualizzazione della data e ho un flag che identifica se lo sto modificando. Se lo sono, restituisco un'altezza di cella appropriata, altrimenti restituisco un'altezza di cella pari a zero.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 && indexPath.row == 2) { // this is my picker cell
        if (editingStartTime) {
            return 219;
        } else {
            return 0;
        }
    } else {
        return self.tableView.rowHeight;
    }
}

Quando si fa clic sulla riga che mostra la data, cambio il flag ed eseguo l'animazione di aggiornamento per mostrare il selettore.

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 && indexPath.row == 1) { // this is my date cell above the picker cell
        editingStartTime = !editingStartTime;
        [UIView animateWithDuration:.4 animations:^{
            [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:2 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView reloadData];
        }];
    }
}

Se ho più selettori di data / ora nella stessa tabella, imposto i flag di conseguenza al clic e ricarico le righe appropriate. Ho scoperto che posso mantenere la mia tabella statica, usare molto meno codice ed è più facile capire cosa sta succedendo.


Questo ha funzionato per me, tranne che sembra esserci un bug in UITableView. L'altezza della riga veniva restituita correttamente nel mio metodo, ma in realtà alternava l'altezza opposta che volevo. Se ho ricaricato le righe due volte ha funzionato. (Non ho usato tableView reloadData perché non volevo ricaricare l'intera cosa). Anche il blocco dell'animazione non era necessario, sembra che si animi da solo.
Chris Garrett

Qualcuno ha usato il campione per creare un selettore di testo? se é cosi, come? Grazie
TheGeezer

1
Intendi rivelare una riga in modo che l'utente possa inserire del testo invece di selezionare una data? Se è così, il codice è lo stesso. Solo il contenuto della riga rivelata è diverso.
Aaron Bratcher

22
C'è un bug con iOS7.1 che mostra oggetti fuori dai limiti della cella, come quello con altezza 0 e selettore all'interno. La soluzione è ottenere un'uscita per la cella e impostare cell.clipsToBounds = YES;
EmilDo

1
@ Dunken - Una soluzione è descritta nel commento sopra votato: stackoverflow.com/questions/18973573/… Anche se la riga ha un'altezza pari a zero, i contenuti non vengono tagliati per impostazione predefinita, quindi puoi vederli sotto il riga successiva.
Chris Nolet,

18

Utilizzando lo storyboard e una tabella statica sono stato in grado di ottenere lo stesso risultato utilizzando il codice seguente. Questa è un'ottima soluzione perché se hai molte celle dalla forma strana o vuoi avere più celle che vengono mostrate / nascoste dinamicamente, questo codice funzionerà comunque.

@interface StaticTableViewController: UITableViewController

@property (weak, nonatomic) IBOutlet UITableViewCell *dateTitleCell; // cell that will open the date picker. This is linked from the story board
@property (nonatomic, assign, getter = isDateOpen) BOOL dateOpen;

@end


@implementation StaticTableViewController

-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    // This is the index path of the date picker cell in the static table
    if (indexPath.section == 1 && indexPath.row == 1 && !self.isDateOpen){
        return 0;
    }
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
    [tableView beginUpdates];
    if (cell == self.dateTitleCell){
        self.dateOpen = !self.isDateOpen;
    }
    [tableView reloadData];
    [self.tableView endUpdates];
}

c'è qualcos'altro che manca qui? L'altezza delle celle non sta cambiando :)
DevC

2
Da iOS 7.1 devi anche selezionare "Ritaglia su SubViews" nell'ispettore Attributi: questo è quello che mi mancava :)
DevC

Inoltre, la riga "self.dateOpen =! Self.isDateOpen;" dovrebbe leggere "self.isDateOpen =" all'inizio, non "self.dateOpen ="
Peter Johnson,

2
La [tableView reloadData];chiamata non è necessaria. Attualmente disabilita la selezione della riga, ma è meglio deselezionare la riga in questo modo:[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
Barry Haanstra

Ho avuto strani effetti di animazione come la cella della data sarebbe stata vuota dopo l '"apertura", ma l'uso delle date di inizio e di fine ha risolto il problema. Bello e liscio adesso. Grazie datinc!
nh32rg

5

Ho preso la fonte DateCell da Apple e ho rimosso il file storyboard.

Se ne vuoi uno senza storyboard, dai un'occhiata a: https://github.com/ajaygautam/DateCellWithoutStoryboard


Grazie @Ajay, ho usato il tuo codice modificato e voglio sostituirlo UIDatePickercon UIPickerView. Ho provato poche cose e in grado di mostrare pickerViewsu ogni cella ma non viene aggiornato con ogni cella. Ho pubblicato la mia domanda e il codice qui . Dai un'occhiata e sarei molto gentile se mi suggerissi una soluzione.
Mughees Musaddiq

Ho visto la tua domanda ... ha troppe informazioni e non spiega molto. Forse puoi caricare il tuo codice / zippato da qualche parte per farmi dare un'occhiata. Posso eseguire il debug - se riesco a eseguire il codice ...
Ajay Gautam

Grazie, in qualche modo sono riuscito a sostituire UIDatePickercon UIPickerViewma con un paio di bug. 1. Si blocca quando apri UIPickerViewe scorri la tabella. 2. Assegna automaticamente il valore a UILabelDettaglio nelle righe inferiori della tabella quando i valori vengono assegnati all'etichetta Dettagli nelle righe superiori. Ecco il mio codice
Mughees Musaddiq

Riesci a trovare il testProject, qualche fortuna ??
Mughees Musaddiq

Scusa, sono stato un po 'occupato. Hai ancora bisogno di aiuto con questo?
Ajay Gautam

5

Uno dei migliori tutorial su questo è UIDatePicker in linea di iOS 7 - Parte 2 . Fondamentalmente qui utilizzo celle di visualizzazione tabella statica e implemento alcuni metodi aggiuntivi. Ho usato Xamarin e C # per questo:

Devi essere attivo Clip Subviews.

Impostazione dell'altezza:

public override float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
    if (indexPath.Row == 4) {
        return (datePickerIsShowing) ? 206f : 0.0f;
    }

    return base.GetHeightForRow(tableView,indexPath);
}

Di una variabile di classe: private bool datePickerIsShowing = false;

Mostra selezione data:

private void showDatePickerCell(){
    datePickerIsShowing = true;
    this.TableView.BeginUpdates ();
    this.TableView.EndUpdates ();
    this.datePicker.Hidden = false;
    this.datePicker.Alpha = 0.0f;

    UIView.Animate (0.25, animation:
        () => {
            this.datePicker.Alpha = 1.0f;
        }
    );
} 

Nascondi selezione data:

private void hideDatePickerCell(){
    datePickerIsShowing = false;
    this.TableView.BeginUpdates ();
    this.TableView.EndUpdates ();

    UIView.Animate (0.25,
        animation: () => {
            this.datePicker.Alpha = 0.0f;
        },
        completion: () => {
            this.datePicker.Hidden = true;
        }
    );
} 

E chiamando queste funzioni:

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    if (indexPath.Row == 3) {
        if (datePickerIsShowing) {
            hideDatePickerCell ();
        } else {
            showDatePickerCell ();
        }
    }

    this.TableView.DeselectRow (indexPath, true);
}

2
Se dai voti negativi, forse puoi spiegare perché voti negativi. Invece di pubblicare link a siti ho incluso anche del codice. Nel mio caso è C #. Non so cosa c'è di sbagliato in questo.
test

3

Ho creato il mio controller di visualizzazione personalizzato per semplificare il processo di aggiunta di un selettore in linea in linea in una visualizzazione tabella. Devi solo sottoclassarlo e seguire alcune semplici regole e gestisce la presentazione del selettore di date.

Puoi trovarlo qui insieme a un progetto di esempio che dimostra come usarlo: https://github.com/ale84/ALEInlineDatePickerViewController


3

Ho trovato una risposta a un difetto nell'esempio di cella dati di Apple in cui devi avere una riga sotto l'ultima cella dati o ottieni un errore. Nel metodo CellForRowAtIndexPath sostituire la riga ItemData con

NSArray *itemsArray = [self.dataArray objectAtIndex:indexPath.section];
NSDictionary *itemData = nil;

if(![indexPath isEqual:self.datePickerIndexPath])
    itemData = [itemsArray objectAtIndex:modelRow];

Dopo aver sostituito il codice di esempio, ora posso visualizzare una cella datePicker senza avere una cella sotto di essa.

Mi sono appena iscritto a stackoverflow quindi se questo è nel posto sbagliato o da qualche altra parte mi scuso.


3

La risposta di Aaron Bratcher ha funzionato tranne quando utilizzata con più sezioni. Le animazioni erano un po 'instabili e le sezioni successive non scorrevano molto bene. Per risolvere questo problema, ho ripetuto il set di sezioni successivo e ho tradotto le righe nella stessa quantità dell'altezza del selettore di date.

Ho modificato didSelectRowAtIndexPath in:

// Return Data to delegate: either way is fine, although passing back the object may be more efficient
// [_delegate imageSelected:currentRecord.image withTitle:currentRecord.title withCreator:currentRecord.creator];
// [_delegate animalSelected:currentRecord];
if (indexPath.section == 1 && indexPath.row == 0) { // this is my date cell above the picker cell
    editingStartTime = !editingStartTime;
    [UIView animateWithDuration:.4 animations:^{
        int height = 0;
        if (editingStartTime) {
            height = 162;
        }
        UITableViewCell* temp = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
        [temp setFrame:CGRectMake(temp.frame.origin.x, temp.frame.origin.y, temp.frame.size.width, height)];
        for (int x = 2; x < [tableView numberOfSections]; x++) {
            for (int y = 0; y < [tableView numberOfRowsInSection:x]; y++) {
                UITableViewCell* temp = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:y inSection:x]];
                int y_coord = temp.frame.origin.y-162;
                if (editingStartTime) {
                    y_coord = temp.frame.origin.y+162;
                }
                [temp setFrame:CGRectMake(temp.frame.origin.x, y_coord, temp.frame.size.width, temp.frame.size.height)];
            }
        }
    }completion:^(BOOL finished){
        [self.tableView reloadData];
    }];
}

Grazie @Timmahh, ho trovato anche l'animazione della sezione instabile. Ho utilizzato con successo la tua soluzione nella mia prima app Swift! Ho scoperto che cellForRowAtIndexPath restituisce zero dove le celle sono fuori schermo. Per evitare ciò, ho aggiunto una raccolta di punti vendita IB contenente tutte le mie celle, che veniva dopo la cella di selezione, e le ho ripetute con il tuo nuovo y_coord. Questo sembra inflessibile, dato che devo mantenere la raccolta aggiornata quando aggiungo nuove celle.
Josh

Hai ragione. In effetti, avevo risolto il problema ma lo stack overflow non mi permetteva di modificare il codice che avevo inserito.
Timothy Logan

3

Aggiungendo alle risposte precedenti,

Ho provato entrambe le soluzioni @datinc e @Aaron Bratcher, entrambe funzionavano alla grande ma l'animazione non era così pulita in una tableView statica raggruppata.

Dopo averci giocato un po 'sono arrivato a questo codice che funziona perfettamente e alla grande per me -

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 && indexPath.row == 1)
    {
        if (self.isPickerOpened)
        {
            return 162;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        return [super tableView:tableView heightForRowAtIndexPath:indexPath];
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0 && indexPath.row == 0) {
        [tableView beginUpdates];
        self.isPickerOpened = ! self.isPickerOpened;
        [super tableView:tableView heightForRowAtIndexPath:indexPath];
        [self.tableView endUpdates];
    }
}

Il cambiamento principale è usare -

        [super tableView:tableView heightForRowAtIndexPath:indexPath];

per aggiornare la riga, in questo modo il resto delle sezioni e delle celle della tabella non si animano.

Spero che aiuti qualcuno.

Shani


Questo ha aiutato moltissimo; grazie! In particolare l'aspetto [super tableView], in bundle con il post di Aaron Bratcher, mi ha ottenuto i risultati di cui avevo bisogno su iOS 9.2. Grazie ancora!
Terrance Shaw

2

In aggiunta alle risposte precedenti e alla soluzione di @Aaron Bratcher ...

Ricevevo animazioni instabili da iOS 9 e il caricamento del tavolo richiedeva un po 'di tempo e abbastanza da essere fastidioso. L'ho ristretto ai selettori di date che sono lenti a caricare dallo storyboard. L'aggiunta dei selettori a livello di programmazione anziché nello storyboard ha migliorato le prestazioni di caricamento e, come sottoprodotto, l'animazione è più fluida.

Rimuovere il selettore di date dallo storyboard e avere una cella vuota, di cui si imposta l'altezza come nelle risposte precedenti, quindi chiamare un'inizializzazione su viewDidLoad:

- (void)initialiseDatePickers
{
    self.isEditingStartTime = NO;
    self.startTimePickerCell.clipsToBounds = YES;

    UIDatePicker *startTimePicker = [[UIDatePicker alloc] init];
    [startTimePicker addTarget:self action:@selector(startTimePickerChanged:) forControlEvents:UIControlEventValueChanged];
    [self.startTimePickerCell addSubview:startTimePicker];
}

Quindi implementare l'azione, ad es

- (IBAction)startTimePickerChanged:(id)sender
{
    NSLog(@"start time picker changed");
}

Questo carica la tabella molto più velocemente di prima. Puoi anche rimuovere la linea di animazione da didSelectRowAtIndexPathcome si anima senza di essa (ymmv).

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 && indexPath.row == 1) { // this is my date cell above the picker cell
        editingStartTime = !editingStartTime;
    }
}

1

L'utilizzo di questa risposta senza l'animazione funziona correttamente in iOS 8.1. L'ho convertito in Swift di seguito:

import UIKit

class TableViewController: UITableViewController {

    var editingCell: Bool = false

    @IBOutlet weak var myCell: UITableViewCell!

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        // Change the section and row to the title cell the user taps to reveal 
        // the cell below
        if (indexPath.section == 0 && indexPath.row == 2 && !editingCell) {
            return 0
        } else {
            return self.tableView.rowHeight
        }
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        self.tableView.deselectRowAtIndexPath(indexPath, animated: false);

        var cell = tableView.cellForRowAtIndexPath(indexPath)

        self.tableView.beginUpdates()
        if (cell == self.myCell) {
            editingType = !editingType;
        }
        self.tableView.endUpdates()
    }
}

1

Ecco un altro modo per risolvere il problema senza numeri costanti statici. Tutte le celle possono essere utilizzate nelle visualizzazioni tabella statica e dinamica. Questo metodo utilizza una cella singola sia per il titolo che per il selettore di date!

A proposito, puoi avere tutti i selettori di date nel tuo tavolo come desideri!

Crea una sottoclasse UITableViewCell :

Tutte le celle della vista tabella devono essere ereditate da questa classe e devi impostare manualmente l'altezza della cella per ogni riga.

//
//  CPTableViewCell.h
//
//  Copyright (c) CodePigeon. All rights reserved.
//

@class CPTableViewCell;

#define kUIAnimationDuration 0.33f

@protocol CPTableViewCellDelegate <NSObject>

@required
- (void)tableViewCellDidChangeValue:(CPTableViewCell *)cell;
@optional
- (void)tableViewCellDidBecomeFirstResponder:(CPTableViewCell *)cell;
- (void)tableViewCellResignedFirstResponder:(CPTableViewCell *)cell;
@end

@interface CPTableViewCell : UITableViewCell

@property (nonatomic, weak) IBOutlet UITableView *tableView;
@property (nonatomic, weak) IBOutlet CPTableViewCell *nextCell;
@property (nonatomic, weak) IBOutlet id<CPTableViewCellDelegate> delegate;

@property (nonatomic, copy) IBInspectable NSString *dataBindKey;
@property (nonatomic) IBInspectable CGFloat height;

@property (nonatomic, readonly) BOOL isFirstResponder;
@property (nonatomic) BOOL isEnabled;

- (void)commonInit;

- (id)value;
- (void)setValue:(id)value;

@end

//
//  CPTableViewCell.m
//
//  Copyright (c) CodePigeon. All rights reserved.
//

#import "CPTableViewCell.h"

@interface CPTableViewCell ()
@end

@implementation CPTableViewCell

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if (!self)
        return nil;

    [self commonInit];

    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];

    if (!self)
        return nil;

    [self commonInit];

    return self;
}

- (void)commonInit
{
    _isFirstResponder = NO;
    _isEnabled = YES;
}

- (BOOL)canBecomeFirstResponder
{
    return _isEnabled;
}

- (BOOL)becomeFirstResponder
{
    if ([_delegate respondsToSelector:@selector(tableViewCellDidBecomeFirstResponder:)])
        [_delegate tableViewCellDidBecomeFirstResponder:self];

    return _isFirstResponder = YES;
}

- (BOOL)resignFirstResponder
{
    if (_isFirstResponder)
    {
        if ([_delegate respondsToSelector:@selector(tableViewCellResignedFirstResponder:)])
            [_delegate tableViewCellResignedFirstResponder:self];

        _isFirstResponder = NO;
    }

    return _isFirstResponder;
}

- (id)value
{
    [self doesNotRecognizeSelector:_cmd];

    return nil;
}

- (void)setValue:(id)value
{
    [self doesNotRecognizeSelector:_cmd];
}

@end

Crea una classe CPDatePickerTableViewCell dal nostro CPTableViewCell

//
//  CPDatePickerTableViewCell.h
//
//  Copyright (c) CodePigeon. All rights reserved.
//

#import "CPTableViewCell.h"

@interface CPDatePickerTableViewCell : CPTableViewCell

@property (nonatomic, copy) IBInspectable NSString *dateFormat;

@property (nonatomic, weak) IBOutlet UILabel *titleLabel;
@property (nonatomic, weak) IBOutlet UILabel *dateLabel;

@property (nonatomic, weak) IBOutlet UIDatePicker *datePicker;

@end

//
//  CPDatePickerTableViewCell.m
//
//  Copyright (c) CodePigeon. All rights reserved.
//

#import "CPDatePickerTableViewCell.h"

#define kCPDatePickerTableViewCellPickerHeight 162.f

@interface CPDatePickerTableViewCell () <UITextFieldDelegate, UIPickerViewDelegate>
{
    NSDateFormatter *_dateFormatter;
    BOOL _isOpen;
}
@end

@implementation CPDatePickerTableViewCell

- (void)awakeFromNib
{
    [super awakeFromNib];

    _dateFormatter = [NSDateFormatter new];
    [_dateFormatter setDateFormat:_dateFormat];

    self.selectionStyle = UITableViewCellSelectionStyleNone;

    _dateLabel.text = [_dateFormatter stringFromDate:_datePicker.date];
    _datePicker.alpha = 0.f;
    _isOpen = NO;
}

- (BOOL)becomeFirstResponder
{
    if (_isOpen == NO)
    {
        self.height += kCPDatePickerTableViewCellPickerHeight;
    }
    else
    {
        self.height -= kCPDatePickerTableViewCellPickerHeight;
    }

    [UIView animateWithDuration:kUIAnimationDuration animations:^{
        _datePicker.alpha = _isOpen ? 0.0f : 1.0f;
    }];

    [self.tableView beginUpdates];
    [self.tableView endUpdates];

    _isOpen = !_isOpen;

    [self.tableView endEditing:YES];

    return [super becomeFirstResponder];
}

- (BOOL)resignFirstResponder
{
    if (_isOpen == YES)
    {
        self.height -= kCPDatePickerTableViewCellPickerHeight;

        [UIView animateWithDuration:kUIAnimationDuration animations:^{
            _datePicker.alpha = 0.0f;
        }];

        [self.tableView beginUpdates];
        [self.tableView endUpdates];

        _isOpen = NO;
    }

    return [super resignFirstResponder];
}

- (id)value
{
    return _datePicker.date;
}

- (void)setValue:(NSDate *)value
{
    _datePicker.date = value;
    _dateLabel.text = [_dateFormatter stringFromDate:_datePicker.date];
}

- (IBAction)datePickerValueChanged:(UIDatePicker *)sender
{
    [_dateLabel setText:[_dateFormatter stringFromDate:_datePicker.date]];

    [self.delegate tableViewCellDidChangeValue:self];
}

@end

Nel tuo controller di visualizzazione implementa questi due metodi delegati

#pragma mark - UITableViewDelegate methods

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CPTableViewCell *cell = (CPTableViewCell *)[super tableView:tableView cellForRowAtIndexPath:indexPath];

    return [cell height];
}

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
    CPTableViewCell *cell = (CPTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];

    if ([cell canBecomeFirstResponder])
    {
        [cell becomeFirstResponder];
    }

    if (cell != _selectedCell)
    {
        [_selectedCell resignFirstResponder];
    }

    _selectedCell = cell;

    return YES;
}

Esempio di come impostare i vincoli in Interface Builder

Costruttore di interfacce

Inoltre ho scritto classi di celle personalizzate per UITextField e UITextView dove tableView: didSelectRowAtIndexPath: viene chiamato quando cell è selezionata!

CPTextFieldTableViewCell

//
//  CPTextFieldTableViewCell.h
//
//  Copyright (c) CodePigeon. All rights reserved.
//

#import "CPTableViewCell.h"

@interface CPTextFieldTableViewCell : CPTableViewCell

@property (nonatomic, weak) IBOutlet UITextField *inputTextField;

@end

//
//  CPTextFieldTableViewCell.m
//
//  Copyright (c) CodePigeon. All rights reserved.
//

#import "CPTextFieldTableViewCell.h"

@interface CPTextFieldTableViewCell () <UITextFieldDelegate>
@end

@implementation CPTextFieldTableViewCell

- (void)awakeFromNib
{
    [super awakeFromNib];

    self.selectionStyle = UITableViewCellSelectionStyleNone;

    _inputTextField.userInteractionEnabled = NO;
    _inputTextField.delegate = self;
}

- (BOOL)becomeFirstResponder
{
    _inputTextField.userInteractionEnabled = YES;

    [_inputTextField becomeFirstResponder];

    return [super becomeFirstResponder];
}

- (BOOL)resignFirstResponder
{
    _inputTextField.userInteractionEnabled = NO;

    return [super resignFirstResponder];
}

- (void)setIsEnabled:(BOOL)isEnabled
{
    [super setIsEnabled:isEnabled];

    _inputTextField.enabled = isEnabled;
}

- (id)value
{
    return _inputTextField.text;
}

- (void)setValue:(NSString *)value
{
    _inputTextField.text = value;
}

#pragma mark - UITextFieldDelegate methods

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self.delegate tableViewCellDidChangeValue:self];
}

@end

CBTextViewTableViewCell

L'altezza della cella è dinamica e la riga crescerà quando il testo viene spostato su una nuova riga!

//
//  CBTextViewTableViewCell.h
//
//  Copyright (c) CodePigeon. All rights reserved.
//

#import "CPTableViewCell.h"

@interface CPTextViewTableViewCell : CPTableViewCell

@property (nonatomic, weak) IBOutlet UITextView *inputTextView;

@end

//
//  CBTextViewTableViewCell.m
//
//  Copyright (c) CodePigeon. All rights reserved.
//

#import "CPTextViewTableViewCell.h"

@interface CPTextViewTableViewCell () <UITextViewDelegate>
{
    UITextView *_heightTextView;
}

@end

@implementation CPTextViewTableViewCell

@synthesize height = _height;

- (void)awakeFromNib
{
    [super awakeFromNib];

    self.selectionStyle = UITableViewCellSelectionStyleNone;

    _inputTextView.userInteractionEnabled = NO;
    _inputTextView.delegate = self;
    _inputTextView.contentInset = UIEdgeInsetsZero;
    _inputTextView.scrollEnabled = NO;
}

- (CGFloat)height
{
    if (!_heightTextView)
    {
        CGRect frame = (CGRect) {
            .origin = CGPointMake(0.f, 0.f),
            .size = CGSizeMake(_inputTextView.textInputView.frame.size.width, 0.f)
        };

        _heightTextView = [[UITextView alloc] initWithFrame:frame];
        _heightTextView.font = [UIFont systemFontOfSize:_inputTextView.font.pointSize];
        _heightTextView.textColor = UIColor.whiteColor;
        _heightTextView.contentInset = UIEdgeInsetsZero;
    }

    _heightTextView.text = _inputTextView.text;

    CGSize size = [_heightTextView sizeThatFits:CGSizeMake(_inputTextView.textInputView.frame.size.width, FLT_MAX)];

    return size.height > _height ? size.height + _inputTextView.font.pointSize : _height;
}

- (BOOL)becomeFirstResponder
{
    _inputTextView.userInteractionEnabled = YES;

    [_inputTextView becomeFirstResponder];

    return [super becomeFirstResponder];
}

- (BOOL)resignFirstResponder
{
    _inputTextView.userInteractionEnabled = NO;

    return [super resignFirstResponder];
}

- (void)setIsEnabled:(BOOL)isEnabled
{
    [super setIsEnabled:isEnabled];

    _inputTextView.editable = isEnabled;
}

- (id)value
{
    return _inputTextView.text;
}

- (void)setValue:(NSString *)value
{
    _inputTextView.text = value;

    [_inputTextView setNeedsLayout];
    [_inputTextView layoutIfNeeded];
}

#pragma mark - UITextViewDelegate methods

- (void)textViewDidChange:(UITextView *)textView
{
    [self.delegate tableViewCellDidChangeValue:self];

    [self.tableView beginUpdates];
    [self.tableView endUpdates];
}

@end

0

Il modo più semplice per utilizzare DateCell nella versione Swift: usa questo esempio .

  1. Apri questo esempio e provalo (Make Xcode to Convert to Swift 2)
  2. Trascina la classe " DateCellTableViewController.swift " nel tuo progetto.

  3. Apri "Main.storyboard" e copia l' oggetto ViewController "DateCell" e incollalo nello storyboard.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.