Xamarin iOS中如何让自定义UICollectionViewCell填充水平宽度?
Hey there! Let's get that chat message cell width sorted out for your Xamarin.iOS UI. I’ve gone through your code and spotted a few tweaks that’ll make those cells fill the horizontal space properly, plus fix the issue where your constructor settings weren’t taking effect. Here’s what to adjust:
1. Fix the Collection View Layout
Your MessageListLayout was on the right track with ShouldInvalidateLayoutForBoundsChange, but we can clean it up to ensure consistent spacing and dynamic width calculation. The reason your constructor settings didn’t stick is because when the collection view’s bounds update (like when the screen loads or rotates), the layout recalculates and overrides those initial values.
Update your MessageListLayout class like this:
public class MessageListLayout : UICollectionViewFlowLayout { public MessageListLayout() { // Set base spacing and insets once in the constructor MinimumLineSpacing = 10; MinimumInteritemSpacing = 10; SectionInset = new UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10); // Enable automatic height for dynamic message content EstimatedItemSize = UICollectionViewFlowLayout.AutomaticSize; } public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds) { // Calculate item width to fill available space minus left/right insets var availableWidth = newBounds.Width - SectionInset.Left - SectionInset.Right; ItemSize = new CGSize(availableWidth, UICollectionViewFlowLayout.AutomaticSize); return true; } }
2. Make the Cell Content Layout Responsive
Your current cell uses absolute positioning for the image view, which won’t adapt when the cell width changes. Switch to Auto Layout to keep the content centered and properly constrained:
public class MessageListViewCell : UICollectionViewCell { UIImageView imageView; public string Text { get; set; } [Export("initWithFrame:")] public MessageListViewCell(CGRect frame) : base(frame) { BackgroundView = new UIView { BackgroundColor = UIColor.Orange }; SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green }; ContentView.Layer.BorderColor = UIColor.LightGray.CGColor; ContentView.Layer.BorderWidth = 2.0f; ContentView.BackgroundColor = UIColor.White; // Let the content view resize with the cell ContentView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight; imageView = new UIImageView(UIImage.FromBundle("placeholder.png")); // Disable auto-resizing mask so Auto Layout takes over imageView.TranslatesAutoresizingMaskIntoConstraints = false; imageView.ContentMode = UIViewContentMode.ScaleAspectFit; imageView.Transform = CGAffineTransform.MakeScale(0.7f, 0.7f); ContentView.AddSubview(imageView); // Add constraints to center the image and prevent it from overflowing NSLayoutConstraint.Activate(new[] { imageView.CenterXAnchor.ConstraintEqualTo(ContentView.CenterXAnchor), imageView.CenterYAnchor.ConstraintEqualTo(ContentView.CenterYAnchor), imageView.WidthAnchor.ConstraintLessThanOrEqualTo(ContentView.WidthAnchor, multiplier: 0.8f), imageView.HeightAnchor.ConstraintLessThanOrEqualTo(ContentView.HeightAnchor, multiplier: 0.8f) }); } public UIImage Image { set { imageView.Image = value; } } [Export("custom")] public void Custom() { Console.WriteLine("custom in the cell"); } public override bool CanPerform(Selector action, NSObject withSender) { return action == new Selector("custom"); } }
3. Ensure the Collection View Resizes Correctly
In your renderer, make sure the collection view adapts to its parent view’s size so the layout gets the correct bounds to calculate cell width:
[assembly: ExportRenderer(typeof(MessagesListControl), typeof(MessagesListControlRenderer))] namespace Vinder.iOS.UI.Renderers { public class MessagesListControlRenderer : ViewRenderer<MessagesListControl, UICollectionView> { static readonly NSString messageListViewCell = new("MessageListViewCell"); private UICollectionView collectionView { get; set; } protected override void OnElementChanged(ElementChangedEventArgs<MessagesListControl> e) { base.OnElementChanged(e); if (e.OldElement != null) { // Clean up any event subscriptions here if needed } if (e.NewElement != null) { if (Control == null) { var layout = new MessageListLayout(); // Initialize with temporary bounds, autoresizing will handle the rest collectionView = new UICollectionView(UIScreen.MainScreen.Bounds, layout); collectionView.RegisterClassForCell(typeof(MessageListViewCell), messageListViewCell); collectionView.BackgroundColor = UIColor.Blue; collectionView.DataSource = new MessageListDataSource(collectionView, messageListViewCell); // Let the collection view resize with its parent collectionView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight; SetNativeControl(collectionView); } // Subscribe to any necessary events here } } } }
What These Changes Do:
- The layout now dynamically calculates cell width based on the collection view’s current bounds, ensuring cells fill the available space minus your desired margins.
- Auto Layout constraints keep the cell’s content centered and responsive, no matter how the cell size changes.
- The collection view will resize with its parent view, so the layout always has the correct bounds to work with.
Give these adjustments a try—your message cells should now stretch horizontally as expected, and the performance should stay snappy like you saw in your initial tests!
内容的提问来源于stack exchange,提问作者Coen Hacking

