UICollectionView with section layout issue in Xamarin

smartsanjasmartsanja Member
edited January 16 in Xamarin.iOS

I have UIcollectionView with 8 sections. Each section has a dedicated array as the data source. I want to add an item to each section on a button press. UICollectionView scroll direction set to Horizontal because I want the sections to be vertical direction. Everything working fine in Xcode project(Xib and Objective-C) as this screenshot(Red colored items are the items added on button press).

When I do the same implementation in Xamarin ios, the layout become a mess after press the button as bellow.

My code as bellow
public partial class GridViewController : UIViewController
{
CVSource source;

        int MAX_NUMBER_OF_ROWS = 4;

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

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        // Perform any additional setup after loading the view, typically from a nib.
        //this.collectionView.SetNeedsDisplay();
        this.collectionView.RegisterClassForCell(typeof(ItemCell), ItemCell.CellId);

        source = new CVSource();
        this.collectionView.DataSource = source;


    }

    partial void AddButtonPressed(UIButton sender)
    {
        Console.WriteLine("Add button pressed");

        MAX_NUMBER_OF_ROWS = MAX_NUMBER_OF_ROWS + 1;
        source.AddItem();

        collectionView.Layer.RemoveAllAnimations();
        collectionView.ReloadData();

        ViewDidLayoutSubviews();

    }

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

        collectionView.Frame = new CoreGraphics.CGRect(collectionView.Frame.Location.X, collectionView.Frame.Location.Y, collectionView.Frame.Size.Width, MAX_NUMBER_OF_ROWS * 40);
        btnAdd.Frame = new CoreGraphics.CGRect(btnAdd.Frame.Location.X, collectionView.Frame.Location.Y + collectionView.Frame.Size.Height + 10, btnAdd.Frame.Size.Width, btnAdd.Frame.Size.Height);

    }

    public override void DidReceiveMemoryWarning()
    {
        base.DidReceiveMemoryWarning();
        // Release any cached data, images, etc that aren't in use.
    }

DataSource class

class CVSource : UICollectionViewSource
{

    List<string> arr1 = new List<string> { "40", "30"};
    List<string> arr2 = new List<string> { "25", "22" };
    List<string> arr3 = new List<string> { "35", "67" };
    List<string> arr4 = new List<string> { "26", "12" };
    List<string> arr5 = new List<string> { "27", "21", };
    List<string> arr6 = new List<string> { "12", "45" };
    List<string> arr7 = new List<string> { "34", "67" };
    List<string> arr8 = new List<string> { "21", "44", };


    public override nint NumberOfSections(UICollectionView collectionView)
    {
        return 8;
    }

    public override nint GetItemsCount(UICollectionView collectionView, nint section)
    {
        if ((int)section == 0)
            return arr1.Count;
        else if ((int)section == 1)
            return arr2.Count;
        else if ((int)section == 2)
            return arr3.Count;
        else if ((int)section == 3)
            return arr4.Count;
        else if ((int)section == 4)
            return arr5.Count;
        else if ((int)section == 5)
            return arr6.Count;
        else if ((int)section == 6)
            return arr7.Count;
        else if ((int)section == 7)
        return arr8.Count;

        return 0;
    }



    public override UICollectionViewCell GetCell(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
    {
        var itemCell = (ItemCell)collectionView.DequeueReusableCell(ItemCell.CellId, indexPath);

        if (indexPath.Section == 0)
        {
            itemCell.SetText(arr1[indexPath.Row]);

        }
        else if (indexPath.Section == 1)
        {
            itemCell.SetText(arr2[indexPath.Row]);

        }
        else if (indexPath.Section == 2)
        {
            itemCell.SetText(arr3[indexPath.Row]);

        }
        else if (indexPath.Section == 3)
        {
            itemCell.SetText(arr4[indexPath.Row]);

        }
        else if (indexPath.Section == 4)
        {
            itemCell.SetText(arr5[indexPath.Row]);

        }
        else if (indexPath.Section == 5)
        {
            itemCell.SetText(arr6[indexPath.Row]);

        }
        else if (indexPath.Section == 6)
        {
            itemCell.SetText(arr7[indexPath.Row]);

        }
        else if (indexPath.Section == 7)
            itemCell.SetText(arr8[(indexPath.Row)]);


        return itemCell;
    }

    public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
    {
        Console.WriteLine("Row selected "+ indexPath.Row);
    }


    public void AddItem()
    {
        arr1.Add("0");
        arr2.Add("0");
        arr3.Add("0");
        arr4.Add("0");
        arr5.Add("0");
        arr6.Add("0");
        arr7.Add("0");
        arr8.Add("0");

    }
}

Im new to Xamarin, appreciate any comments/suggestions from Xamarin experts

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    I tried to use your code to build a sample for UICollectionView, it worked fine on my side:

    The new item will be added at the bottom of the Collection View.

    I noticed that you called ViewDidLayoutSubviews in your button's click event. This method should be called by the system when it finds the subviews of the root view have changed its size. It's better to avoid calling it manually. And now, using auto layout could be a better choice.

    Refer to my attachment here for the specific code.

    If your issue persists, try to upload your repo here to help me reproduce this issue.

  • smartsanjasmartsanja Member

    @LandLu Thanks a lot for the answer. I think in my code issue is in the ItemCell class which I haven't share in the original question. In my case I did not use Storyboard or Xib to design Cell. I use code only. Can you please help to point out any issue in the below code

    public partial class ItemCell : UICollectionViewCell
    {
        public static readonly NSString CellId = new NSString("ItemCell");
        public static UITextField txtFld;
    
        [Export("initWithFrame:")]
    
        public ItemCell(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;
            ContentView.Transform = CGAffineTransform.MakeScale(0.8f, 0.8f);
    
            txtFld = new UITextField() { Frame = new CGRect(5.0, 5.0, 60.0, 30.0), KeyboardType = UIKeyboardType.DecimalPad };
    
        }
    }
    
  • LandLuLandLu Member, Xamarin Team Xamurai

    That won't make a difference no matter you used code or storyboard to construct the cell.
    I noticed you initialized a static txtFld in the cell's constructor but it hasn't been added on the content view. Normally, we won't define a static control and it should be added to the view architecture.
    It's better to share your sample here as what I did above. This could help me understand your code more clearly.

  • smartsanjasmartsanja Member

    Thanks a lot for the support. After I change public static UITextField txtFld; to UITextField txtFld; everything work fine.

  • LandLuLandLu Member, Xamarin Team Xamurai

    You're welcome.
    If you feel this helping you try to mark it to end this discussion.

Sign In or Register to comment.