programing

콘텐츠에 맞게 UITableView 크기 조정

sourcejob 2023. 4. 19. 22:58
반응형

콘텐츠에 맞게 UITableView 크기 조정

나는 질문이 있는 앱을 만들고 있다.UILabel 답안지에는 객관식 이 나와 .UITableView행. , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .에 저는 이게 요.UITableView이치노

는 ㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇ를 찾고 요.sizeToFit되어 있는 테이블의 프레임이 모든 컨텐츠의 높이로 설정됩니다.

제가 이걸 어떻게 할 수 있는지 조언해 주실 수 있나요?

KVO, Dispatch Queue 또는 제약조건을 직접 설정하지 않는 Swift 5 및 4.2 솔루션.

해결책은 Gulz의 대답에 기초하고 있다.

1) 서브스를 1 1 of 1 1 of of 。UITableView:

import UIKit

final class ContentSizedTableView: UITableView {
    override var contentSize:CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

a를 붙입니다.UITableView레이아웃에 맞추어 모든 면에 구속조건을 설정합니다.를 래클를 of of of set 、 set set set set 。ContentSizedTableView.

우리 때문에 입니다. 3) Storyboard는 우리 서브클래스를 받지 않습니다.intrinsicContentSize값으로 할 수 .크기 검사기를 열고 intrentContentSize를 자리 표시자 값으로 재정의하여 이 문제를 해결합니다.이치노 시, 실실 in in 、 in in in in in in in in の합니다.ContentSizedTableView 표시


업데이트: Swift 4.2의 코드가 변경되었습니다.이전 버전을 사용하는 경우UIViewNoIntrinsicMetricUIView.noIntrinsicMetric

사실 제가 직접 답을 찾았어요.

는 그냥 냥냥 a a a a a를 .CGRect★★★★★★★★★★★★★★★★의 경우tableView.frameheight- 아, 아, 아, 아! - 아, 아, 아!table.contentSize.height

하면 높이가 .UITableViewheight그 내용에 대해서요.코드는 UI를 수정하므로 메인 스레드에서 실행하는 것을 잊지 마십시오.

dispatch_async(dispatch_get_main_queue(), ^{
        //This code will run in the main thread:
        CGRect frame = self.tableView.frame;
        frame.size.height = self.tableView.contentSize.height;
        self.tableView.frame = frame;
    });

신속한 솔루션

다음의 순서에 따릅니다.

  1. 스토리보드에서 테이블의 높이 제한을 설정합니다.

  2. @IBOutlet뷰 컨트롤러 파일에 저장해야 합니다.

    @IBOutlet var tableHeight: NSLayoutConstraint!
    
  3. 그런 다음 다음 다음 코드를 사용하여 테이블의 높이를 동적으로 변경할 수 있습니다.

    override func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.tableHeight?.constant = self.table.contentSize.height
    }
    

, " " " 를 .viewWillLayoutSubviews()willDisplay cell★★★★

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.viewWillLayoutSubviews()
}

iOS 7에서 사용해 봤는데 효과가 있었어요.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}

테이블 뷰에서 contentSize 속성의 옵서버를 추가하고 그에 따라 프레임 크기를 조정합니다.

[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];

콜백에서 다음을 수행합니다.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
         CGRect frame = your_tableview.frame;
         frame.size = your_tableview.contentSize;
         your_tableview.frame = frame;
    }

이게 도움이 되길 바라.

스크롤 뷰 내에 테이블 뷰가 있어서 table View의 높이를 계산하고 그에 따라 크기를 조정해야 했습니다.다음은 제가 취한 조치입니다.

0) 스크롤 뷰에 UIView를 추가합니다(아마 이 절차 없이도 작동하지만 발생할 수 있는 충돌을 피하기 위해 이 작업을 수행했습니다). 이것은 테이블 뷰의 컨테이너 뷰가 됩니다.이 단계를 수행할 경우 뷰 경계선을 테이블 뷰 경계선으로 설정합니다.

1) UITableView 서브클래스를 만듭니다.

class IntrinsicTableView: UITableView {

    override var contentSize:CGSize {
        didSet {
            self.invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        self.layoutIfNeeded()
        return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
    }

}

2) Storyboard의 테이블 뷰 클래스를 IntelligentTableView: 스크린샷: http://joxi.ru/a2XEENpsyBWq0A로 설정합니다.

3) heightConstraint를 테이블 뷰로 설정합니다.

4) 테이블의 IBoutlet을 View Controller로 드래그합니다.

5) 테이블 높이 제약의 IBoutlet을 View Controller로 드래그합니다.

6) 이 메서드를 View Controller에 추가합니다.

override func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height
    }

도움이 되었으면 좋겠다

Swift 5 솔루션

다음의 4개의 순서를 실행합니다.

  1. 스토리보드에서 테이블 뷰의 높이 제한을 설정합니다.

  2. @IBOutlet뷰 컨트롤러 파일에 저장해야 합니다.

    @IBOutlet var tableViewHeightConstraint: NSLayoutConstraint!
    
  3. 합니다.override func viewDidLoad()

override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
 
    }

  1. 그런 다음 다음 다음 코드를 사용하여 테이블의 높이를 동적으로 변경할 수 있습니다.

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
         if(keyPath == "contentSize"){
             if let newvalue = change?[.newKey]
             {
                 DispatchQueue.main.async {
                 let newsize  = newvalue as! CGSize
                 self.tableViewHeightConstraint.constant = newsize.height
                 }
    
             }
         }
     }
    

테이블 보기의 내용 크기 변경을 추적하지 않으려는 경우 이 하위 클래스가 유용할 수 있습니다.

protocol ContentFittingTableViewDelegate: UITableViewDelegate {
    func tableViewDidUpdateContentSize(_ tableView: UITableView)
}

class ContentFittingTableView: UITableView {

    override var contentSize: CGSize {
        didSet {
            if !constraints.isEmpty {
                invalidateIntrinsicContentSize()
            } else {
                sizeToFit()
            }

            if contentSize != oldValue {
                if let delegate = delegate as? ContentFittingTableViewDelegate {
                    delegate.tableViewDidUpdateContentSize(self)
                }
            }
        }
    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        return contentSize
    }
}

content Size가 올바르지 않은 경우 이는 content Size가 estimated Row를 기반으로 하기 때문입니다.높이(자동), 전에 사용

tableView.estimatedRow높이 = 0;

출처 : https://forums.developer.apple.com/thread/81895

조금 다른 방법으로 했습니다만, 사실 제 TableView는 스크롤 뷰 안쪽에 있어서 높이 제한을 0으로 해야 했습니다.

그리고 런타임에 다음과 같이 변경했습니다.

       func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            self.viewWillLayoutSubviews()
       }
    
       override func viewWillLayoutSubviews() {
            super.updateViewConstraints()
             DispatchQueue.main.async {
               self.tableViewHeightConstraint?.constant = self.myTableView.contentSize.height
               self.view.layoutIfNeeded()
          }
       }

Swift 3, iOS 10.3

해결책 1: 그냥 넣어주세요self.tableview.sizeToFit()cellForRowAt indexPath make. 뷰 높이를 해 주세요.테이블 뷰 높이를 필요한 것보다 높게 설정하십시오.테이블 뷰 아래에 뷰가 없는 경우 이 솔루션이 좋습니다. 아래 ).

예:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell {
        cell.configureCell(data: testArray[indexPath.row])
        self.postsTableView.sizeToFit()
        return cell
    }

    return UITableViewCell()
}

해결책 2: 스토리보드에서 테이블 뷰 높이 제한을 설정하고 View Controller로 드래그합니다.셀의 평균 높이를 알고 배열에 포함된 요소의 수를 알고 있다면 다음과 같은 작업을 수행할 수 있습니다.

tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0     // Let's say 90 is the average cell height

*편집:

모든 솔루션을 시도해 본 결과, 모든 솔루션이 완전히 수정되지는 않았지만, 이것이 이 문제를 설명하고 완전히 수정하는 해답입니다.

이것은 섹션이 1개뿐인 테이블 뷰와 함께 자동 레이아웃을 사용할 때 사용할 수 있습니다.

func getTableViewContentHeight(tableView: UITableView) -> CGFloat {
        tableView.bounds = CGRect(x: 0, y: 0, width: 300, height: 40)
        let rows = tableView.numberOfRows(inSection: 0)
        var height = CGFloat(0)
        for n in 0...rows - 1 {
            height = height + tableView.rectForRow(at: IndexPath(row: n, section: 0)).height
        }
        return height
    }

자동 레이아웃을 설정할 때 이 기능을 호출합니다(여기 샘플은 SnapKit를 사용하지만, 이해하실 수 있습니다).

    let height = getTableViewContentHeight(tableView: myTableView)
    myTableView.snp.makeConstraints {
        ...
        ...
        $0.height.equalTo(height)
    }

UITableView의 높이는 셀을 합친 높이만큼만 하고 셀을 루프하여 셀의 총 높이를 누적합니다.이 시점에서 테이블뷰의 사이즈는 CGRect.zero이므로 셀에 의해 정의된 Auto Layout 규칙을 준수할 수 있도록 경계를 설정해야 합니다.크기를 충분히 큰 임의의 값으로 설정합니다.실제 크기는 나중에 자동 레이아웃 시스템에 의해 계산됩니다.

AutoLayout을 사용하는 경우 높이를 결정하는 구속조건을 변경하는 훨씬 더 좋은 방법이 있습니다.표 내용의 높이를 계산한 후 구속조건을 찾아 변경하기만 하면 됩니다.다음은 예를 제시하겠습니다(테이블 높이를 결정하는 구속조건이 실제로는 "동일한" 관계인 높이 구속조건이라고 가정함).

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    for constraint in tableView.constraints {
        if constraint.firstItem as? UITableView == tableView {
            if constraint.firstAttribute == .height {
                constraint.constant = tableView.contentSize.height
            }
        }
    }
}

에 기반을 둔 fl034의 답변

스위치 5

var tableViewHeight: NSLayoutConstraint?

    tableViewHeight = NSLayoutConstraint(item: servicesTableView, 
    attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,
    multiplier: 0.0, constant: 10)
    tableViewHeight?.isActive = true


  func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    tableViewHeight?.constant = tableView.contentSize.height
    tableView.layoutIfNeeded()
}

Mimo의 답변Anoj VM의 답변은 모두 훌륭하지만, 리스트가 클 경우 프레임의 높이로 인해 일부 셀이 절단될 수 있습니다.

그래서 답을 조금 수정했습니다.

dispatch_async(dispatch_get_main_queue()) {
    //This code will run in the main thread:
    CGFloat newHeight=self.tableView.contentSize.height;
    CGFloat screenHeightPermissible=(self.view.bounds.size.height-self.tableView.frame.origin.y);
    if (newHeight>screenHeightPermissible)
    {
        //so that table view remains scrollable when 'newHeight'  exceeds the screen bounds
        newHeight=screenHeightPermissible;
    }

    CGRect frame = self.tableView.frame;
    frame.size.height = newHeight;
    self.tableView.frame = frame;
}

Swift 5 구현에서는 tableView의 높은 구속조건을 콘텐츠 크기로 설정합니다(contentSize.height). 이 방법에서는 자동 레이아웃을 사용하고 있는 것을 전제로 하고 있습니다.이 코드는 tableView 메서드 내에 배치해야 합니다.

tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height).isActive = true

저 같은 경우에는 테이블 뷰의 높이를 일정하게 설정해 주세요.테이블 뷰 높이의 아웃렛을 만들고 테이블을 다시 볼 때마다 다음 함수를 호출합니다.View

private func manageHeight(){
        tableViewHeight.constant=CGFloat.greatestFiniteMagnitude
        tableView.reloadData()
        tableView.layoutIfNeeded()
        tableViewHeight.constant=tableView.contentSize.height
    }

주의: tableView는 테이블 뷰와 테이블 뷰의 아웃렛입니다.높이는 tableView높이의 출구입니다.

Anoj VM의 답변의 연장선상에서 콘텐츠 사이즈가 변경되었을 때만 갱신하는 것을 다음과 같이 제안합니다.

, 이 어프로치에서는, 스크롤이 올바르게 무효가 되어, 보다리스트회전이 서포트됩니다.메인 스레드에서 contentSize 변경이 디스패치되므로 dispatch_async를 사용할 필요가 없습니다.

- (void)viewDidLoad {
        [super viewDidLoad];
        [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; 
}


- (void)resizeTableAccordingToContentSize:(CGSize)newContentSize {
        CGRect superviewTableFrame  = self.tableView.superview.bounds;
        CGRect tableFrame = self.tableView.frame;
        BOOL shouldScroll = newContentSize.height > superviewTableFrame.size.height;
        tableFrame.size = shouldScroll ? superviewTableFrame.size : newContentSize;
        [UIView animateWithDuration:0.3
                                    delay:0
                                    options:UIViewAnimationOptionCurveLinear
                                    animations:^{
                            self.tableView.frame = tableFrame;
        } completion: nil];
        self.tableView.scrollEnabled = shouldScroll;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([change[NSKeyValueChangeKindKey] unsignedIntValue] == NSKeyValueChangeSetting &&
        [keyPath isEqualToString:@"contentSize"] &&
        !CGSizeEqualToSize([change[NSKeyValueChangeOldKey] CGSizeValue], [change[NSKeyValueChangeNewKey] CGSizeValue])) {
        [self resizeTableAccordingToContentSize:[change[NSKeyValueChangeNewKey] CGSizeValue]];
    } 
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    [self resizeTableAccordingToContentSize:self.tableView.contentSize]; }

- (void)dealloc {
    [self.tableView removeObserver:self forKeyPath:@"contentSize"];
}

무사 알마트리 objc판

(void)viewWillLayoutSubviews
{
    [super updateViewConstraints];
    CGFloat desiredHeight = self.tableView.contentSize.height;
    // clamp desired height, if needed, and, in that case, leave scroll Enabled
    self.tableHeight.constant = desiredHeight;
    self.tableView.scrollEnabled = NO;
}

이 커스텀을 사용해 볼 수 있습니다.AGTableView

TableView높이 제한을 설정하려면 스토리보드를 사용하거나 프로그래밍 방식으로 설정합니다(이 클래스는 높이 제한을 자동으로 가져와 컨텐츠 뷰 높이를 테이블 뷰 높이로 설정합니다).

class AGTableView: UITableView {

    fileprivate var heightConstraint: NSLayoutConstraint!

    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        self.associateConstraints()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.associateConstraints()
    }

    override open func layoutSubviews() {
        super.layoutSubviews()

        if self.heightConstraint != nil {
            self.heightConstraint.constant = self.contentSize.height
        }
        else{
            self.sizeToFit()
            print("Set a heightConstraint to Resizing UITableView to fit content")
        }
    }

    func associateConstraints() {
        // iterate through height constraints and identify

        for constraint: NSLayoutConstraint in constraints {
            if constraint.firstAttribute == .height {
                if constraint.relation == .equal {
                    heightConstraint = constraint
                }
            }
        }
    }
}

주의: 높이 설정에 문제가 있는 경우yourTableView.layoutSubviews()

fl034의 답변에 근거합니다.하지만 Xamarin.i는OS 사용자:

    [Register("ContentSizedTableView")]
    public class ContentSizedTableView : UITableView
    {
        public ContentSizedTableView(IntPtr handle) : base(handle)
        {
        }

        public override CGSize ContentSize { get => base.ContentSize; set { base.ContentSize = value; InvalidateIntrinsicContentSize(); } }
        public override CGSize IntrinsicContentSize
        {
            get
            {
                this.LayoutIfNeeded();
                return new CGSize(width: NoIntrinsicMetric, height: ContentSize.Height);
            }
        }
    }

UIView 확장을 사용하고 있습니다.위의 @CrisB 접근법에 가깝습니다.

 extension UIView {
func updateHeight(_ height:NSLayoutConstraint)
{
    
    let newSize = CGSize(width: self.frame.size.width, height: CGFloat(MAXFLOAT))
    let fitSize : CGSize = self.sizeThatFits(newSize)
    
    height.constant = fitSize.height
    
   
}
}

실장:

@IBOutlet weak var myTableView: UITableView!
@IBOutlet weak var myTableVieweHeight: NSLayoutConstraint!
//(call it whenever tableView is updated inside/outside delegate methods)
myTableView.updateHeight(myTableVieweHeigh)

보너스 : 기타 모든 UIView에서 사용할 수 있습니다(예: 사용자 고유의 다이내믹 라벨).

테이블을 역동적으로 만들려면 위에서 설명한 표의 내용을 기반으로 한 솔루션을 사용해야 합니다.단순히 작은 테이블을 표시하는 경우 컨테이너 뷰를 사용하여 UITableViewController를 내장할 수 있습니다.UITableView는 컨테이너 크기에 따라 크기가 조정됩니다.

이것에 의해, 많은 계산이나 레이아웃 호출이 불필요하게 됩니다.

이를 위한 Mu solution in swift 3: 에서 이 메서드를 호출합니다.viewDidAppear

func UITableView_Auto_Height(_ t : UITableView)
{
        var frame: CGRect = t.frame;
        frame.size.height = t.contentSize.height;
        t.frame = frame;        
}

언급URL : https://stackoverflow.com/questions/2595118/resizing-uitableview-to-fit-content

반응형