iOS 7 - Як відобразити інструмент вибору дати на перегляді таблиці?


121

У відеозаписі WWDC 2013 компанія Apple пропонує відобразити місце вибору на вікні таблиці в iOS 7. Як вставити та анімувати представлення даних між клітинками подання таблиці?

Ось так, з програми календаря Apple:

Місце вибору дат


Яке відео WWDC це? Я намагаюся зрозуміти, чому це специфічно для iOS7, і якщо є причина, чому цього не вдалося зробити на попередніх версіях.
Clafou

4
Виявив це, "Що нового в iOS User Interface Design" (спасибі ASCIIwwdc). Обґрунтування полягає в тому, що старий стиль не виглядав правильно, але новий плоский вигляд.
Clafou

Відповіді:


102

З iOS7 Apple випустила зразок коду DateCell.

введіть тут опис зображення

Демонструє відформатоване відображення об'єктів дати у комірках таблиці та використання UIDatePicker для редагування цих значень. Як делегат цієї таблиці, зразок використовує метод "didSelectRowAtIndexPath" для відкриття елемента UIDatePicker.

Для iOS 6.x та новіших версій UIViewAnimation використовується для переміщення UIDatePicker вгору по екрану та вниз по екрану. Для iOS 7.x, UIDatePicker додається рядково до подання таблиці.

Метод дії UIDatePicker безпосередньо встановить властивість NSDate клітинки користувацької таблиці. Крім того, в цьому зразку показано, як використовувати клас NSDateFormatter для досягнення зовнішнього вигляду у форматі даної клітинки.

введіть тут опис зображення

Ви можете завантажити зразок коду тут: DateCell .


Код Apple має проблеми. Дивіться мою відповідь нижче, якщо ви хочете зберегти свою статичну таблицюView
Аарон Братчер

1
@AaronBratcher я просто ввожу Datecell у свою відповідь, і ти ніколи не очікуєш, що ти отримаєш точний код, який ти хочеш. ви повинні змінювати та змінювати відповідно до вашої вимоги. ваше рішення також добре, але пам’ятайте, що ви ніколи не отримуєте точного вам того, що з іншого коду, який вам потрібен.
Нітін Гогель

3
найжахливіший зразок коду. Вони могли б порадитись із порадами, коли створити метод із Code Complete
Anirudha Agashe

2
Нічого так, що код Apple - це… ну, скажімо, акцент робиться на ефекті подання таблиці. Я сподіваюся, що ніхто не надихнеться своїм кодом у цьому зразковому проекті: s
Даніель

84

Ви можете скористатися відповіддю, яку я раніше наводив нижче, або використати цей новий клас у Swift, який я зробив, щоб зробити це завдання набагато простішим та чистішим: https://github.com/AaronBratcher/TableViewHelper


Я вважаю код, наданий Apple, проблематичним двома способами:

  • Ви не можете мати статичну tableView, оскільки вони використовують метод tableView: cellForRowAtIndexPath
  • Код руйнується, якщо у вас немає додаткових рядків під коміркою вибору останньої дати

Для таблиць статичних комірок я визначаю клітинку вибору дати під коміркою відображення дати і прапор, який ідентифікує, чи редагую її. Якщо я є, я повертаю відповідну висоту комірки, інакше повертаю висоту комірки нульову.

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

Коли натискається рядок із датою, я змінюю прапор і роблю анімацію оновлення, щоб показати вибральник.

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

Якщо у мене в одній таблиці є декілька інструментів вибору дати / часу, я встановлюю прапори відповідно до клацання і перезавантажую відповідні рядки. Я виявив, що я можу зберігати свою статичну таблицю, використовувати набагато менше коду, і простіше зрозуміти, що відбувається.


Це працювало для мене, за винятком помилок UITableView. Висота рядка поверталася правильно в моєму методі, але насправді перемикала протилежну висоту, яку я хотів. Якщо я перезавантажив рядки двічі, це спрацювало. (Я не використовував tableView reloadData, тому що не хотів перезавантажувати все). Також блок анімації не був необхідним, він, здається, анімував самостійно.
Кріс Гарретт

Хтось використовував зразок для створення текстового вибору? якщо так, то як? Спасибі
TheGeezer

1
Ви маєте на увазі розкрити рядок, щоб користувач міг вводити текст замість вибору дати? Якщо так, код той самий. Просто зміст розкритого ряду відрізняється.
Аарон Братчер

22
У нас є помилка з iOS7.1, яка відображає предмети поза межами комірок - як, наприклад, з висотою 0 і вибирачем всередині. Рішення полягає в тому, щоб отримати розетку для комірки та встановити cell.clipsToBounds = ТАК;
EmilDo

1
@Dunken - Рішення описано в коментарі, який голосували вище: stackoverflow.com/questions/18973573/… Хоча рядок має висоту нуля, вміст за замовчуванням не відсікається, тому ви можете бачити їх під наступний рядок
Кріс Нолет

18

Використовуючи табло та статичну таблицю, я зміг досягти такого ж результату, використовуючи наступний код. Це відмінне рішення, тому що якщо у вас багато комірок дивної форми або хочете мати декілька комірок, які динамічно показані / приховані, цей код все одно буде працювати.

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

чи тут ще щось бракує? Висота комірок не змінюється :)
DevC

2
Оскільки для iOS 7.1 ви також повинні вибрати "Кліп до субвідоменів" в інспекторі атрибутів - ось що мені не вистачало :)
DevC

Також рядок "self.dateOpen =! Self.isDateOpen;" слід прочитати "self.isDateOpen =" на початку, а не "self.dateOpen ="
Пітер Джонсон

2
[tableView reloadData];Виклик не потрібно. Наразі це вимкнення вибору рядків, але краще скасувати виділення рядка таким чином:[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
Barry Haanstra

У мене були дивні ефекти анімації, такі як клітинка дати буде порожньою після "відкриття", але використання старту та ендупдаудів це вирішило. Приємно і гладко зараз. Дякуємо, датин
nh32rg

5

Я взяв джерело DateCell з Apple і видалив файл розкадровки.

Якщо ви хочете, щоб він не мав розповідь, подивіться на сторінку: https://github.com/ajaygautam/DateCellWithoutStoryboard


Завдяки @Ajay, я використовував свій виправлений код і хочу замінити UIDatePickerз UIPickerView. Я спробував декілька речей і міг показати їх pickerViewу кожній комірці, але вона не оновлюється з кожною коміркою. Я відправив своє питання і коди тут . Погляньте, і було б дуже люб'язно, якби ви могли запропонувати мені рішення.
Mughees Musaddiq

Я бачив ваше запитання ... він має занадто багато інформації, і насправді не дуже багато пояснює. Можливо, ви можете завантажити свій код / ​​блискавку кудись, щоб я подивився. Я можу його налагодити - якщо я можу запустити код ...
Аджай Гаутам

Спасибі, я як - то вдалося замінити UIDatePickerз , UIPickerViewале з кількома помилками. 1. Він виходить з ладу, коли ви відкриваєте UIPickerViewта прокручуєте таблицю. 2. Він автоматично присвоює значення UILabelDetail у нижчих рядках таблиці, коли значення присвоюються мітці Details у верхніх рядках. Ось мій код
Mughees Musaddiq

Чи можете ви знайти тест-проект, будь-яка удача ??
Mughees Musaddiq

Вибачте, я трохи зайнявся. Ще потрібна допомога з цим?
Аджай Гаутам

5

Один з найкращих навчальних посібників з цього приводу - iOS 7, вбудований UIDatePicker в iOS 7, частина 2 . В основному тут я використовую комірки статичного перегляду таблиці та реалізую деякі додаткові методи. Для цього я використовував Xamarin і C #:

Ви повинні діяти Clip Subviews .

Встановлення висоти:

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

    return base.GetHeightForRow(tableView,indexPath);
}

Чим змінну класу: private bool datePickerIsShowing = false;

Показати інструмент вибору дати:

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

Сховати інструмент вибору дати:

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

І виклик цієї функції:

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

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

2
Якщо ви виступаєте за акцію, можливо, ви зможете пояснити, чому ви виступаєте проти. Замість публікації посилань на сайти я також включив якийсь код. У моєму випадку це C #. Не знаю, що з цим погано.
тестування

3

Я створив власний власний контролер подання, щоб спростити процес додавання вибору вбудованого вбудованого рядка у вигляді таблиці. Ви просто підкласируєте його та дотримуєтесь простих правил, і він обробляє презентацію вибору дати.

Ви можете знайти його тут разом із прикладом проекту, який демонструє, як ним користуватися: https://github.com/ale84/ALEInlineDatePickerViewController


3

У прикладі datecell яблука я знайшов відповідь на дефект, у якому ви повинні мати рядок нижче останньої datecell або ви отримаєте помилку. У методі CellForRowAtIndexPath замініть рядок ItemData на

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

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

Після заміни зразкового коду тепер я можу відобразити відображення комірки datePicker, не маючи комірки під нею.

Я щойно приєднався до stackoverflow, тому якщо це не в тому місці чи десь ще, я вибачаюся.


3

Відповідь Аарона Братчера спрацювала, за винятком випадків, коли вони використовувались у кількох розділах. Анімація була трохи похмурою, і вона не ковзала наступними розділами вниз дуже добре. Щоб виправити це, я повторив наступний набір розділів і переклав рядки вниз на ту ж суму, що і висота вибору дати.

Я редагував didSelectRowAtIndexPath для:

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

Дякую @Timmahh, я виявив, що анімація в розділі теж хитра. Я успішно використовував ваше рішення в моєму першому додатку Swift! Я виявив, що cellForRowAtIndexPath повертає нуль там, де клітини поза екраном. Щоб уникнути цього, я додав колекцію IB-розетки, що містить усі мої клітини, що надійшли після комірки вибору, і повторив їх через ваш новий y_coord. Це здається негнучким, хоча мені доводиться постійно оновлювати колекцію, коли я додаю нові комірки.
Джош

Ти маєш рацію. Насправді я виправив проблему, але переповнення стека не дозволило мені редагувати код, який я туди вклав.
Тимофі Логан

3

Додавши до попередніх відповідей,

Я спробував і рішення @datinc, і @Aaron Bratcher, обидва працювали чудово, але анімація не була такою чистою в згрупованій статичній tableView.

Трохи погравши з цим, я дійшов до цього коду, який працює для мене чисто і чудово -

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

Основна зміна полягає у використанні -

        [super tableView:tableView heightForRowAtIndexPath:indexPath];

щоб оновити рядок, таким чином решта розділів та комірок таблиці не анімують.

Сподіваюся, це комусь допоможе.

Шані


Це надзвичайно допомогло; спасибі! Зокрема, аспект [super tableView] в комплекті з публікацією Аарона Братчера отримав мені потрібні результати в iOS 9.2. Ще раз дякую вам!
Терренс Шоу

2

Додавання до попередніх відповідей та рішення @Aaron Bratcher ...

З iOS 9 я отримував похмурі анімації, і завантажувати стіл потрібно було трохи часу, і це було достатньо для роздратування. Я звузив це, щоб підбирачі дат повільно завантажувались із аркуша розкадри. Додавання вибирачів програмно, а не дошка розгортки покращило ефективність завантаження, а як побічний продукт анімація плавніша.

Видаліть інструмент вибору дат із табло та мати порожню клітинку, яку ви встановите висоту, як у попередніх відповідях, а потім зателефонуйте на ініціалізацію у 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];
}

Потім реалізуйте дію, наприклад

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

Це завантажує стіл набагато швидше, ніж раніше. Ви також видаляєте рядок анімації, didSelectRowAtIndexPathоскільки вона плавно анімує без неї (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

Використання цієї відповіді без анімації працює правильно в iOS 8.1. Я перетворив його в Swift нижче:

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

Ось ще один спосіб вирішити задачу без статичних постійних чисел. Усі комірки можуть використовуватися у статичних та динамічних поданнях таблиць. Цей метод використовує одну клітинку як для вибору назви, так і для дати!

Тим не менш, у твоєму столі може бути стільки вибраних дат!

Створіть підклас UITableViewCell :

Усі осередки перегляду таблиці повинні бути успадковані від цього класу, і ви повинні встановити висоту комірок вручну для кожного ряду.

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

Створіть клас CPDatePickerTableViewCell з нашого 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

На ваш погляд, контролер реалізує ці два способи делегування

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

Приклад встановлення обмежень у конструкторі інтерфейсів

Інтерфейс-конструктор

Крім того, я написав спеціальні класи комірок для UITextField та UITextView, де tableView: didSelectRowAtIndexPath: викликається, коли вибрана комірка!

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

Висота комірки динамічна, і рядок буде зростати, коли текст буде переведено на новий рядок!

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

Найпростіший спосіб використання DateCell у версії Swift: Використовуйте цей приклад .

  1. Відкрийте цей приклад і протестуйте його (Зробіть Xcode для перетворення на Swift 2)
  2. Перетягніть клас " DateCellTableViewController.swift " до свого проекту.

  3. Відкрийте "Main.storyboard" та скопіюйте " DateCell " ViewController Object та вставте її у свою таблицю розкад.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.