に質問UILabel
が表示されUITableView
、各行に複数の選択肢が表示される複数の選択肢の回答が表示されるアプリを作成しています。質問と回答はさまざまですので、これはUITableView
動的に変化する必要があります。
sizeToFit
テーブルの回避策を見つけたいのですが。テーブルのフレームがすべてのコンテンツの高さに設定されている場所。
誰でも私がこれを達成する方法についてアドバイスできますか?
- sizeToFit
メソッドを試したことはありますか?
に質問UILabel
が表示されUITableView
、各行に複数の選択肢が表示される複数の選択肢の回答が表示されるアプリを作成しています。質問と回答はさまざまですので、これはUITableView
動的に変化する必要があります。
sizeToFit
テーブルの回避策を見つけたいのですが。テーブルのフレームがすべてのコンテンツの高さに設定されている場所。
誰でも私がこれを達成する方法についてアドバイスできますか?
- sizeToFit
メソッドを試したことはありますか?
回答:
実際に自分で答えを見つけました。
私はちょうど新しいを作成するCGRect
ためtableView.frame
とheight
のtable.contentSize.height
それはの高さを設定UITableView
しheight
、そのコンテンツの。コードによって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;
});
KVO、DispatchQueue、または制約を自分で設定しないSwift 5および4.2ソリューション。
1)のサブクラスを作成します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)
}
}
2)をUITableView
レイアウトに追加し、すべての側に制約を設定します。そのクラスをに設定しContentSizedTableView
ます。
3)StoryboardはサブクラスintrinsicContentSize
を考慮していないため、いくつかのエラーが表示されます。これを修正するには、サイズインスペクターを開き、intrinsicContentSizeをプレースホルダー値にオーバーライドします。これは設計時のオーバーライドです。実行時には、ContentSizedTableView
クラスのオーバーライドを使用します
更新: Swift 4.2のコードが変更されました。以前のバージョンを使用している場合は、UIViewNoIntrinsicMetric
代わりにUIView.noIntrinsicMetric
tableView
があり IntrinsicTableView
ました。テーブルビューを別のに埋め込む必要はありませんでしたUIView
。
tableView
にIntrinsicTableView
。また、追加のラッピングUIView
は必要ありません。もちろん、既存の親ビューを使用できます:)
tableView.sizeToFit()
sizeToFit()
呼び出す必要のある場所を
Swiftソリューション
次の手順を実行します:
1-ストーリーボードからテーブルの高さの制約を設定します。
2-ストーリーボードから高さ制約をドラッグし、ビューコントローラーファイルにそのための@IBOutletを作成します。
@IBOutlet weak var tableHeight: NSLayoutConstraint!
3-次に、次のコードを使用してテーブルの高さを動的に変更できます。
override func viewWillLayoutSubviews() {
super.updateViewConstraints()
self.tableHeight?.constant = self.table.contentSize.height
}
更新
最後の行が切り取られた場合は、willDisplayセル関数でviewWillLayoutSubviews()を呼び出してみてください。
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;
}
これがお役に立てば幸いです。
スクロールビュー内にテーブルビューがあり、それに応じてtableViewの高さを計算してサイズを変更する必要がありました。これらは私が取ったステップです:
0)UIViewをscrollViewに追加します(おそらく、この手順がなくても機能しますが、競合を回避するために行いました)-これは、テーブルビューのコンテナービューになります。この手順を実行する場合は、ビューの境界をtableviewのものに設定します。
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のテーブルビューのクラスをIntrinsicTableViewに設定:スクリーンショット:http : //joxi.ru/a2XEENpsyBWq0A
3)heightConstraintをテーブルビューに設定します。
4)テーブルのIBoutletをViewControllerにドラッグします
5)テーブルの高さ制約のIBoutletをViewControllerにドラッグします
6)このメソッドをViewControllerに追加します。
override func viewWillLayoutSubviews() {
super.updateViewConstraints()
self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.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
}
}
override public var intrinsicContentSize: CGSize { //... return someCGSize }
contentSizeが正しくない場合は、推定されたRowHeight(自動)に基づいているためです。
tableView.estimatedRowHeight = 0;
Swift 3、iOS 10.3
解決方法1:
だけは入れself.tableview.sizeToFit()
でcellForRowAt indexPath
機能。テーブルビューの高さを必要以上に高く設定してください。これは、tableviewの下にビューがない場合に適したソリューションです。ただし、使用している場合、下部のテーブルビュー制約は更新されません(解決策2を考え出したため、修正しようとしませんでした)。
例:
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: ストーリーボードでテーブルビューの高さの制約を設定し、それをViewControllerにドラッグします。セルの平均の高さがわかっていて、配列に含まれる要素の数がわかっている場合は、次のようなことができます。
tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0 // Let's say 90 is the average cell height
*編集:
私が試したすべてのソリューションの後、それらのすべてが何かを修正していましたが、完全ではありませんでしたが、これがこの問題を完全に説明して修正する答えです。
Mimoの回答とAnooj 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;
}
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
}
}
}
}
myTableHeightConstraint.constant = tableView.contentSize.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なので、セルで定義された自動レイアウトルールを尊重できるように境界を設定する必要があります。サイズは、十分に大きい任意の値に設定します。実際のサイズは、自動レイアウトシステムによって後で計算されます。
私は少し違った方法で行いました。実際、私のTableViewはscrollview内にあったため、高さの制約を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()
}
}
Anooj 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"];
}
Musa almatriの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.iOSユーザーの場合:
[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);
}
}
}
私のSwift 5の実装では、tableViewの高さ制約をコンテンツのサイズ(contentSize.height
)に設定しています。この方法は、自動レイアウトを使用していることを前提としています。このコードは、cellForRowAt
tableViewメソッド内に配置する必要があります。
tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height).isActive = true
テーブルを動的にする場合は、上記のようにテーブルの内容に基づいたソリューションを使用する必要があります。小さなテーブルを表示したいだけの場合は、コンテナービューを使用してUITableViewControllerを埋め込むことができます。UITableViewはコンテナーのサイズに従ってサイズ変更されます。
これにより、多くの計算とレイアウトの呼び出しが回避されます。
above
答えがシャッフルされる可能性があるため、言葉は使用しないでください。