iOS: UILabel หลายบรรทัดในเค้าโครงอัตโนมัติ


183

ฉันมีปัญหาในการพยายามที่จะบรรลุพฤติกรรมการจัดวางพื้นฐานบางอย่างกับเค้าโครงอัตโนมัติ ตัวควบคุมมุมมองของฉันมีลักษณะเช่นนี้ใน IB:

ป้อนคำอธิบายรูปภาพที่นี่

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

ฉันจะทำให้ป้ายชื่อปรับขนาดให้พอดีกับจำนวนบรรทัดที่สตริงต้องการได้อย่างไร ความเข้าใจของฉันคือฉันไม่สามารถใช้เมธอด setFrame ได้เพราะฉันใช้เลย์เอาต์อัตโนมัติ และฉันต้องใช้การจัดวางอัตโนมัติเพราะฉันต้องการมุมมองอื่น ๆ เหล่านั้นเพื่อให้อยู่ใต้ป้ายกำกับชื่อเรื่อง (ข้อ จำกัด )

ฉันจะทำให้สิ่งนี้เกิดขึ้นได้อย่างไร


3
ฉันกำลังต่อสู้กับปัญหาที่คล้ายกัน แต่ฉันยังคงดิ้นรนเพื่อให้ได้ป้ายกำกับยอดนิยมเพื่อปรับความสูงแบบไดนามิกเพื่อให้พอดีกับเนื้อหา คุณบรรลุสิ่งนี้ได้อย่างไร
jbandi

1
โปรดพิจารณาการทำเครื่องหมายคำตอบของ @ mwhuss เป็นคำตอบที่ยอมรับได้
jemmons

1
คุณบรรลุผลตามที่ต้องการหรือไม่?
Aniruddha

ตรวจสอบเรื่องนี้คุณไม่จำเป็นต้องเพิ่มบรรทัดเดียวของรหัสstackoverflow.com/a/36862795/4910767
Badal ชาห์

คำตอบ:


254

ใช้งาน-setPreferredMaxLayoutWidthบนUILabelและ autolayout ควรจัดการส่วนที่เหลือ

[label setPreferredMaxLayoutWidth:200.0];

ดูเอกสาร UILabel บน preferredMaxLayoutWidth

ปรับปรุง:

จำเป็นต้องตั้งค่าheightข้อ จำกัด ในกระดานเรื่องราวเป็นGreater than or equal toไม่จำเป็นต้อง setPreferredMaxLayoutWidth


8
เป็นเรื่องที่ดีอย่างไรก็ตามการทำเช่นนี้ในเครื่องมือสร้างอินเตอร์เฟส
Sjoerd Perfors

12
นอกจากนี้ตั้งข้อจำกัดความสูงใน IB เป็นมากกว่าหรือเท่ากับ ".
jowie

10
คำเตือน: โปรดอย่าลืมตั้งค่าคุณสมบัติ numberOfLines
Li Fumin

2
ใช่ใช้สิ่งที่คุณต้องการความกว้างสูงสุดที่จะ
mwhuss

4
ดูstackoverflow.com/a/29180323/1529675สำหรับวิธีการตรวจสอบpreferredMaxLayoutWidthและดูdevetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.htmlสำหรับการเขียนสั้น ๆ แต่มีข้อมูลพร้อมด้วย GIF เคลื่อนไหว (ไม่ใช่บทความของฉันฉันพบผ่าน Google)
tboyce12

213

ขยายจำนวนชุดป้ายกำกับของคุณเป็น 0 และที่สำคัญยิ่งกว่าสำหรับความสูงของการจัดวางเลย์เอาต์อัตโนมัติเป็น> = x เลย์เอาต์อัตโนมัติจะทำส่วนที่เหลือ นอกจากนี้คุณยังอาจมีองค์ประกอบอื่น ๆ ของคุณตามองค์ประกอบก่อนหน้าเพื่อตำแหน่งที่ถูกต้องแล้ว

เลย์เอาต์อัตโนมัติ


หากวิธีนี้ใช้ไม่ได้กับคุณโปรดดูคำตอบของ Cory Imdieke เกี่ยวกับการทำให้แน่ใจว่ามุมมองที่ตามมาไม่ได้ห้ามการจัดวางอัตโนมัติจากการปรับขนาดมุมมองหลายเส้น (อาจ)
Tom Howard

1
นี่เป็นคำตอบเดียวที่ทำงานกับฉันภายใน Table View Cell ยังทำงานร่วมกับจำนวนคงที่ของแถว (แทน 0 / ไม่ จำกัด )
bgolson

สิ่งนี้ใช้ไม่ได้สำหรับฉันด้วยชุดความกว้างสูงสุดที่ต้องการอย่างชัดเจนดังนั้นตรวจสอบให้แน่ใจว่าตั้งค่าเป็นอัตโนมัติใน IB เมื่อใช้เทคนิคนี้ ไชโย
jmc

การตั้งค่าความกว้างสูงสุดอัตโนมัติใช้ได้เฉพาะใน iOS8 นอกจากนี้จากความเข้าใจของฉันจะปรับความสูงโดยอัตโนมัติและจากประสบการณ์ของฉันคุณไม่จำเป็นต้องตั้งค่าข้อจำกัดความสูงให้ใช้งานได้ สิ่งนี้ใช้ได้สำหรับฉันโดยใช้ความกว้างที่ชัดเจน
Tony

1
สิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันเชื่อว่าstackoverflow.com/a/13032251/1529675เป็นคำตอบที่ถูกต้อง
tboyce12

48

ที่มา: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

ขนาดเนื้อหาที่แท้จริงของข้อความแบบหลายบรรทัด

ขนาดเนื้อหาภายในของ UILabel และ NSTextField นั้นไม่ชัดเจนสำหรับข้อความหลายบรรทัด ความสูงของข้อความขึ้นอยู่กับความกว้างของบรรทัดซึ่งยังไม่สามารถระบุได้เมื่อแก้ไขข้อ จำกัด เพื่อแก้ไขปัญหานี้ทั้งสองคลาสมีคุณสมบัติใหม่ที่เรียกว่า PreferredMaxLayoutWidth ซึ่งระบุความกว้างของบรรทัดสูงสุดสำหรับการคำนวณขนาดเนื้อหาที่แท้จริง

เนื่องจากปกติเราไม่ทราบค่านี้ล่วงหน้าเราจึงต้องใช้วิธีสองขั้นตอนเพื่อให้ได้สิ่งนี้ อันดับแรกเราปล่อยให้ Auto Layout ทำงานแล้วจากนั้นเราใช้เฟรมผลลัพธ์ในเค้าโครงผ่านเพื่ออัปเดตความกว้างสูงสุดที่ต้องการและเค้าโครงทริกเกอร์อีกครั้ง

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

การเรียกครั้งแรกไปที่ [super layoutSubviews] เป็นสิ่งจำเป็นสำหรับฉลากที่จะได้รับการตั้งค่าเฟรมในขณะที่การเรียกครั้งที่สองจำเป็นต้องปรับปรุงเค้าโครงหลังจากการเปลี่ยนแปลง หากเราละเว้นการโทรครั้งที่สองเราจะได้รับข้อผิดพลาด NSInternalInconsistencyException เนื่องจากเราได้ทำการเปลี่ยนแปลงในเลย์เอาต์พาสซึ่งต้องการการอัปเดตข้อ จำกัด แต่เราไม่ได้ทริกเกอร์เลย์เอาต์อีกครั้ง

เรายังสามารถทำสิ่งนี้ได้ในคลาสย่อยของเลเบลเอง:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

ในกรณีนี้เราไม่จำเป็นต้องเรียกใช้ [super layoutSubviews] ก่อนเพราะเมื่อ layoutSubviews ถูกเรียกเรามีเฟรมอยู่บนฉลากแล้ว

ในการปรับค่านี้จากระดับตัวควบคุมมุมมองเราขอเชื่อมโยงเข้ากับ viewDidLayoutSubviews ณ จุดนี้เฟรมของการผ่านเลย์เอาต์อัตโนมัติครั้งแรกได้ถูกตั้งค่าไว้แล้วและเราสามารถใช้มันเพื่อตั้งค่าความกว้างสูงสุดที่ต้องการ

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

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


ขอบคุณขอบคุณสำหรับรหัสที่ไม่เพียง แต่ที่สำคัญกว่านั้นคำอธิบายและตัวอย่างของวิธีการทำเช่นนี้ไม่เพียง แต่ในคลาสย่อย แต่ยังมาจากตัวควบคุมมุมมอง
djibouti33

ฉันพยายามทำสิ่งนี้ในตัวควบคุมมุมมองของฉันและ viewDidLayoutSubviews จะถูกเรียกหลังจาก viewWillAppear และ viewDidAppear หลังจาก viewDidAppear จะมีแฟลชเมื่อปรับขนาดป้ายกำกับอย่างถูกต้อง มีวิธีใดที่จะหลีกเลี่ยงปัญหานี้หรือไม่? มีวิธีการปรับขนาดให้เสร็จสมบูรณ์ก่อนที่ผู้ใช้จะเห็นอะไรหรือไม่? ในกรณีของฉันฉลากหลายบรรทัดของฉันอยู่ใน tableHeaderView และดังนั้นฉันจึงปรับขนาดความสูงของมุมมองส่วนหัวตามป้ายกำกับโดยใช้ตัวอย่างนี้ ( stackoverflow.com/questions/20982558/… )
djibouti33

@ djibouti33 คุณสามารถให้รหัสตัวอย่างขั้นต่ำ (เช่นในรูปแบบของ gitub repo) ดังนั้นฉันสามารถตรวจสอบปัญหาของคุณได้อย่างง่ายดาย?
Anton Matosov

ขอบคุณ @Anton การออกแบบของเราเปลี่ยนไปจาก UITableView เป็น UICollectionView และโชคดีที่ฉันไม่เห็นพฤติกรรมนี้ หากฉันได้รับประวัติคอมไพล์ของฉันเพื่อสร้างโครงการตัวอย่างขนาดเล็กฉันจะแจ้งให้คุณทราบ
djibouti33

ปัญหาสำหรับฉันตั้งแต่ฉันเริ่มทำงานบนซิม iOS 9 แต่เมื่อฉันทดสอบบน iOS 8 ปัญหาก็เริ่มต้นขึ้น ฉันต้องตั้งค่าความกว้างสูงสุดด้วยตนเอง
naz

17

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

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

วิธีง่ายๆในการบอกว่าเป็นกรณีนี้หรือไม่โดยพยายามปรับขนาดฉลากด้วยตนเอง IB ช่วยให้คุณเติบโตได้หรือไม่? หากเป็นเช่นนั้นป้ายด้านล่างจะย้ายตามที่คุณคาดหวังหรือไม่ ตรวจสอบให้แน่ใจว่าคุณได้ตรวจสอบทั้งสองอย่างนี้ก่อนที่จะปรับขนาดเพื่อดูว่าข้อ จำกัด ของคุณจะย้ายมุมมองของคุณอย่างไร:

เมนู IB

หากมุมมองค้างอยู่ให้ทำตามมุมมองที่อยู่ด้านล่างและตรวจสอบให้แน่ใจว่ามุมมองนั้นไม่มีช่องว่างด้านบนเพื่อ จำกัด การควบคุม จากนั้นตรวจสอบให้แน่ใจว่าตัวเลือกจำนวนบรรทัดสำหรับฉลากถูกตั้งไว้ที่ 0 และควรดูแลส่วนที่เหลือ


ใช่หลังจากเล่นไปกับมันฉันสามารถรับเอฟเฟกต์ที่ฉันต้องการได้ คุณแค่คิดอย่างรอบคอบเกี่ยวกับข้อ จำกัด ที่คุณต้องการ มันไม่ได้ช่วยให้ IB กำลังทำข้อ จำกัด อย่างต่อเนื่องที่คุณไม่คาดคิด
James Harpe

5

ฉันคิดว่าคุณต้องการสิ่งต่อไปนี้:

  • ข้อ จำกัด ด้านบน
  • ข้อ จำกัด ชั้นนำ (เช่นด้านซ้าย)
  • ข้อ จำกัด ต่อท้าย (เช่นด้านขวา)
  • กำหนดลำดับความสำคัญของการแฮ็กเนื้อหาแนวนอนเป็นต่ำดังนั้นมันจะเติมช่องว่างที่กำหนดหากข้อความสั้น
  • ตั้งค่าความต้านทานการบีบอัดเนื้อหาในแนวนอนเป็นต่ำดังนั้นมันจะห่อแทนที่จะพยายามให้กว้างขึ้น
  • กำหนดจำนวนบรรทัดเป็น 0
  • ตั้งค่าโหมดตัวแบ่งบรรทัดเป็นการตัดคำ

มันควรจะทำงานใน xcode9 ฉันไม่ต้องทำอะไรกับข้อจำกัดความสูงของฉลาก (ฉันไม่มีเลย): มันเพิ่งออกมาจากกล่องเมื่อเร็ว ๆ นี้เมื่อฉลากถูก จำกัด (ต่อท้าย, นำ, บนและล่าง) uikit ทำส่วนที่เหลือ
Anton Tropashko

ลำดับความสำคัญของการกอดเนื้อหาคือปัญหาของฉัน ขอบคุณที่ทำให้ฉันตระหนักถึงคุณสมบัตินั้นและความต้านทานแรงอัด คุณช่วยฉันแก้ปัญหาที่มีความยาวหลายชั่วโมง
David Gay

0

ไม่มีวิธีแก้ไขปัญหาที่แตกต่างกันที่พบในหัวข้อต่าง ๆ ในหัวข้อเรื่องทำงานได้อย่างสมบูรณ์แบบสำหรับกรณีของฉัน (x เลเบลหลายไดนามิกในเซลล์มุมมองตารางแบบไดนามิก)

ฉันพบวิธีที่จะทำ:

หลังจากตั้งค่าข้อ จำกัด บนเลเบลของคุณและตั้งค่าคุณสมบัติหลายค่าเป็น 0 ให้สร้างคลาสย่อยของ UILabel ฉันเรียกว่า AutoLayoutLabel ของฉัน:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end

0

ฉันมี UITableViewCell ซึ่งมีฉลากกำกับข้อความ ฉันทำงานการตัดข้อความดังนี้

1) ตั้งค่าข้อ จำกัด UILabel ดังนี้

ป้อนคำอธิบายรูปภาพที่นี่

2) ตั้งหมายเลข ของสายถึง 0

3) เพิ่มข้อจำกัดความสูงของ UILabel ให้กับ UITableViewCell

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) บน UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5

-12

วิธีหนึ่งในการทำเช่นนี้ ... เมื่อความยาวข้อความเพิ่มขึ้นพยายามเปลี่ยน (ลด) แบบอักษรของข้อความฉลากโดยใช้

Label.adjustsFontSizeToFitWidth = YES;

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