【问题标题】:View height constraints are not set correctly as I scroll UICollectionView up and down当我上下滚动 UICollectionView 时,视图高度约束设置不正确
【发布时间】:2020-02-23 02:28:27
【问题描述】:

我正在尝试根据模型属性来确定视图高度,但是当 UICollectionView 上下滚动时,不正确的高度分配给可见单元格。似乎在GetCell(即cellForItemAtIndexPath)中设置HeightAnchor 不起作用。我怎样才能做到这一点?

using CoreGraphics;
using Foundation;
using System;
using System.Collections.Generic;
using UIKit;

namespace App2
{
    public partial class ViewController : UIViewController
    {
        private UICollectionView _collectionView;

        public ViewController (IntPtr handle) : base (handle)
        {
        }

        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            InitializeCollectionView();
        }

        private void InitializeCollectionView()
        {
            _collectionView = new UICollectionView(View.Frame, new UICollectionViewCompositionalLayout(GetSection()))
            {
                DataSource = new CustomUICollectionViewDataSource(),
                TranslatesAutoresizingMaskIntoConstraints = false
            };

            _collectionView.RegisterClassForCell(typeof(CustomUICollectionViewCell), "CustomUICollectionViewCell");

            View.AddSubview(_collectionView);

            NSLayoutConstraint.ActivateConstraints(new[]
            {
                _collectionView.TopAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.TopAnchor),
                _collectionView.BottomAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.BottomAnchor),
                _collectionView.LeftAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.LeftAnchor),
                _collectionView.RightAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.RightAnchor)
            });
        }

        private static NSCollectionLayoutSection GetSection()
        {
            var size = NSCollectionLayoutSize.Create(NSCollectionLayoutDimension.CreateFractionalWidth(1), NSCollectionLayoutDimension.CreateEstimated(50));
            var item = NSCollectionLayoutItem.Create(size);
            var group = NSCollectionLayoutGroup.CreateHorizontal(layoutSize: size, subitem: item, count: 1);
            var section = NSCollectionLayoutSection.Create(group);

            section.InterGroupSpacing = 5;

            return section;
        }
    }

    public class CustomUICollectionViewDataSource : UICollectionViewDataSource
    {
        private readonly List<Model> _models = new List<Model>
        {
            new Model {Height = 250},
            new Model {Height = 100},
            new Model {Height = 300},
            new Model {Height = 400},
            new Model {Height = 500},
            new Model {Height = 50},
            new Model {Height = 230},
            new Model {Height = 100},
            new Model {Height = 600},
            new Model {Height = 310},
            new Model {Height = 150},
            new Model {Height = 220}
        };

        public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
        {
            var model = _models[(int)indexPath.Item];

            var cell = collectionView.DequeueReusableCell("CustomUICollectionViewCell", indexPath) as CustomUICollectionViewCell;

            cell.UpdateHeight(model.Height);

            return cell;
        }

        public override nint GetItemsCount(UICollectionView collectionView, nint section)
        {
            return _models.Count;
        }
    }

    public sealed class CustomUICollectionViewCell : UICollectionViewCell
    {
        private readonly UIView _uiView;

        [Export("initWithFrame:")]
        public CustomUICollectionViewCell(CGRect frame) : base(frame)
        {
            _uiView = new UIView
            {
                BackgroundColor = UIColor.Brown,
                TranslatesAutoresizingMaskIntoConstraints = false
            };

            ContentView.AddSubview(_uiView);

            NSLayoutConstraint.ActivateConstraints(new[]
            {
                _uiView.TopAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.TopAnchor),
                _uiView.BottomAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.BottomAnchor),
                _uiView.LeftAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.LeftAnchor),
                _uiView.RightAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.RightAnchor)
            });
        }

        public void UpdateHeight(int height)
        {
            _uiView.HeightAnchor.ConstraintEqualTo(height).Active = true;
        }
    }

    public class Model
    {
        public int Height { get; set; }
    }
}

【问题讨论】:

    标签: ios xamarin uicollectionview autolayout uicollectionviewcell


    【解决方案1】:

    这是Xamarin support 推荐的解决方法:

    NSLayoutConstraint heightConstraint;
    public void UpdateHeight(int height)
    {
        if (heightConstraint == null)
        {
            heightConstraint = _uiView.HeightAnchor.ConstraintEqualTo(height);
            heightConstraint.Active = true;
        }
        else
        {
            heightConstraint.Constant = height;
        }
    }
    

    【讨论】:

    • sizeForItemAt 只适用于UICollectionViewFlowLayout,所以它绝对不适用于UICollectionViewCompositionalLayout
    【解决方案2】:

    如果您这样做,打印消息会提示您重复约束。

    您设置了left, right, bottom, top的约束,并在更新时添加了height约束。前四个约束已经确定了最终高度,这里的新高度不起作用,会打印警告信息。

    如果真的要更新高度,应该从头设置left, right, top, height约束,并保存更新时使用的height约束。

    var heightConstraint: NSLayoutConstraint?
    
    heightConstraint = _uiView.heightAnchor.constraint(equalToConstant: 50)//Defaults
    NSLayoutConstraint.activate([
    
    (_uiView.topAnchor.constraint(equalTo:ContentView.SafeAreaLayoutGuide.topAnchor))!,                
    (_uiView.leftAnchor.constraint(equalTo:ContentView.SafeAreaLayoutGuide.leftAnchor))!
    (_uiView.rightAnchor.constraint(equalTo:ContentView.SafeAreaLayoutGuide.rightAnchor))!,
    (heightConstraint)!
    ]);
    
    
    public void UpdateHeight(int height){
        heightConstraint?.isActive = false
        heightConstraint = _uiView.heightAnchor.constraint(equalToConstant: height)
        heightConstraint?.isActive = true
    }
    

    【讨论】:

    • 很遗憾,这个建议没有奏效。我移除了底部锚点并为高度约束创建了一个类成员。我按照您的建议在UpdateHeight 中更新了它。我看不到任何InterGroupSpacing,整个屏幕看起来都是棕色的。
    • 在更新之前,可见单元格在第一次显示集合视图时呈现良好。滚动时高度不正常。
    • 之所以这样是因为item的高度是固定的,可以动态改变内部视图的高度,很有可能会超出。也许您应该考虑动态设置item 的高度,而不是更改内部视图的高度。
    • item,你的意思是ContentView吗?我将_uiView 从其子视图中删除,并直接在ContentView 上设置高度约束。什么都没有。
    • UICollectionViewDelegateFlowLayoutfunc collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -&gt; CGSize的方法控制每个UICollectionViewCell的大小
    猜你喜欢
    • 2015-08-30
    • 2019-02-19
    • 2021-05-13
    • 2018-01-10
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    • 2021-10-28
    相关资源
    最近更新 更多