iOS 7 - จะแสดงตัวเลือกวันที่ในมุมมองตารางได้อย่างไร?


121

ในวิดีโอ WWDC 2013 Apple แนะนำให้แสดงตัวเลือกในมุมมองตารางใน iOS 7 จะแทรกและทำให้มุมมองเคลื่อนไหวระหว่างเซลล์มุมมองตารางได้อย่างไร

เช่นนี้จากแอปปฏิทินของ Apple:

เครื่องมือเลือกวันที่ในสถานที่


นี่คือวิดีโอ WWDC ใด ฉันพยายามทำความเข้าใจว่าเหตุใดจึงเป็น iOS7 โดยเฉพาะและมีสาเหตุที่ทำให้ไม่สามารถทำได้ในเวอร์ชันก่อนหน้านี้
Clafou

4
พบแล้วมันคือ "มีอะไรใหม่ในการออกแบบอินเทอร์เฟซผู้ใช้ iOS" (ขอบคุณ ASCIIwwdc) เหตุผลก็คือการจัดแต่งทรงผมแบบเก่าดูไม่ถูกต้องแบบอินไลน์ แต่รูปลักษณ์ใหม่ที่ดูเรียบ
Clafou

คำตอบ:


102

ด้วย iOS7, DateCellแอปเปิ้ลเปิดตัวโค้ดตัวอย่าง

ใส่คำอธิบายภาพที่นี่

แสดงให้เห็นถึงการจัดรูปแบบการแสดงวัตถุวันที่ในเซลล์ตารางและการใช้ UIDatePicker เพื่อแก้ไขค่าเหล่านั้น ในฐานะผู้รับมอบสิทธิ์ในตารางนี้ตัวอย่างใช้เมธอด "didSelectRowAtIndexPath" เพื่อเปิดตัวควบคุม UIDatePicker

สำหรับ iOS 6.x และรุ่นก่อนหน้า UIViewAnimation ใช้สำหรับเลื่อน UIDatePicker ขึ้นบนหน้าจอและลงจากหน้าจอ สำหรับ iOS 7.x UIDatePicker จะถูกเพิ่มในบรรทัดในมุมมองตาราง

วิธีการดำเนินการของ UIDatePicker จะตั้งค่าคุณสมบัติ NSDate ของเซลล์ตารางที่กำหนดเองโดยตรง นอกจากนี้ตัวอย่างนี้ยังแสดงวิธีใช้คลาส NSDateFormatter เพื่อให้ได้รูปลักษณ์ที่จัดรูปแบบวันที่ของเซลล์แบบกำหนดเอง

ใส่คำอธิบายภาพที่นี่

คุณสามารถดาวน์โหลดโค้ดตัวอย่างที่นี่: datecell


รหัสของ Apple มีปัญหา ดูคำตอบของฉันด้านล่างหากคุณต้องการคง tableView ของคุณไว้
Aaron Bratcher

1
@AaronBratcher ฉันเพิ่งแนะนำDatecellในคำตอบของฉันและคุณไม่เคยคาดหวังว่าคุณจะได้รหัสที่แน่นอนที่คุณต้องการ คุณต้องแก้ไขและเปลี่ยนแปลงตามที่คุณต้องการ วิธีแก้ปัญหาของคุณก็ดีเช่นกัน แต่อย่าลืมว่าคุณไม่เคยเข้าใจสิ่งที่แน่นอนจากรหัสอื่น ๆ ที่คุณต้องการ
Nitin Gohel

3
โค้ดตัวอย่างที่น่ากลัวที่สุด พวกเขาสามารถทำได้โดยมีคำแนะนำว่าเมื่อใดควรสร้างวิธีการจาก Code Complete
Anirudha Agashe

2
ว้าวรหัส Apple คือ .... สมมติว่าโฟกัสอยู่ที่เอฟเฟกต์มุมมองตาราง ฉันหวังว่าจะไม่มีใครได้รับแรงบันดาลใจจากโค้ดของพวกเขาในโครงการตัวอย่างนี้: s
Daniel

84

คุณสามารถใช้คำตอบที่ฉันได้รับก่อนหน้านี้ด้านล่างหรือใช้ระดับใหม่นี้ในสวิฟท์ที่ผมทำเพื่อให้งานนี้เป็นจำนวนมากง่ายและทำความสะอาด: 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 เพราะฉันไม่ต้องการโหลดซ้ำทั้งหมด) นอกจากนี้บล็อกภาพเคลื่อนไหวก็ไม่จำเป็นดูเหมือนว่าจะเคลื่อนไหวได้ด้วยตัวเอง
Chris Garrett

มีใครใช้ตัวอย่างเพื่อสร้างตัวเลือกข้อความหรือไม่? ถ้าเป็นอย่างไร ขอบคุณ
TheGeezer

1
คุณต้องการเปิดเผยแถวเพื่อให้ผู้ใช้ป้อนข้อความแทนการเลือกวันที่? ถ้าเป็นเช่นนั้นรหัสจะเหมือนกัน เพียงแค่เนื้อหาของแถวที่เปิดเผยนั้นแตกต่างกัน
Aaron Bratcher

22
มีข้อผิดพลาดกับ iOS7.1 ที่แสดงวัตถุนอกขอบเขตเซลล์ - เช่นเดียวกับความสูง 0 และตัวเลือกภายใน วิธีแก้ไขคือหาทางออกสำหรับเซลล์และตั้งค่า cell.clipsToBounds = YES;
EmilDo

1
@Dunken - วิธีแก้ปัญหาอธิบายไว้ในความคิดเห็นที่โหวตด้านบน: stackoverflow.com/questions/18973573/…แม้ว่าแถวจะมีความสูงเป็นศูนย์ แต่เนื้อหาจะไม่ถูกตัดตามค่าเริ่มต้นดังนั้นคุณจึงสามารถเห็นได้ภายใต้ แถวต่อไปนี้
Chris 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 คุณต้องเลือก "Clip to SubViews" ในตัวตรวจสอบแอตทริบิวต์นั่นคือสิ่งที่ฉันขาดหายไป :)
DevC

นอกจากนี้บรรทัด "self.dateOpen =! self.isDateOpen;" ควรอ่าน "self.isDateOpen =" ตอนเริ่มต้นไม่ใช่ "self.dateOpen ="
Peter Johnson

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

ฉันเห็นคำถามของคุณ ... มีข้อมูลมากเกินไปและไม่ได้อธิบายอะไรมากนัก บางทีคุณอาจอัปโหลดรหัสของคุณ / ซิปไว้ที่ไหนสักแห่งเพื่อให้ฉันดู ฉันสามารถดีบักได้ - ถ้าฉันสามารถรันโค้ดได้ ...
Ajay Gautam

ขอบคุณฉันสามารถแทนที่UIDatePickerด้วยUIPickerViewข้อบกพร่องสองสามข้อได้ 1. มันขัดข้องเมื่อคุณเปิดUIPickerViewและเลื่อนตาราง 2. จะกำหนดค่าให้กับUILabelรายละเอียดโดยอัตโนมัติที่แถวล่างสุดของตารางเมื่อมีการกำหนดค่าให้กับป้ายรายละเอียดที่แถวบนสุด นี่คือรหัสของฉัน
Mughees Musaddiq

คุณสามารถหา testProject ได้หรือไม่?
Mughees Musaddiq

ขอโทษนะฉันยุ่งนิดหน่อย หากยังต้องการความช่วยเหลือ
Ajay Gautam

5

หนึ่งในบทเรียนที่ดีที่สุดเกี่ยวกับเรื่องนี้เป็นiOS 7 UIDatePicker ในบรรทัด - ส่วนที่ 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

ฉันได้สร้างตัวควบคุมมุมมองที่กำหนดเองเพื่อลดความซับซ้อนของกระบวนการเพิ่มตัวเลือกอินไลน์แบบอินไลน์ใน tableview คุณเพียงแค่ซับคลาสและปฏิบัติตามกฎง่ายๆและจัดการการนำเสนอตัวเลือกวันที่

คุณสามารถค้นหาได้ที่นี่พร้อมกับโครงการตัวอย่างที่สาธิตวิธีการใช้งาน: https://github.com/ale84/ALEInlineDatePickerViewController


3

ฉันพบคำตอบสำหรับข้อบกพร่องในตัวอย่าง datecell ของ apple ซึ่งคุณต้องมีแถวด้านล่าง 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

คำตอบจาก 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 ส่งคืนค่าศูนย์โดยที่เซลล์อยู่นอกหน้าจอ เพื่อหลีกเลี่ยงสิ่งนี้ฉันได้เพิ่มคอลเลกชัน IB outlet ที่มีเซลล์ทั้งหมดของฉันซึ่งมาตามหลังเซลล์ตัวเลือกและวนซ้ำด้วย 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];

เพื่ออัปเดตแถววิธีนี้ส่วนที่เหลือของตารางและเซลล์จะไม่เคลื่อนไหว

หวังว่ามันจะช่วยใครบางคน

Shani


สิ่งนี้ช่วยได้มาก ขอบคุณ! โดยเฉพาะด้าน [super tableView] ที่มาพร้อมกับโพสต์ของ Aaron Bratcher ทำให้ฉันได้รับผลลัพธ์ที่ต้องการบน 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

สร้างคลาส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 และวางลงในสตอรี่บอร์ดของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.