มีวิธีUIScrollView
ปรับอัตโนมัติตามความสูง (หรือความกว้าง) ของเนื้อหาที่กำลังเลื่อนหรือไม่
สิ่งที่ต้องการ:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
มีวิธีUIScrollView
ปรับอัตโนมัติตามความสูง (หรือความกว้าง) ของเนื้อหาที่กำลังเลื่อนหรือไม่
สิ่งที่ต้องการ:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
คำตอบ:
วิธีที่ดีที่สุดที่ฉันเคยพบในการอัปเดตขนาดเนื้อหาUIScrollView
ตามมุมมองย่อยที่มีอยู่:
Objective-C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
รวดเร็ว
let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in
rect = rect.union(view.frame)
}
scrollView.contentSize = contentRect.size
UIScrollView ไม่ทราบความสูงของเนื้อหาโดยอัตโนมัติ คุณต้องคำนวณความสูงและความกว้างด้วยตัวคุณเอง
ทำด้วยสิ่งที่ชอบ
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
แต่จะใช้ได้ผลก็ต่อเมื่อมุมมองอยู่ด้านล่างมุมมองอื่น ๆ หากคุณมีมุมมองที่อยู่ติดกันคุณจะต้องเพิ่มความสูงเพียงครั้งเดียวหากคุณไม่ต้องการตั้งค่าเนื้อหาของตัวเลื่อนให้ใหญ่กว่าที่เป็นจริง
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
ตั้งค่าtranslatesAutoresizingMaskIntoConstraints
เป็นNO
มุมมองทั้งหมดที่เกี่ยวข้อง
จัดตำแหน่งและขนาดมุมมองเลื่อนของคุณโดยมีข้อ จำกัด ภายนอกมุมมองเลื่อน
ใช้ข้อ จำกัด ในการจัดวางมุมมองย่อยภายในมุมมองแบบเลื่อนตรวจสอบให้แน่ใจว่าข้อ จำกัด นั้นผูกกับขอบทั้งสี่ของมุมมองเลื่อนและไม่ต้องพึ่งพามุมมองแบบเลื่อนเพื่อให้ได้ขนาด
ที่มา: https://developer.apple.com/library/ios/technotes/tn2154/_index.html
ฉันเพิ่มสิ่งนี้ในคำตอบของ Espuz และ JCC ใช้ตำแหน่ง y ของมุมมองย่อยและไม่รวมแถบเลื่อน แก้ไขใช้ด้านล่างของมุมมองย่อยที่ต่ำที่สุดที่มองเห็นได้
+ (CGFloat) bottomOfLowestContent:(UIView*) view
{
CGFloat lowestPoint = 0.0;
BOOL restoreHorizontal = NO;
BOOL restoreVertical = NO;
if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
{
if ([(UIScrollView*)view showsHorizontalScrollIndicator])
{
restoreHorizontal = YES;
[(UIScrollView*)view setShowsHorizontalScrollIndicator:NO];
}
if ([(UIScrollView*)view showsVerticalScrollIndicator])
{
restoreVertical = YES;
[(UIScrollView*)view setShowsVerticalScrollIndicator:NO];
}
}
for (UIView *subView in view.subviews)
{
if (!subView.hidden)
{
CGFloat maxY = CGRectGetMaxY(subView.frame);
if (maxY > lowestPoint)
{
lowestPoint = maxY;
}
}
}
if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
{
if (restoreHorizontal)
{
[(UIScrollView*)view setShowsHorizontalScrollIndicator:YES];
}
if (restoreVertical)
{
[(UIScrollView*)view setShowsVerticalScrollIndicator:YES];
}
}
return lowestPoint;
}
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
ในตอนต้นและself.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
ตอนท้ายของวิธีการ?
นี่คือคำตอบที่ได้รับการยอมรับอย่างรวดเร็วสำหรับทุกคนที่ขี้เกียจแปลง :)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
นี่คือการปรับใช้ Swift 3 ของคำตอบของ @ leviatan:
ส่วนขยาย
import UIKit
extension UIScrollView {
func resizeScrollViewContentSize() {
var contentRect = CGRect.zero
for view in self.subviews {
contentRect = contentRect.union(view.frame)
}
self.contentSize = contentRect.size
}
}
การใช้งาน
scrollView.resizeScrollViewContentSize()
ใช้งานง่ายมาก!
ต่อไปนี้ส่วนขยายจะเป็นประโยชน์ในการสวิฟท์
extension UIScrollView{
func setContentViewSize(offset:CGFloat = 0.0) {
// dont show scroll indicators
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
var maxHeight : CGFloat = 0
for view in subviews {
if view.isHidden {
continue
}
let newHeight = view.frame.origin.y + view.frame.height
if newHeight > maxHeight {
maxHeight = newHeight
}
}
// set content size
contentSize = CGSize(width: contentSize.width, height: maxHeight + offset)
// show scroll indicators
showsHorizontalScrollIndicator = true
showsVerticalScrollIndicator = true
}
}
ตรรกะเหมือนกันกับคำตอบที่ระบุ อย่างไรก็ตามจะละเว้นมุมมองที่ซ่อนอยู่ภายในUIScrollView
และการคำนวณจะดำเนินการหลังจากตั้งค่าตัวบ่งชี้การเลื่อนที่ซ่อนอยู่
นอกจากนี้ยังมีพารามิเตอร์ฟังก์ชันที่เป็นทางเลือกและคุณสามารถเพิ่มค่าออฟเซ็ตได้โดยการส่งผ่านพารามิเตอร์ไปยังฟังก์ชัน
ทางออกที่ดีและดีที่สุดจาก @leviathan เพียงแค่แปลให้รวดเร็วโดยใช้วิธี FP (การเขียนโปรแกรมเชิงฟังก์ชัน)
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
self.contentSize = self.subviews.reduce(CGRect(), { $0.union($1.frame) }).size
คุณสามารถรับความสูงของเนื้อหาภายใน UIScrollView ได้โดยคำนวณว่าเด็กคนใด "ไปถึงไกลกว่า" ในการคำนวณสิ่งนี้คุณต้องคำนึงถึงจุดเริ่มต้น Y (เริ่มต้น) และความสูงของรายการ
float maxHeight = 0;
for (UIView *child in scrollView.subviews) {
float childHeight = child.frame.origin.y + child.frame.size.height;
//if child spans more than current maxHeight then make it a new maxHeight
if (childHeight > maxHeight)
maxHeight = childHeight;
}
//set content size
[scrollView setContentSize:(CGSizeMake(320, maxHeight))];
การทำสิ่งต่างๆด้วยวิธีนี้รายการ (มุมมองย่อย) ไม่จำเป็นต้องซ้อนกันโดยตรงภายใต้รายการอื่น
ฉันคิดวิธีแก้ปัญหาอื่นโดยใช้วิธีแก้ปัญหาของ @ emenegro
NSInteger maxY = 0;
for (UIView* subview in scrollView.subviews)
{
if (CGRectGetMaxY(subview.frame) > maxY)
{
maxY = CGRectGetMaxY(subview.frame);
}
}
maxY += 10;
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, maxY)];
โดยพื้นฐานแล้วเราจะทราบว่าองค์ประกอบใดอยู่ไกลที่สุดในมุมมองและเพิ่มช่องว่าง 10px ที่ด้านล่าง
เนื่องจาก scrollView สามารถมี scrollViews อื่น ๆ หรือทรี inDepth subViews ที่แตกต่างกันการรันในเชิงลึกแบบวนซ้ำจึงเป็นที่ต้องการ
สวิฟต์ 2
extension UIScrollView {
//it will block the mainThread
func recalculateVerticalContentSize_synchronous () {
let unionCalculatedTotalRect = recursiveUnionInDepthFor(self)
self.contentSize = CGRectMake(0, 0, self.frame.width, unionCalculatedTotalRect.height).size;
}
private func recursiveUnionInDepthFor (view: UIView) -> CGRect {
var totalRect = CGRectZero
//calculate recursevly for every subView
for subView in view.subviews {
totalRect = CGRectUnion(totalRect, recursiveUnionInDepthFor(subView))
}
//return the totalCalculated for all in depth subViews.
return CGRectUnion(totalRect, view.frame)
}
}
การใช้
scrollView.recalculateVerticalContentSize_synchronous()
หรือเพียงแค่ทำ:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(ฉันเพิ่มวิธีแก้ปัญหานี้เป็นความคิดเห็นในหน้านี้หลังจากได้รับคะแนนโหวต 19 คะแนนสำหรับความคิดเห็นนี้ฉันตัดสินใจเพิ่มโซลูชันนี้เป็นคำตอบอย่างเป็นทางการเพื่อประโยชน์ของชุมชน!)
สำหรับ swift4 โดยใช้การลด:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
ขนาดขึ้นอยู่กับเนื้อหาที่โหลดภายในและตัวเลือกการตัด หากเป็นมุมมองข้อความก็ขึ้นอยู่กับการตัดข้อความจำนวนบรรทัดขนาดตัวอักษรและอื่น ๆ แทบจะเป็นไปไม่ได้เลยที่คุณจะคำนวณตัวเอง ข่าวดีก็คือมีการคำนวณหลังจากโหลดมุมมองและใน viewWillAppear ก่อนหน้านั้นจะไม่ทราบทั้งหมดและขนาดเนื้อหาจะเท่ากับขนาดเฟรม แต่ในเมธอด viewWillAppear และหลัง (เช่น viewDidAppear) ขนาดเนื้อหาจะเป็นขนาดจริง
การห่อโค้ดของ Richy ฉันสร้างคลาส UIScrollView แบบกำหนดเองที่ปรับขนาดเนื้อหาโดยอัตโนมัติ!
SBScrollView.h
@interface SBScrollView : UIScrollView
@end
SBScrollView.m:
@implementation SBScrollView
- (void) layoutSubviews
{
CGFloat scrollViewHeight = 0.0f;
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
for (UIView* view in self.subviews)
{
if (!view.hidden)
{
CGFloat y = view.frame.origin.y;
CGFloat h = view.frame.size.height;
if (y + h > scrollViewHeight)
{
scrollViewHeight = h + y;
}
}
}
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = YES;
[self setContentSize:(CGSizeMake(self.frame.size.width, scrollViewHeight))];
}
@end
วิธีใช้:
เพียงแค่นำเข้าไฟล์. h ไปยังตัวควบคุมมุมมองของคุณและประกาศอินสแตนซ์ SBScrollView แทน UIScrollView ปกติ
กำหนดขนาดเนื้อหาแบบไดนามิกเช่นนี้
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
ขึ้นอยู่กับเนื้อหาจริงๆ: content.frame.height อาจให้สิ่งที่คุณต้องการ? ขึ้นอยู่กับว่าเนื้อหาเป็นสิ่งเดียวหรือสิ่งที่รวบรวม
ฉันยังพบคำตอบของเลวีอาธานว่าทำงานได้ดีที่สุด อย่างไรก็ตามมันกำลังคำนวณความสูงแปลก ๆ เมื่อวนลูปผ่านมุมมองย่อยถ้า scrollview ถูกตั้งค่าให้แสดงตัวบ่งชี้การเลื่อนสิ่งเหล่านั้นจะอยู่ในอาร์เรย์ของมุมมองย่อย ในกรณีนี้วิธีแก้ไขคือปิดใช้งานตัวบ่งชี้การเลื่อนชั่วคราวก่อนที่จะวนซ้ำจากนั้นตั้งค่าการมองเห็นก่อนหน้านี้อีกครั้ง
-(void)adjustContentSizeToFit
เป็นวิธีการสาธารณะในคลาสย่อยที่กำหนดเองของ UIScrollView
-(void)awakeFromNib {
dispatch_async(dispatch_get_main_queue(), ^{
[self adjustContentSizeToFit];
});
}
-(void)adjustContentSizeToFit {
BOOL showsVerticalScrollIndicator = self.showsVerticalScrollIndicator;
BOOL showsHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
CGRect contentRect = CGRectZero;
for (UIView *view in self.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.contentSize = contentRect.size;
self.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
self.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
}
ฉันคิดว่านี่อาจเป็นวิธีที่เรียบร้อยในการอัปเดตขนาดมุมมองเนื้อหาของ UIScrollView
extension UIScrollView {
func updateContentViewSize() {
var newHeight: CGFloat = 0
for view in subviews {
let ref = view.frame.origin.y + view.frame.height
if ref > newHeight {
newHeight = ref
}
}
let oldSize = contentSize
let newSize = CGSize(width: oldSize.width, height: newHeight + 20)
contentSize = newSize
}
}
ทำไมไม่โค้ดบรรทัดเดียว ??
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);
import UIKit
class DynamicSizeScrollView: UIScrollView {
var maxHeight: CGFloat = UIScreen.main.bounds.size.height
var maxWidth: CGFloat = UIScreen.main.bounds.size.width
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size,self.intrinsicContentSize){
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
let height = min(contentSize.height, maxHeight)
let width = min(contentSize.height, maxWidth)
return CGSize(width: width, height: height)
}
}
viewDidLayoutSubviews
เพื่อให้การจัดวางอัตโนมัติเสร็จสิ้นใน iOS7 มันใช้งานได้ดี แต่การทดสอบระบบปฏิบัติการ iOS6 การจัดวางอัตโนมัติด้วยเหตุผลบางอย่างไม่เสร็จสิ้นการทำงานดังนั้นฉันจึงมีค่าความสูงที่ไม่ถูกต้องดังนั้นฉันจึงเปลี่ยนมาใช้viewDidAppear
ตอนนี้ได้ดี .. เพียงเพื่อชี้ให้เห็นว่าอาจมีคนต้องการสิ่งนี้ ขอบคุณ