iOS 7-테이블보기에서 날짜 선택기를 표시하는 방법은 무엇입니까?


121

WWDC 2013 비디오에서 Apple은 iOS 7의 테이블보기에 선택기를 표시 할 것을 제안합니다. 테이블보기 셀간에보기를 삽입하고 애니메이션하는 방법은 무엇입니까?

이와 같이 Apple 캘린더 앱에서 :

현재 위치 날짜 선택기


이것은 어떤 WWDC 비디오입니까? 왜 이것이 iOS7에 한정되어 있는지, 그리고 이전 버전에서는 이것이 불가능한 이유가 있는지 이해하려고합니다.
Clafou

4
"iOS 사용자 인터페이스 디자인의 새로운 기능"입니다 (ASCIIwwdc에게 감사드립니다). 이론적 근거는 이전 스타일이 제대로 인라인으로 보이지 않았지만 새로운 평면 모양이 그렇다는 것입니다.
Clafou

답변:


102

iOS7에서 Apple은 샘플 코드를 출시했습니다 DateCell.

여기에 이미지 설명 입력

테이블 셀에서 날짜 개체의 서식이 지정된 표시와 UIDatePicker를 사용하여 해당 값을 편집하는 방법을 보여줍니다. 이 테이블의 대리자로서 샘플은 "didSelectRowAtIndexPath"메서드를 사용하여 UIDatePicker 컨트롤을 엽니 다.

iOS 6.x 및 이전 버전의 경우 UIViewAnimation은 UIDatePicker를 화면에서 위로, 화면에서 아래로 슬라이딩하는 데 사용됩니다. iOS 7.x의 경우 UIDatePicker가 테이블보기에 인라인으로 추가됩니다.

UIDatePicker의 동작 메서드는 사용자 지정 테이블 셀의 NSDate 속성을 직접 설정합니다. 또한이 샘플은 NSDateFormatter 클래스를 사용하여 사용자 지정 셀의 날짜 형식 모양을 얻는 방법을 보여줍니다.

여기에 이미지 설명 입력

여기에서 샘플 코드를 다운로드 할 수 있습니다 : DateCell .


Apple의 코드에 문제가 있습니다. 당신이 당신의 정적있는 tableView 유지하려면 내 대답은 아래를 참조
아론 Bratcher

1
@AaronBratcher 나는 내 대답에 Datecell 을 소개 하고 원하는 정확한 코드를 얻을 것이라고 결코 기대하지 않습니다. 필요에 따라 수정하고 변경해야합니다. 솔루션도 좋지만 다른 코드에서 요구하는 것을 정확히 얻을 수 없다는 것을 기억하십시오.
Nitin Gohel 2013

3
가장 끔찍한 샘플 코드. 그들은 전체 코드에서 방법을 작성하는 경우에 대한 몇 가지 조언을 할 수
Anirudha Agashe

2
와우 애플 코드는 .... 글쎄, 초점이 테이블 뷰 효과에 있다고 가정 해 봅시다. 이 샘플 프로젝트의 코드에서 영감을받은 사람은 아무도 없기를 바랍니다. s
Daniel

84

이전에 아래에 제시 한 답변을 사용하거나 Swift에서이 새로운 클래스를 사용하여이 작업을 훨씬 더 간단하고 깔끔하게 만들 수 있습니다 : https://github.com/AaronBratcher/TableViewHelper


Apple에서 제공하는 코드는 몇 가지 문제가 있습니다.

  • tableView : cellForRowAtIndexPath 메서드를 사용하고 있기 때문에 정적 tableView를 가질 수 없습니다.
  • 마지막 날짜 선택기 셀 아래에 추가 행이 없으면 코드가 충돌합니다.

정적 셀 테이블의 경우 날짜 표시 셀 아래에 날짜 선택기 셀을 정의하고 편집 중인지 여부를 식별하는 플래그가 있습니다. 그렇다면 적절한 셀 높이를 반환하고 그렇지 않으면 0의 셀 높이를 반환합니다.

- (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를 사용하지 않았습니다). 또한 애니메이션 블록이 필요하지 않았으며 자체적으로 잘 애니메이션되는 것 같습니다.
Chris Garrett

샘플을 사용하여 텍스트 선택기를 만든 사람이 있습니까? 그렇다면 어떻게? 감사합니다
TheGeezer 2013-12-13

1
사용자가 날짜를 선택하는 대신 텍스트를 입력 할 수 있도록 행을 표시한다는 의미입니까? 그렇다면 코드는 동일합니다. 공개 된 행의 내용 만 다릅니다.
Aaron Bratcher

22
iOS7.1에는 높이가 0이고 내부에 선택기가있는 개체와 같이 셀 경계를 벗어난 개체를 표시하는 버그가 있습니다. 해결책은 셀에 대한 콘센트를 얻고 cell.clipsToBounds = YES를 설정하는 것입니다.
EmilDo 2014 년

1
@Dunken-해결책은 위의 투표 된 댓글에 설명되어 있습니다. stackoverflow.com/questions/18973573/… 행의 높이가 0이더라도 기본적으로 내용은 잘리지 않으므로 아래에서 볼 수 있습니다. 다음 행.
크리스 Nolet

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부터는 Attributes inspector에서 "Clip to SubViews"를 선택해야합니다.-이것이 제가 놓친 것입니다. :)
DevC

또한 "self.dateOpen =! self.isDateOpen;"줄 "self.dateOpen ="이 아니라 시작시 "self.isDateOpen ="을 읽어야합니다.
Peter Johnson

2
[tableView reloadData];호출이 필요하지 않습니다. 현재는 행 선택을 비활성화하지만이 같은 행을 선택 해제하는 것이 좋습니다 :[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
배리 Haanstra

"열기"후에 날짜 셀이 비어있는 것과 같은 이상한 애니메이션 효과가 있었지만 시작 및 종료 업데이트를 사용하면 문제가 해결되었습니다. 이제 멋지고 부드럽습니다. 감사합니다 datinc!
nh32rg 2015

5

Apple에서 DateCell 소스를 가져와 스토리 보드 파일을 제거했습니다.

스토리 보드없이 하나를 원한다면 https://github.com/ajaygautam/DateCellWithoutStoryboard를 살펴보십시오.


@Ajay에게 감사합니다. 수정 된 코드를 사용 UIDatePicker했으며 UIPickerView. 나는 몇 가지를 시도 pickerView하고 각 셀 에 표시 할 수 있었지만 각 셀에서 업데이트되지 않습니다. 여기 에 내 질문과 코드를 게시했습니다 . 저에게 해결책을 제안 할 수 있다면 매우 친절 할 것입니다.
Mughees Musaddiq 2014

귀하의 질문을 봤습니다 ... 정보가 너무 많고 설명이별로 없습니다. 아마도 코드를 업로드하거나 내가 살펴볼 수 있도록 어딘가에 압축 할 수 있습니다. 나는 그것을 디버깅 할 수 있습니다 - 내가 코드를 실행할 수 있는지 ...
아제 가우 탐에게

고마워, 나는 어떻게 든 몇 가지 버그 로 교체 UIDatePicker했습니다 UIPickerView. 1. UIPickerView테이블 을 열고 스크롤 하면 충돌이 발생 합니다. 2. UILabel상단 행의 Details 레이블에 값을 할당 할 때 테이블의 하단 행에있는 Detail에 값을 자동으로 할당합니다 . 여기 내 코드입니다
Mughees Musaddiq

testProject를 찾을 수 있습니까, 행운이 있습니까 ??
Mughees Musaddiq 2014

죄송합니다. 좀 바빠서 요. 여전히 도움이 필요하십니까?
Ajay Gautam

5

이것에 대한 최고의 튜토리얼 중 하나는 iOS 7 인라인 UIDatePicker – Part 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

마지막 날짜 셀 아래에 행이 있어야하거나 오류가 발생하는 사과의 날짜 셀 예제에서 결함에 대한 답변을 찾았습니다. CellForRowAtIndexPath 메서드에서 ItemData 줄을

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

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

샘플 코드를 교체 한 후에는 아래에 셀이 없어도 datePicker 셀을 표시 할 수 있습니다.

나는 방금 stackoverflow에 가입했기 때문에 이것이 잘못된 장소에 있거나 다른 곳에 있으면 사과드립니다.


3

Aaron Bratcher의 답변은 여러 섹션에서 사용할 때를 제외하고는 작동했습니다. 애니메이션이 약간 고르지 않았고 다음 섹션이 잘 아래로 미끄러지지 않았습니다. 이 문제를 해결하기 위해 다음 섹션 세트를 반복하고 날짜 선택기의 높이와 같은 양으로 행을 번역했습니다.

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가 셀이 화면 밖에서 nil을 반환한다는 것을 발견했습니다. 이를 방지하기 위해 선택기 셀 뒤에 오는 모든 셀을 포함하는 IB 콘센트 컬렉션을 추가하고 새 y_coord로 반복했습니다. 새 셀을 추가 할 때 컬렉션을 최신 상태로 유지해야하므로 융통성이 없어 보입니다.
Josh

네가 옳아. 사실, 나는 문제를 해결했지만 스택 오버플로로 내가 거기에 넣은 코드를 편집 할 수 없었습니다.
Timothy Logan

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

행을 업데이트하려면 나머지 테이블 섹션과 셀이 애니메이션되지 않습니다.

누군가에게 도움이되기를 바랍니다.

샤니


이것은 엄청난 도움이되었습니다. 감사합니다! 특히 Aaron Bratcher의 게시물과 함께 제공되는 [super tableView] 측면은 iOS 9.2에서 필요한 결과를 얻었습니다. 다시 감사합니다!
Terrance Shaw

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

정적 상수없이 문제를 해결하는 또 다른 방법이 있습니다. 모든 셀은 정적 및 동적 테이블보기에서 사용할 수 있습니다. 이 방법은 제목과 날짜 선택기에 단일 셀을 사용합니다!

Btw 당신이 원하는만큼 테이블에 날짜 선택기를 가질 수 있습니다!

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

CPTableViewCell 에서 CPDatePickerTableViewCell 클래스를 만듭니다.

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

인터페이스 빌더에서 제한 조건을 설정하는 방법의 예

인터페이스 빌더

또한 UITextFieldUITextView에 대한 사용자 정의 셀 클래스를 작성했습니다. 여기서 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

Swift 버전에서 DateCell을 사용하는 가장 쉬운 방법 : Use this example .

  1. 이 예제를 열고 테스트 (Make Xcode to Convert to Swift 2)
  2. " DateCellTableViewController.swift "클래스를 프로젝트로 드래그 합니다.

  3. "Main.storyboard"를 열고 "DateCell" ViewController 개체를 복사 하여 스토리 보드에 붙여 넣 습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.