为Xamarin.iOS创建类似Pinterest的布局

时间:2018-01-08 13:28:42

标签: c# ios xamarin xamarin.ios

我已经尝试了很长时间才弄清楚如何将This转换为C#和iOS。我基本上找不到任何真正对我有帮助的东西,特别是在.net方面,我们想知道是否有一个善良的灵魂可能有一个解决方案的例子,或者愿意为这样的解决方案提供代码。

此外,如何将此解决方案与从Web请求下载的图像一起使用?

我尝试过创建类似的东西,但有问题的是我只能模拟不同的单元格大小,我无法弄清楚如何精确地计算图像大小或者如何将图像信息都输入到我的PrepareLayout中( )布局类中的方法。

https://pastebin.com/jEXThW0X

public partial class CustomViewCell : UICollectionViewCell
{

    public CustomViewCell (IntPtr handle) : base (handle)
    {
    }
    public static readonly NSString Key = new NSString("ViewCell");
    public static readonly UINib Nib;

    public string ItemId { get; private set; }

    static CustomViewCell()
    {
        Nib = UINib.FromName("ViewCell", NSBundle.MainBundle);

    }

    public static CustomViewCell Create()
    {
        var cell = (CustomViewCell) Nib.Instantiate(null, null)[0];

        return cell;
    }

    public void Bind(ContentObjectViewModel model)
    {
        var imageUrl = $"myUrl/{image}";

        InvokeOnMainThread(() =>
        {
            ItemImageView.Image = ImageHelper.FromUrl(imageUrl);
            ItemId = model.Id.ToString();
        });


    }



    public async Task<UIImage> DownloadImageAsync(string imageUrl)
    {
        var httpClient = new HttpClient();

        Task<Byte[]> contentsTask = httpClient.GetByteArrayAsync(imageUrl);

        var contents = await contentsTask;

        return UIImage.LoadFromData(NSData.FromArray(contents));
    }
}


public class CustomDataSource : UICollectionViewSource
{
    public IEnumerable<ContentObjectViewModel> Items { get; set; }



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

    public override nint GetItemsCount(UICollectionView collectionView, nint section)
    {
        var count = section == 0 ? 1 : Items?.Count() ?? 0;

        return count;
    }

    public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
    {

            var cell = collectionView.DequeueReusableCell(CustomViewCell.Key, indexPath) as CustomViewCell ?? CustomViewCell.Create();

            cell.Bind(Items.ElementAt(indexPath.Row));

            return cell;

    }


}

public partial class CollectionViewLayout : UICollectionViewFlowLayout
{
    private const int NumberOfColumns = 2;

    private readonly List<UICollectionViewLayoutAttributes> _calculatedAttributes = new List<UICollectionViewLayoutAttributes>();
    private nfloat _contentWidth = 0f;
    private nfloat _contentHeight = 0f;

    private readonly nfloat[] _columnsXOffset = new nfloat[NumberOfColumns];
    private readonly nfloat[] _columnsYOffset = new nfloat[NumberOfColumns];

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

    public override void PrepareLayout()
    {
        base.PrepareLayout();
        _calculatedAttributes.Clear();

        _contentWidth = CollectionView.Frame.Width;
        var columnWidth = _contentWidth / NumberOfColumns;


        for (var i = 0; i < _columnsXOffset.Length; i++)
        {
            _columnsXOffset[i] = i * columnWidth;
        }

        for (var i = 0; i < _columnsYOffset.Length; i++)
        {
            _columnsYOffset[i] = 0;
        }

        var attribute1 = UICollectionViewLayoutAttributes.CreateForCell(NSIndexPath.FromItemSection(0, 0));
        attribute1.Frame = new CGRect(_columnsXOffset[1], 0, columnWidth, 0);
        _calculatedAttributes.Add(attribute1);

        //_columnsYOffset[1] = _buttonHeight; // Second column has a vertical offset (due to sell button height)
        var random = new Random();
        var column = 0;
        for (var i = 0; i < CollectionView.NumberOfItemsInSection(1); i++)
        {
            var cellHeight = random.Next(250, 500);
            var photoHeight = CollectionView.Frame.Height;
            var indexPath = NSIndexPath.FromItemSection(i, 1);

            var frame = new CGRect(_columnsXOffset[column], _columnsYOffset[column], columnWidth, photoHeight);
            var insetFrame = frame.Inset(0f, 0f);

            var attribute = UICollectionViewLayoutAttributes.CreateForCell(indexPath);

            attribute.Frame = insetFrame;

            _calculatedAttributes.Add(attribute);

            _contentHeight = NMath.Max(_contentHeight, frame.GetMaxY());
            _columnsYOffset[column] = _columnsYOffset[column] + photoHeight;

            column = column >= (NumberOfColumns - 1) ? 0 : ++column;
        }
    }



    public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect)
    {
        var attributes = new List<UICollectionViewLayoutAttributes>();

        foreach (var attr in _calculatedAttributes)
        {
            var intersection = CGRect.Intersect(attr.Frame, rect);

            if (intersection != CGRect.Empty)
            {
                attributes.Add(attr);
            }
        }

        return attributes.ToArray();
    }

    public override CGSize CollectionViewContentSize => new CGSize(_contentWidth, _contentHeight);


}

  public partial class TabProfileController : UIViewController
{
    private CustomDataSource _customDataSource;
    private readonly ContentServiceClient _contentServiceClient = new ContentServiceClient();
    private string _userId = "userid";
    bool useRefreshControl = false;
    UIRefreshControl RefreshControl;

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

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


        AddRefreshControl();
        ProfileItemsCollectionView.Add(RefreshControl);

        imageViewProfilePicture.Image = UIImage.FromBundle("profilepic");
        imageViewProfilePicture.Layer.CornerRadius = imageViewProfilePicture.Frame.Size.Width / 2;
        imageViewProfilePicture.ClipsToBounds = true;


        //await LoadSaleItems();
        await InitializeCollectionView();


    }

    private async void HandleValueChanged(object sender, EventArgs e)
    {
        await RefreshAsync();
    }

    async Task RefreshAsync()
    {
        // only activate the refresh control if the feature is available  

            RefreshControl.BeginRefreshing();
        _customDataSource.Items = await _contentServiceClient.GetItemsForUser(_userId.ToString());
        ProfileItemsCollectionView.ReloadData();
            RefreshControl.EndRefreshing();


    }


    // This method will add the UIRefreshControl to the table view if  
    // it is available, ie, we are running on iOS 6+  
    void AddRefreshControl()
    {

        // the refresh control is available, let's add it  
        RefreshControl = new UIRefreshControl();
        RefreshControl.ValueChanged += async (sender, e) =>
        {

            await RefreshAsync();
        };
        useRefreshControl = true;

    }


    private async Task InitializeCollectionView()
    {
        var nib = UINib.FromName(CustomViewCell.Key, null);
        ProfileItemsCollectionView.RegisterNibForCell(nib, CustomViewCell.Key);

        _customDataSource = new CustomDataSource();


        var items = await _contentServiceClient.GetItemsForUser(_userId.ToString());
        _customDataSource.Items = items;
        ProfileItemsCollectionView.Source = _customDataSource;
        ProfileItemsCollectionView.ReloadData();

    }

1 个答案:

答案 0 :(得分:0)

经过大量的研究和一些反复试验后,我终于成功地了解了代表以及如何将它们与Xamarin.iOS结合使用。

基本上我要做的就是将以下内容添加到我的Layout类中:

public delegate CGSize CollectionViewDelegateFlowLayout(UICollectionView collectionView, UICollectionViewFlowLayout layout, NSIndexPath indexPath);
    public event CollectionViewDelegateFlowLayout SizeForItem;

然后调用事件&#39;&#39; SizeFoItem&#39;在循环中计算单元格的大小。

最后将调用添加到我的ViewController中,如下所示:

collectionViewLayout.SizeForItem += (collectionView, layout, indexPath) => {

            return new CGSize((View.Bounds.Width - 40) / 3, photoheight
        };

变量photoHeight来自构建ViewController时初始化的照片列表。