iOS 7 - Bagaimana cara menampilkan pemilih tanggal di tempat dalam tampilan tabel?

121

Dalam video WWDC 2013, Apple menyarankan untuk menampilkan picker di tempat dalam tampilan tabel di iOS 7. Bagaimana cara menyisipkan dan menganimasikan tampilan antara sel tampilan tabel?

Seperti ini, dari aplikasi kalender Apple:

Alat pilih tanggal di tempat

XY
sumber
Video WWDC manakah ini? Saya mencoba memahami mengapa ini khusus untuk iOS7, dan jika ada alasan mengapa hal ini tidak dapat dilakukan pada versi sebelumnya.
Clafou
4
Menemukannya, ini adalah "What's New in iOS User Interface Design" (terima kasih ASCIIwwdc). Alasannya adalah bahwa gaya lama tidak terlihat sejajar, tetapi tampilan datar baru terlihat.
Clafou

Jawaban:

102

Dengan iOS7, Apple merilis kode sampel DateCell.

masukkan deskripsi gambar di sini

Mendemonstrasikan tampilan objek tanggal yang diformat dalam sel tabel dan penggunaan UIDatePicker untuk mengedit nilai tersebut. Sebagai delegasi ke tabel ini, sampel menggunakan metode "didSelectRowAtIndexPath" untuk membuka kontrol UIDatePicker.

Untuk iOS 6.x dan yang lebih lama, UIViewAnimation digunakan untuk menggeser UIDatePicker ke atas di layar dan ke bawah di luar layar. Untuk iOS 7.x, UIDatePicker ditambahkan sebaris ke tampilan tabel.

Metode tindakan UIDatePicker akan langsung menyetel properti NSDate dari sel tabel kustom. Selain itu, contoh ini menunjukkan cara menggunakan kelas NSDateFormatter untuk mendapatkan tampilan format tanggal sel kustom.

masukkan deskripsi gambar di sini

Anda dapat mengunduh kode sampel di sini: DateCell .

Nitin Gohel
sumber
Kode Apple bermasalah. Lihat jawaban saya di bawah ini jika Anda ingin menyimpan tableView statis Anda
Aaron Bratcher
1
@AaronBratcher Saya baru saja memperkenalkan Datecell di jawaban saya dan Anda tidak pernah berharap Anda mendapatkan kode persis yang Anda inginkan. Anda harus memodifikasi dan mengubah sesuai kebutuhan Anda. solusi Anda juga bagus tetapi ingat Anda tidak pernah mendapatkan apa yang tepat dari kode lain yang Anda butuhkan.
Nitin Gohel
3
kode contoh yang paling mengerikan. Mereka dapat melakukan dengan beberapa saran tentang kapan membuat metode dari Code Complete
Anirudha Agashe
2
Wow kode Apple adalah .... yah, katakanlah fokusnya ada pada efek tampilan tabel. Saya harap tidak ada yang terinspirasi oleh kode mereka dalam proyek contoh ini: s
Daniel
84

Anda dapat menggunakan jawaban yang saya berikan sebelumnya di bawah atau menggunakan kelas baru ini di Swift yang saya buat untuk membuat tugas ini jauh lebih sederhana dan lebih bersih: https://github.com/AaronBratcher/TableViewHelper


Saya menemukan kode yang disediakan oleh Apple bermasalah dalam beberapa cara:

  • Anda tidak bisa memiliki tableView statis karena mereka menggunakan metode tableView: cellForRowAtIndexPath
  • Kode macet jika Anda tidak memiliki baris tambahan di bawah sel pemilih tanggal terakhir

Untuk tabel sel statis, saya menentukan sel pemilih tanggal saya di bawah sel tampilan tanggal saya dan memiliki bendera yang mengidentifikasi jika saya mengeditnya. Jika ya, saya mengembalikan tinggi sel yang sesuai, jika tidak, saya mengembalikan tinggi sel nol.

- (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;
    }
}

Ketika baris yang menunjukkan tanggal diklik, saya mengubah bendera dan melakukan animasi pembaruan untuk menampilkan alat pilih.

-(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];
        }];
    }
}

Jika saya memiliki beberapa alat pilih tanggal / waktu dalam tabel yang sama, saya menyetel bendera sesuai dengan klik dan memuat ulang baris yang sesuai. Saya telah menemukan bahwa saya dapat menyimpan tabel statis saya, menggunakan lebih sedikit kode, dan lebih mudah untuk memahami apa yang terjadi.

Aaron Bratcher
sumber
Ini berhasil untuk saya, kecuali tampaknya ada bug di UITableView. Tinggi baris dikembalikan dengan benar dalam metode saya, tetapi sebenarnya itu mengubah ketinggian berlawanan yang saya inginkan. Jika saya memuat ulang baris dua kali itu berhasil. (Saya tidak menggunakan reloadData tableView karena saya tidak ingin memuat ulang semuanya). Juga blok animasi tidak diperlukan, tampaknya bergerak sendiri dengan baik.
Chris Garrett
Adakah yang pernah menggunakan sampel untuk membuat pemilih teks? jika ya, bagaimana caranya? Terima kasih
TheGeezer
1
Anda bermaksud menampilkan baris sehingga pengguna dapat memasukkan teks alih-alih memilih tanggal? Jika ya, kodenya sama. Hanya isi baris yang terungkap berbeda.
Aaron Bratcher
22
Ada bug dengan iOS7.1 yang menunjukkan objek di luar batas sel - seperti yang tingginya 0 dan picker di dalamnya. Solusinya adalah mendapatkan jalan keluar untuk sel dan mengatur cell.clipsToBounds = YES;
EmilDo
1
@Dunken - Solusi dijelaskan dalam komentar yang dipilih secara maksimal di atas: stackoverflow.com/questions/18973573/… Meskipun baris memiliki tinggi nol, konten tidak dipotong secara default, sehingga Anda dapat melihatnya di bawah baris berikutnya.
Chris Nolet
18

Menggunakan storyboard dan tabel statis saya dapat mencapai hasil yang sama menggunakan kode berikut. Ini adalah solusi yang bagus karena jika Anda memiliki banyak sel berbentuk aneh atau ingin memiliki beberapa sel yang ditampilkan / disembunyikan secara dinamis, kode ini akan tetap berfungsi.

@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];
}
datinc
sumber
apakah ada hal lain yang hilang di sini? Ketinggian sel tidak berubah :)
DevC
2
Sejak iOS 7.1 Anda juga harus memilih "Klip ke SubTampilan" di inspektur Atribut - itulah yang saya lewatkan :)
DevC
Juga, baris "self.dateOpen =! Self.isDateOpen;" harus membaca "self.isDateOpen =" di awal, bukan "self.dateOpen ="
Peter Johnson
2
The [tableView reloadData];panggilan tidak diperlukan. Saat ini menonaktifkan pemilihan baris, tetapi lebih baik untuk membatalkan pilihan baris seperti ini:[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
Barry Haanstra
Saya memiliki efek animasi yang aneh seperti sel tanggal akan kosong setelah "pembukaan" tetapi menggunakan mulai dan tanggal akhir menyelesaikannya. Bagus dan mulus sekarang. Terima kasih datinc!
nh32rg
5

Saya telah mengambil sumber DateCell dari Apple, dan menghapus file storyboard.

Jika Anda menginginkannya tanpa storyboard, lihat: https://github.com/ajaygautam/DateCellWithoutStoryboard

Ajay Gautam
sumber
Terima kasih @Ajay, saya menggunakan kode Anda yang telah diubah dan ingin menggantinya UIDatePickerdengan UIPickerView. Saya mencoba beberapa hal dan dapat ditampilkan pickerViewdi setiap sel tetapi tidak diperbarui dengan setiap sel. Saya telah memposting pertanyaan dan kode saya di sini . Silakan lihat dan akan sangat baik jika Anda dapat menyarankan saya solusi.
Mughees Musaddiq
Saya melihat pertanyaan Anda ... memiliki terlalu banyak info, dan tidak terlalu menjelaskan. Mungkin Anda dapat mengunggah kode / zip Anda di suatu tempat agar saya dapat melihatnya. Saya dapat men-debugnya - jika saya dapat menjalankan kode ...
Ajay Gautam
Terima kasih, saya entah bagaimana berhasil menggantikan UIDatePickerdengan UIPickerViewtetapi dengan beberapa bug. 1. Itu macet saat Anda membuka UIPickerViewdan menggulir tabel. 2. Secara otomatis memberikan nilai ke UILabelDetail di baris bawah tabel ketika nilai-nilai diberikan ke label Details di baris atas. Ini kode saya
Mughees Musaddiq
Apakah Anda dapat menemukan testProject, Semoga beruntung ??
Mughees Musaddiq
Maaf, saya agak sibuk. Masih butuh bantuan untuk ini?
Ajay Gautam
5

Salah satu tutorial terbaik tentang ini adalah UIDatePicker in-line iOS 7 - Bagian 2 . Pada dasarnya di sini saya menggunakan sel tampilan tabel statis dan menerapkan beberapa metode tambahan. Saya menggunakan Xamarin dan C # untuk ini:

Anda harus aktif Clip Subviews.

Mengatur ketinggian:

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

    return base.GetHeightForRow(tableView,indexPath);
}

Dari variabel kelas: private bool datePickerIsShowing = false;

Tampilkan pemilih tanggal:

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;
        }
    );
} 

Sembunyikan pemilih tanggal:

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;
        }
    );
} 

Dan memanggil fungsi ini:

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

    this.TableView.DeselectRow (indexPath, true);
}
pengujian
sumber
2
Jika Anda memberi suara negatif, mungkin Anda bisa menjelaskan mengapa Anda memberi suara negatif. Alih-alih memposting tautan ke situs, saya juga menyertakan beberapa kode. Dalam kasus saya itu C #. Tidak tahu apa yang salah dengan itu.
menguji
3

Saya telah membuat pengontrol tampilan kustom saya sendiri untuk menyederhanakan proses penambahan inline picker inline dalam tableview. Anda cukup membuat subkelasnya dan mengikuti beberapa aturan sederhana dan ini menangani presentasi pemilih tanggal.

Anda dapat menemukannya di sini bersama dengan contoh proyek yang mendemonstrasikan cara menggunakannya: https://github.com/ale84/ALEInlineDatePickerViewController

ale84
sumber
3

Saya menemukan jawaban untuk kesalahan dalam contoh datecell apel di mana Anda harus memiliki baris di bawah sel data terakhir atau Anda mendapatkan kesalahan. Dalam metode CellForRowAtIndexPath, ganti baris ItemData dengan

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

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

Setelah mengganti kode sampel, saya sekarang dapat menampilkan tampilan sel datePicker tanpa sel di bawahnya.

Saya baru saja bergabung dengan stackoverflow jadi jika ini ada di tempat yang salah atau di tempat lain, saya minta maaf.

pjmarshall1
sumber
3

Jawaban dari Aaron Bratcher berhasil kecuali jika digunakan dengan banyak bagian. Animasi agak berombak dan tidak menggeser bagian berikutnya dengan baik. Untuk memperbaikinya, saya mengulang melalui set bagian berikutnya dan menerjemahkan baris ke bawah dengan jumlah yang sama dengan ketinggian pemetik tanggal.

Saya mengedit didSelectRowAtIndexPath menjadi:

// 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];
    }];
}
Timothy Logan
sumber
Terima kasih @Timmahh, saya menemukan bagian animasi yang berombak juga. Saya berhasil menggunakan solusi Anda di aplikasi Swift pertama saya! Saya menemukan bahwa cellForRowAtIndexPath mengembalikan nihil di mana sel berada di luar layar. Untuk menghindari hal ini, saya menambahkan koleksi outlet IB yang berisi semua sel saya, yang muncul setelah sel pemilih, dan mengulanginya dengan y_coord baru Anda. Ini tampaknya tidak fleksibel karena saya harus menjaga koleksi tetap mutakhir ketika saya menambahkan sel baru.
Josh
Kamu benar. Faktanya, saya telah memperbaiki masalah ini tetapi stack overflow tidak mengizinkan saya mengedit kode yang saya taruh di sana.
Timothy Logan
3

Menambah jawaban sebelumnya,

Saya mencoba solusi @datinc dan @Aaron Bratcher, keduanya bekerja dengan baik tetapi animasinya tidak begitu bersih dalam tableView statis yang dikelompokkan.

Setelah memainkannya sedikit, saya mendapatkan kode ini yang berfungsi bersih dan bagus untuk saya -

- (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];
    }
}

Perubahan utama adalah menggunakan -

        [super tableView:tableView heightForRowAtIndexPath:indexPath];

untuk memperbarui baris, dengan cara ini bagian tabel dan sel lainnya tidak dianimasikan.

Semoga membantu seseorang.

Shani

shannoga.dll
sumber
Ini sangat membantu; Terima kasih! Khususnya aspek [super tableView], dibundel dengan postingan Aaron Bratcher, memberi saya hasil yang saya butuhkan di iOS 9.2. Terima kasih lagi!
Terrance Shaw
2

Menambahkan ke jawaban sebelumnya dan solusi @Aaron Bratcher ...

Saya mendapatkan animasi berombak sejak iOS 9, dan tabel memerlukan waktu beberapa saat untuk dimuat, dan cukup mengganggu. Saya mempersempitnya hingga pengambil tanggal lambat memuat dari storyboard. Menambahkan alat pilih secara terprogram daripada di papan cerita meningkatkan kinerja pemuatan, dan sebagai produk sampingan, animasinya menjadi lebih mulus.

Hapus pemilih tanggal dari storyboard dan memiliki sel kosong, yang Anda setel tingginya seperti pada jawaban sebelumnya, lalu panggil inisialisasi di 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];
}

Kemudian terapkan tindakan misalnya

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

Ini memuat tabel jauh lebih cepat dari sebelumnya. Anda juga menghapus garis animasi dari yang didSelectRowAtIndexPathdianimasikan dengan mulus tanpanya (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;
    }
}
matt_s
sumber
1

Menggunakan jawaban ini tanpa animasi berfungsi dengan benar di iOS 8.1. Saya telah mengubahnya menjadi Swift di bawah ini:

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()
    }
}
davidmytton
sumber
1

Berikut adalah cara lain untuk menyelesaikan soal tanpa bilangan konstan statis. Semua sel dapat digunakan dalam tampilan tabel statis dan dinamis. Metode ini menggunakan sel tunggal untuk pemilih judul dan tanggal!

Btw Anda dapat memiliki sebanyak mungkin pemilih tanggal di meja Anda sesuai keinginan!

Buat subclass UITableViewCell :

Semua sel tampilan tabel Anda harus diwarisi dari kelas ini dan Anda harus menyetel tinggi sel secara manual untuk setiap baris.

//
//  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

Buat kelas CPDatePickerTableViewCell dari CPTableViewCell kami

//
//  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

Dalam pengontrol tampilan Anda, implementasikan dua metode delegasi ini

#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;
}

Contoh cara menyiapkan batasan di Pembuat antarmuka

Pembuat antarmuka

Selain itu saya telah menulis kelas sel khusus untuk UITextField dan UITextView di mana tableView: didSelectRowAtIndexPath: dipanggil ketika sel dipilih!

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

Tinggi sel dinamis dan baris akan bertambah ketika teks dibungkus dengan baris baru!

//
//  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
Ako
sumber
0

Cara termudah untuk menggunakan DateCell dalam versi Swift: Gunakan contoh ini .

  1. Buka contoh ini dan uji (Make Xcode to Convert to Swift 2)
  2. Seret kelas " DateCellTableViewController.swift " ke proyek Anda.

  3. Buka "Main.storyboard" dan Salin Objek ViewController "DateCell" dan tempelkan di storyboard Anda.

Ahmed Lotfy
sumber