ความสูงของเซลล์แบบไดนามิก UITableView จะถูกต้องหลังจากการเลื่อนบางครั้งเท่านั้น


117

ฉันมีแบบUITableViewกำหนดเองUITableViewCellในสตอรีบอร์ดโดยใช้รูปแบบอัตโนมัติ เซลล์มีหลายสายUILabelsสาย

UITableViewปรากฏขึ้นให้สูงเซลล์คำนวณอย่างถูกต้อง แต่สำหรับไม่กี่เซลล์แรกที่มีความสูงไม่ได้แบ่งแยกออกจากกันอย่างถูกต้องระหว่างฉลาก หลังจากเลื่อนไปเล็กน้อยทุกอย่างจะทำงานตามที่คาดไว้ (แม้แต่เซลล์ที่เริ่มต้นไม่ถูกต้อง)

- (void)viewDidLoad {
    [super viewDidLoad]
    // ...
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"];
    // ...
    // Set label.text for variable length string.
    return cell;
}

มีอะไรที่ฉันอาจขาดหายไปซึ่งทำให้การจัดวางอัตโนมัติไม่สามารถทำงานได้ในสองสามครั้งแรก?

ฉันได้สร้างโครงการตัวอย่างที่แสดงให้เห็นถึงพฤติกรรมนี้

โครงการตัวอย่าง: มุมมองด้านบนของตารางจากโครงการตัวอย่างในการโหลดครั้งแรก โครงการตัวอย่าง: เซลล์เดียวกันหลังจากเลื่อนลงและสำรองข้อมูล


1
ฉันกำลังประสบปัญหานี้เช่นกัน แต่คำตอบด้านล่างไม่ได้ผลสำหรับฉันความช่วยเหลือใด ๆ เกี่ยวกับเรื่องนี้
Shangari C

1
ประสบปัญหาเดียวกันกับการเพิ่ม layoutIfNeeded สำหรับเซลล์ไม่ได้ผลเช่นกัน? ข้อเสนอแนะเพิ่มเติม
สูงสุด

1
จุดที่ดี สิ่งนี้ยังคงเป็นปัญหาในปี 2019: /
Fattie

ฉันพบสิ่งที่ช่วยฉันได้ในลิงค์ต่อไปนี้ - เป็นการอภิปรายที่ครอบคลุมเกี่ยวกับเซลล์มุมมองตารางความสูงตัวแปร: stackoverflow.com/a/18746930/826946
Andy Weinstein

คำตอบ:


139

ฉันไม่รู้ว่านี่เป็นเอกสารที่ชัดเจนหรือไม่ แต่การเพิ่ม[cell layoutIfNeeded]ก่อนส่งคืนเซลล์จะช่วยแก้ปัญหาของคุณได้

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"];
    NSUInteger n1 = firstLabelWordCount[indexPath.row];
    NSUInteger n2 = secondLabelWordCount[indexPath.row];
    [cell setNumberOfWordsForFirstLabel:n1 secondLabel:n2];

    [cell layoutIfNeeded]; // <- added

    return cell;
}

3
ฉันสงสัยว่าทำไมถึงจำเป็นเพียงครั้งแรกที่ผ่านมา? การทำงานก็เช่นกันถ้าฉันใส่การเรียกร้องให้ในส่วนของมือถือ-layoutIfNeeded -awakeFromNibฉันต้องการโทรหาเฉพาะlayoutIfNeededที่ที่ฉันรู้ว่าทำไมจึงจำเป็น
blackp

2
ทำงานให้ฉัน! และฉันชอบที่จะรู้ว่าทำไมจึงต้องมี!
มุสตาฟา

ใช้งานไม่ได้ถ้าคุณสร้างคลาสขนาดซึ่งแตกต่างจาก X ใด ๆ
Andrei Konstantinov

@AndreyKonstantinov ใช่มันไม่ทำงานกับคลาสขนาดฉันจะทำให้มันทำงานกับคลาสขนาดได้อย่างไร
z22

ใช้งานได้โดยไม่มีคลาสขนาดโซลูชันใด ๆ ที่มีคลาสขนาดหรือไม่
Yuvrajsinh

38

สิ่งนี้ใช้ได้ผลสำหรับฉันเมื่อโซลูชันอื่นที่คล้ายกันไม่ได้:

override func didMoveToSuperview() {
    super.didMoveToSuperview()
    layoutIfNeeded()
}

ดูเหมือนว่าจะเป็นข้อบกพร่องที่เกิดขึ้นจริงเนื่องจากฉันคุ้นเคยกับ AutoLayout และวิธีใช้ UITableViewAutomaticDimension เป็นอย่างดีอย่างไรก็ตามฉันยังคงพบปัญหานี้เป็นครั้งคราว ในที่สุดฉันก็ดีใจที่พบสิ่งที่เป็นวิธีแก้ปัญหาได้


1
ดีกว่าคำตอบที่ยอมรับเนื่องจากถูกเรียกเฉพาะเมื่อเซลล์กำลังโหลดจาก xib แทนที่จะแสดงทุกเซลล์ บรรทัดโค้ดน้อยเกินไป
Robert Wagstaff

3
อย่าลืมโทรsuper.didMoveToSuperview()
cicerocamargo

@cicerocamargo Apple กล่าวเกี่ยวกับdidMoveToSuperview: "การใช้งานตามค่าเริ่มต้นของวิธีนี้ไม่ได้ทำอะไรเลย"
Ivan Smetanin

4
@IvanSmetanin ไม่สำคัญว่าการใช้งานเริ่มต้นจะไม่ทำอะไรคุณควรเรียก super method เพราะมันสามารถทำอะไรบางอย่างได้ในอนาคต
TNguyen

(เพียงแค่คุณควรเรียก super อย่างแน่นอนในเรื่องนั้นฉันไม่เคยเห็นโครงการที่ทีมโดยรวมไม่ได้ subclass มากกว่าหนึ่งเซลล์ดังนั้นแน่นอนว่าคุณต้องเลือกมันทั้งหมดและในฐานะ แยกประเด็นเฉพาะสิ่งที่ TNguyen พูด)
Fattie

22

การเพิ่ม[cell layoutIfNeeded]เข้าใช้cellForRowAtIndexPathไม่ได้กับเซลล์ที่ถูกเลื่อนออกจากมุมมองในตอนแรก

หรือไม่ prefacing [cell setNeedsLayout]ด้วย

คุณยังคงต้องเลื่อนเซลล์บางเซลล์ออกและกลับเข้าไปดูเพื่อให้ปรับขนาดได้อย่างถูกต้อง

สิ่งนี้ค่อนข้างน่าผิดหวังเนื่องจาก devs ส่วนใหญ่มี Dynamic Type, AutoLayout และ Self-Sizing Cells ทำงานได้อย่างถูกต้อง - ยกเว้นในกรณีที่น่ารำคาญนี้ ข้อบกพร่องนี้ส่งผลกระทบต่อตัวควบคุมมุมมองตารางที่ "สูงกว่า" ทั้งหมดของฉัน


เหมือนกับฉัน. เมื่อฉันเลื่อนครั้งแรกขนาดของเซลล์คือ 44px ถ้าฉันเลื่อนเพื่อให้เซลล์อยู่นอกสายตาและกลับมาแสดงว่ามีขนาดเหมาะสม คุณพบวิธีแก้ปัญหาหรือไม่?
สูงสุด

ขอบคุณ @ ashy_32bit สิ่งนี้แก้ไขให้ฉันเช่นกัน
ImpurestClub

ดูเหมือนจะเป็นข้อผิดพลาดธรรมดา @Scenario ใช่ไหม? สิ่งที่น่ากลัว
Fattie

3
การใช้[cell layoutSubviews]แทน layoutIfNeeded อาจเป็นไปได้ในการแก้ไข อ้างอิงstackoverflow.com/a/33515872/1474113
ypresto

14

ฉันมีประสบการณ์เดียวกันในโครงการหนึ่งของฉัน

ทำไมมันถึงเกิดขึ้น?

เซลล์ที่ออกแบบใน Storyboard โดยมีความกว้างสำหรับบางอุปกรณ์ ตัวอย่างเช่น 400px ตัวอย่างเช่นฉลากของคุณมีความกว้างเท่ากัน เมื่อโหลดจากสตอรีบอร์ดจะมีความกว้าง 400px

นี่คือปัญหา:

tableView:heightForRowAtIndexPath: เรียกก่อนเค้าโครงเซลล์เป็นมุมมองย่อย

ดังนั้นจึงคำนวณความสูงสำหรับป้ายกำกับและเซลล์ที่มีความกว้าง 400px แต่คุณเรียกใช้บนอุปกรณ์ที่มีหน้าจอเช่น 320px และความสูงที่คำนวณโดยอัตโนมัตินี้ไม่ถูกต้อง เพียงเพราะเซลล์layoutSubviewsเกิดขึ้นหลังจากtableView:heightForRowAtIndexPath: แม้ว่าคุณจะตั้งค่าpreferredMaxLayoutWidthป้ายกำกับด้วยตนเองก็ตามlayoutSubviewsก็ตาม แต่ก็ไม่ช่วยอะไร

วิธีแก้ปัญหาของฉัน:

1) คลาสและแทนที่UITableView dequeueReusableCellWithIdentifier:forIndexPath:ตั้งค่าความกว้างของเซลล์ให้เท่ากับความกว้างของตารางและบังคับเค้าโครงของเซลล์

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [super dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
    CGRect cellFrame = cell.frame;
    cellFrame.size.width = self.frame.size.width;
    cell.frame = cellFrame;
    [cell layoutIfNeeded];
    return cell;
}

2) UITableViewCellซับคลาส ตั้งค่าด้วยตนเองสำหรับป้ายชื่อของคุณpreferredMaxLayoutWidth layoutSubviewsนอกจากนี้คุณต้องจัดวางด้วยตนเองcontentViewเนื่องจากไม่ได้จัดวางโดยอัตโนมัติหลังจากเปลี่ยนกรอบเซลล์ (ฉันไม่รู้ว่าทำไม แต่เป็น)

- (void)layoutSubviews {
    [super layoutSubviews];
    [self.contentView layoutIfNeeded];
    self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width;
}

1
เมื่อฉันพบปัญหานี้ฉันต้องตรวจสอบให้แน่ใจว่าเฟรมของ tableview นั้นถูกต้องดังนั้นฉันจึงเรียก [self.tableview layoutIfNeeded] ก่อนที่ tableview จะถูกเติมข้อมูล (ใน viewDidLoad)
GK100

ฉันไม่เคยหยุดที่จะคิดว่ามันเกี่ยวข้องกับความกว้างที่ไม่ถูกต้อง cell.frame.size.width = tableview.frame.widthจากนั้นcell.layoutIfNeeded()ในcellForRowAtฟังก์ชั่นก็ใช้เคล็ดลับสำหรับฉัน
Cam Connor

10

ฉันมีปัญหาที่คล้ายกันในการโหลดครั้งแรกความสูงของแถวไม่ได้ถูกคำนวณ แต่หลังจากเลื่อนหรือไปที่หน้าจออื่นและฉันกลับมาที่แถวหน้าจอนี้จะถูกคำนวณ ในการโหลดครั้งแรกรายการของฉันจะโหลดจากอินเทอร์เน็ตและในการโหลดครั้งที่สองรายการของฉันจะถูกโหลดก่อนจากข้อมูลหลักและโหลดซ้ำจากอินเทอร์เน็ตและฉันสังเกตเห็นว่าความสูงของแถวจะคำนวณจากการโหลดซ้ำจากอินเทอร์เน็ต ดังนั้นฉันสังเกตเห็นว่าเมื่อ tableView.reloadData () ถูกเรียกในระหว่างการทำภาพเคลื่อนไหวต่อเนื่อง (ปัญหาเดียวกันกับการผลักดันและการทำตามปัจจุบัน) ความสูงของแถวไม่ได้ถูกคำนวณ ดังนั้นฉันจึงซ่อน tableview ไว้ที่การเริ่มต้นมุมมองและใส่ตัวโหลดกิจกรรมเพื่อป้องกันผลกระทบที่น่าเกลียดต่อผู้ใช้และฉันเรียก tableView.reloadData หลังจาก 300ms และตอนนี้ปัญหาได้รับการแก้ไขแล้ว ฉันคิดว่ามันเป็นข้อผิดพลาดของ UIKit แต่วิธีแก้ปัญหานี้ทำให้เคล็ดลับ

ฉันใส่บรรทัดเหล่านี้ (Swift 3.0) ในตัวจัดการการโหลดรายการของฉัน

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: {
        self.tableView.isHidden = false
        self.loader.stopAnimating()
        self.tableView.reloadData()
    })

สิ่งนี้จะอธิบายว่าทำไมสำหรับบางคนให้ใส่ reloadData ใน layoutSubviews เพื่อแก้ปัญหา


นี่เป็น WA คนเดียวที่ทำงานให้ฉันด้วย ยกเว้นฉันไม่ได้ใช้ isHidden แต่ตั้งค่าอัลฟาของตารางเป็น 0 เมื่อเพิ่มแหล่งข้อมูลจากนั้นเป็น 1 หลังจากโหลดซ้ำ
PJ_Finnegan

6

วิธีแก้ปัญหาข้างต้นไม่ได้ผลสำหรับฉันสิ่งที่ได้ผลคือสูตรแห่งเวทมนตร์นี้: เรียกพวกเขาตามลำดับนี้:

tableView.reloadData()
tableView.layoutIfNeeded() tableView.beginUpdates() tableView.endUpdates()

ข้อมูล tableView ของฉันได้รับการเติมจากบริการเว็บในการโทรกลับของการเชื่อมต่อฉันเขียนบรรทัดด้านบน


1
สำหรับ Swift 5 สิ่งนี้ใช้งานได้แม้ในมุมมองคอลเลกชันขอพระเจ้าอวยพรคุณ
Govani Dhruv Vijaykumar

สำหรับฉันสิ่งนี้ส่งคืนความสูงและเลย์เอาต์ที่ถูกต้องของเซลล์ แต่ไม่มีข้อมูลอยู่ในนั้น
Darrow Hartman

ลอง setNeedsDisplay () หลังบรรทัดเหล่านั้น
JAHelia

5

ในกรณีของฉันบรรทัดสุดท้ายของ UILabel ถูกตัดทอนเมื่อเซลล์ถูกแสดงเป็นครั้งแรก มันค่อนข้างสุ่มและวิธีเดียวที่จะปรับขนาดให้ถูกต้องคือเลื่อนเซลล์ออกจากมุมมองและนำกลับมา ฉันลองวิธีแก้ปัญหาที่เป็นไปได้ทั้งหมดที่แสดงจนถึงตอนนี้ (layoutIfNeeded..reloadData) แต่ไม่มีอะไรได้ผล เคล็ดลับคือการตั้งค่า"Autoshrink"เป็นMinimuum Font Scale (0.5 สำหรับฉัน) ให้มันลอง


สิ่งนี้ใช้ได้ผลสำหรับฉันโดยไม่ต้องใช้วิธีแก้ไขปัญหาอื่นใดที่ระบุไว้ข้างต้น การค้นพบที่ยอดเยี่ยม
mckeejm

2
แต่สิ่งนี้จะทำให้ข้อความอัตโนมัติ ... ทำไมเราถึงต้องการมีขนาดข้อความที่แตกต่างกันในมุมมองตาราง? ดูแย่มาก
lucius degeer

5

เพิ่มข้อ จำกัด สำหรับเนื้อหาทั้งหมดภายในเซลล์แบบกำหนดเองของมุมมองตารางจากนั้นประมาณความสูงของแถวมุมมองตารางและตั้งค่าความสูงของแถวเป็นมิติข้อมูลอัตโนมัติในโหลด viewdid:

    override func viewDidLoad() {
    super.viewDidLoad()

    tableView.estimatedRowHeight = 70
    tableView.rowHeight = UITableViewAutomaticDimension
}

ในการแก้ไขปัญหาการโหลดครั้งแรกให้ใช้เมธอด layoutIfNeeded กับในเซลล์มุมมองตารางแบบกำหนดเอง:

class CustomTableViewCell: UITableViewCell {

override func awakeFromNib() {
    super.awakeFromNib()
    self.layoutIfNeeded()
    // Initialization code
}
}

สิ่งสำคัญคือต้องตั้งค่าestimatedRowHeightเป็นค่า> 0 และไม่เป็นUITableViewAutomaticDimension(ซึ่งเท่ากับ -1) มิฉะนั้นความสูงของแถวอัตโนมัติจะไม่ทำงาน
PJ_Finnegan

5

ฉันได้ลองใช้คำตอบส่วนใหญ่สำหรับคำถามนี้แล้วและไม่สามารถหาคำตอบได้เลย โซลูชันที่ใช้งานได้เดียวที่ฉันพบคือเพิ่มสิ่งต่อไปนี้ในUITableViewControllerคลาสย่อยของฉัน:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    UIView.performWithoutAnimation {
        tableView.beginUpdates()
        tableView.endUpdates()
    }
}

UIView.performWithoutAnimationโทรจะต้องมิฉะนั้นคุณจะเห็นภาพเคลื่อนไหวดูตารางปกติโหลดมุมมองควบคุม


ทำงานได้ดีกว่าการเรียกใช้ reloadData สองครั้ง
Jimmy George Thomas

2
มนต์ดำ. ทำในviewWillAppearไม่ได้ผลสำหรับฉัน แต่ทำในviewDidAppearไม่
Martin

โซลูชันนี้ 'ไม่ได้ผล' สำหรับฉันเมื่อใช้งานใน viewDidAppear มันไม่ได้เหมาะสมที่สุดสำหรับประสบการณ์ของผู้ใช้เนื่องจากเนื้อหาตารางจะกระโดดไปมาเมื่อการปรับขนาดที่ถูกต้องเกิดขึ้น
richardpiazza

น่าทึ่งมากฉันได้ลองตัวอย่างมากมาย แต่ล้มเหลวคุณเป็นปีศาจ
Shakeel Ahmed

เหมือนกับ @martin
AJ Hernandez


3

โทรcell.layoutIfNeeded()เข้าไปข้างในcellForRowAtงานได้สำหรับฉันบน iOS 10 และ ios 11 แต่ไม่ใช่บน iOS 9

เพื่อให้ได้งานนี้บน ios 9 ด้วยฉันเรียกcell.layoutSubviews()และมันก็เป็นเคล็ดลับ


2

การแนบภาพหน้าจอสำหรับการอ้างอิงของคุณสำหรับฉันวิธีการเหล่านี้ไม่ได้ผล แต่ฉันพบว่าป้ายกำกับมีการPreferred Widthตั้งค่าอย่างชัดเจนในตัวสร้างอินเทอร์เฟซ การลบสิ่งนั้น (ยกเลิกการเลือก "Explicit") จากนั้นใช้UITableViewAutomaticDimensionงานได้ตามที่คาดไว้


2

ฉันลองวิธีแก้ปัญหาทั้งหมดในหน้านี้แล้ว แต่การยกเลิกการเลือกใช้คลาสขนาดจากนั้นตรวจสอบอีกครั้งเพื่อแก้ปัญหาของฉัน

แก้ไข: การไม่เลือกคลาสขนาดทำให้เกิดปัญหามากมายในสตอรีบอร์ดดังนั้นฉันจึงลองวิธีอื่น ฉันเติมข้อมูลมุมมองตารางในตัวควบคุมมุมมองviewDidLoadและviewWillAppearวิธีการของฉัน สิ่งนี้ช่วยแก้ปัญหาของฉันได้


1

ฉันมีปัญหากับการปรับขนาดฉลากดังนั้นฉันจึงต้องทำ
chatTextLabel.text = chatMessage.message chatTextLabel? .updateConstraints () หลังจากตั้งค่าข้อความ

// รหัสเต็ม

func setContent() {
    chatTextLabel.text = chatMessage.message
    chatTextLabel?.updateConstraints()

    let labelTextWidth = (chatTextLabel?.intrinsicContentSize().width) ?? 0
    let labelTextHeight = chatTextLabel?.intrinsicContentSize().height

    guard labelTextWidth < originWidth && labelTextHeight <= singleLineRowheight else {
      trailingConstraint?.constant = trailingConstant
      return
    }
    trailingConstraint?.constant = trailingConstant + (originWidth - labelTextWidth)

  }

1

ในกรณีของฉันฉันกำลังอัปเดตในรอบอื่น ดังนั้นความสูงของ tableViewCell จึงได้รับการอัปเดตหลังจากตั้งค่า labelText ฉันลบบล็อก async

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCell(withIdentifier:Identifier, for: indexPath) 
     // Check your cycle if update cycle is same or not
     // DispatchQueue.main.async {
        cell.label.text = nil
     // }
}

ฉันยังมีบล็อก async แต่จำเป็น? ไม่มีทางเลือกอื่นหรือ?
Nazar Medeiros

1

ตรวจสอบให้แน่ใจว่าคุณไม่ได้ตั้งค่าข้อความป้ายกำกับในวิธีมอบหมาย 'willdisplaycell' ของมุมมองตาราง ตั้งค่าข้อความป้ายกำกับในวิธีการมอบหมาย 'cellForRowAtindexPath' สำหรับการคำนวณความสูงแบบไดนามิก

ยินดีต้อนรับคุณ :)


1

ในกรณีของฉันมุมมองสแต็กในเซลล์ทำให้เกิดปัญหา เห็นได้ชัดว่าเป็นข้อผิดพลาด เมื่อฉันลบออกแล้วปัญหาก็จะได้รับการแก้ไข


1
ฉันลองใช้วิธีแก้ปัญหาอื่น ๆ ทั้งหมดแล้วโซลูชันของคุณใช้งานได้ดีสำหรับขอบคุณที่แบ่งปัน
tamtoum1987

1

ปัญหาคือเซลล์เริ่มต้นจะโหลดก่อนที่เราจะมีความสูงของแถวที่ถูกต้อง วิธีแก้ปัญหาคือบังคับให้ตารางโหลดซ้ำเมื่อมุมมองปรากฏขึ้น

- (void)viewDidAppear:(BOOL)animated
{
  [super viewDidAppear:animated];
  [self.tableView reloadData];
}

นี่เป็นทางออกที่ดีที่สุดที่ช่วยฉันได้ ไม่ได้แก้ไข 100% ของเซลล์ แต่มากถึง 80% ที่ใช้ขนาดจริง ขอบคุณมาก
TheTravloper

1

สำหรับ iOS 12+ เท่านั้นปี 2019 เป็นต้นไป ...

ตัวอย่างต่อเนื่องของการไร้ความสามารถที่แปลกประหลาดเป็นครั้งคราวของ Apple ซึ่งปัญหาเกิดขึ้นเป็นเวลาหลายปี

ดูเหมือนจะเป็นอย่างนั้น

        cell.layoutIfNeeded()
        return cell

จะแก้ไขได้ (แน่นอนว่าคุณกำลังสูญเสียประสิทธิภาพบางอย่าง)

นั่นคือชีวิตของ Apple


0

ในกรณีของฉันปัญหาเกี่ยวกับความสูงของเซลล์จะเกิดขึ้นหลังจากที่โหลดมุมมองตารางเริ่มต้นและการดำเนินการของผู้ใช้จะเกิดขึ้น (แตะที่ปุ่มในเซลล์ที่มีผลต่อการเปลี่ยนความสูงของเซลล์) ฉันไม่สามารถทำให้เซลล์เปลี่ยนความสูงได้เว้นแต่ฉันจะทำ:

[self.tableView reloadData];

ฉันไม่ได้ลอง

[cell layoutIfNeeded];

แต่ไม่ได้ผล


0

ใน Swift 3 ฉันต้องเรียก self.layoutIfNeeded () ทุกครั้งที่ฉันอัปเดตข้อความของเซลล์ที่ใช้ซ้ำได้

import UIKit
import SnapKit

class CommentTableViewCell: UITableViewCell {

    static let reuseIdentifier = "CommentTableViewCell"

    var comment: Comment! {
        didSet {
            textLbl.attributedText = comment.attributedTextToDisplay()
            self.layoutIfNeeded() //This is a fix to make propper automatic dimentions (height).
        }
    }

    internal var textLbl = UILabel()

    override func layoutSubviews() {
        super.layoutSubviews()

        if textLbl.superview == nil {
            textLbl.numberOfLines = 0
            textLbl.lineBreakMode = .byWordWrapping
            self.contentView.addSubview(textLbl)
            textLbl.snp.makeConstraints({ (make) in
                make.left.equalTo(contentView.snp.left).inset(10)
                make.right.equalTo(contentView.snp.right).inset(10)
                make.top.equalTo(contentView.snp.top).inset(10)
                make.bottom.equalTo(contentView.snp.bottom).inset(10)
            })
        }
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let comment = comments[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: CommentTableViewCell.reuseIdentifier, for: indexPath) as! CommentTableViewCell
        cell.selectionStyle = .none
        cell.comment = comment
        return cell
    }

commentsTableView.rowHeight = UITableViewAutomaticDimension
    commentsTableView.estimatedRowHeight = 140

0

วิธีแก้ปัญหาข้างต้นไม่ได้ผล แต่ใช้ข้อเสนอแนะต่อไปนี้

ต้องเพิ่มสิ่งต่อไปนี้ใน viewDidLoad ()

DispatchQueue.main.async {

        self.tableView.reloadData()

        self.tableView.setNeedsLayout()
        self.tableView.layoutIfNeeded()

        self.tableView.reloadData()

    }

ชุดค่าผสมข้างต้นของ reloadData, setNeedsLayout และ layoutIfNeeded ใช้งานได้ แต่ไม่ทำงานอื่น ๆ อาจเฉพาะเจาะจงกับเซลล์ในโครงการแม้ว่า และใช่ต้องเรียกใช้ reloadData สองครั้งเพื่อให้ทำงานได้

ตั้งค่าสิ่งต่อไปนี้ใน viewDidLoad ด้วย

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = MyEstimatedHeight

ใน tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath)

cell.setNeedsLayout()
cell.layoutIfNeeded() 

สิ่งที่คล้ายกันของฉันreloadData/beginUpdates/endUpdates/reloadDataก็ใช้งานได้เช่นกัน reloadData ต้องเรียกเป็นครั้งที่สอง asyncไม่จำเป็นต้องห่อไว้ใน
ray

0

ฉันวิ่งเข้าไปในปัญหานี้และคงได้โดยการย้ายรหัสเริ่มต้นมุมมอง / ฉลากของฉันจากไปtableView(willDisplay cell:)tableView(cellForRowAt:)


ซึ่งไม่ใช่วิธีที่แนะนำในการเริ่มต้นเซลล์ จะมีประสิทธิภาพดีกว่าwillDisplay cellForRowAtใช้ช่องสุดท้ายเท่านั้นเพื่อสร้างเซลล์ที่ถูกต้อง
Martin

2 ปีหลังจากนั้นฉันอ่านความคิดเห็นเก่า ๆ ที่ฉันเขียนลงไป นี่เป็นคำแนะนำที่ไม่ดี แม้ว่าจะwillDisplayมีประสิทธิภาพที่ดีขึ้นขอแนะนำให้ iS เริ่มต้น UI ของเซลล์ของคุณcellForRowAtเมื่อเค้าโครงเป็นแบบอัตโนมัติ อันที่จริงเลย์เอาต์คำนวณโดย UIKit หลัง cellForRowAt และก่อน willDisplay ดังนั้นถ้าความสูงของเซลล์ของคุณขึ้นอยู่กับเนื้อหาเริ่มต้นเนื้อหาฉลาก (หรืออะไรก็ตาม) cellForRowAtใน
Martin

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


//  call the method dynamiclabelHeightForText
}

ใช้วิธีการข้างต้นซึ่งส่งกลับความสูงของแถวแบบไดนามิก และกำหนดความสูงแบบไดนามิกเดียวกันให้กับฉลากที่คุณใช้

-(int)dynamiclabelHeightForText:(NSString *)text :(int)width :(UIFont *)font
{

    CGSize maximumLabelSize = CGSizeMake(width,2500);

    CGSize expectedLabelSize = [text sizeWithFont:font
                                constrainedToSize:maximumLabelSize
                                    lineBreakMode:NSLineBreakByWordWrapping];


    return expectedLabelSize.height;


}

รหัสนี้ช่วยคุณค้นหาความสูงแบบไดนามิกสำหรับข้อความที่แสดงในป้ายกำกับ


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