Пользовательская анимация в SetContentOffset для операций ввода-вывода CollectionView, запускаемая PageControl, не является плавной - PullRequest
0 голосов
/ 08 июня 2018

У меня есть проект Xamarin.IOs.Я использую UICollectionView с включенным пейджингом.Затем есть UIPageControl, который синхронизируется с UICollectionView.

Требуются две функциональные возможности:

  1. При перелистывании UICollectionView текущая страница CollectionView изменится, итекущий индикатор UIPageControl также будет меняться синхронно.

    Реализация:

    В UICollectionViewSource,

    public override void DecelerationEnded(UIScrollView scrollView)
    {
        Index = (int)(scrollView.ContentOffset.X / scrollView.Frame.Width);
        PageControl.CurrentPage = Index;
        CardSwiped?.Invoke(this, new CustomEventArgs(Index));
    }
    

    В соответствующем ViewController,

    private void SomeMethod()
    {
        CollectionSource.CardSwiped += OnCardSwiped;
    }
    
    private void OnCardSwiped(object sender, CustomEventArgs args)
    {
        // Perform some action
    }
    

    Работает отлично!

  2. При нажатии UIPageControl текущая страница CollectionView должна меняться в соответствии с касанием и текущим индикатором UIPageControlтакже будет меняться при синхронизации.

    Реализация:

    В соответствующем ViewController

    private void SomeMethod()
    {
        PageControl.PrimaryActionTriggered += OnPageControlTapped;
    }
    
    private void OnPageControlTapped(object sender, EventArgs args)
    {
        // Some action
    
        var pageControlIndex = CardPageControl.CurrentPage;
        var sourceIndex = CollectionSource.Index;
        var distanceToScroll = CardCollectionView.Frame.Width * (pageControlIndex - sourceIndex);
    
        UIView.Animate(0.5, 0, UIViewAnimationOptions.TransitionNone,
            () =>
            {
                CollectionView.SetContentOffset(
                    new CGPoint(CollectionView.ContentOffset.X + distanceToScroll, CollectionView.ContentOffset.Y),
                    false);
            },
            () =>
            {
                CollectionSource.DecelerationEnded(CollectionView);
            });
    }
    

    Я не могу вызвать SetContentOffset с анимацией true,

    CollectionView.SetContentOffset(new CGPoint(CollectionView.ContentOffset.X + y, CollectionView.ContentOffset.Y), true);
    

    , потому что мне нужно вызвать CollectionSource.DecelerationEnded(CollectionView); после того, как страница позиционируется методом SetContentOffset.

    Проблема , когда я использую эту пользовательскую анимацию, CollectionView не анимируется правильно,

    enter image description here

Как мне преодолеть это?

1 Ответ

0 голосов
/ 08 июня 2018

Кажется, есть некоторая проблема с тем, как UICollectionView прокручивает SetContentOffset с пользовательской анимацией, когда Пейджинг включен.

Когда полная ширина страницы (CardCollectionView.Frame.Width) берется как расстояние, которое нужно прокрутить,

var distanceToScroll = CardCollectionView.Frame.Width * (pageControlIndex - sourceIndex);

и используется в SetContentOffset,

CollectionView.SetContentOffset(
            new CGPoint(CollectionView.ContentOffset.X + distanceToScroll, CollectionView.ContentOffset.Y),
            false);

, тогда оно не будет анимироваться так, как при использовании пользовательских анимаций.

Решение:

Вы не должны настраивать анимацию для полной ширины страницы расстояния прокрутки, вместо этого вы должны уменьшить расстояние прокрутки на 1 пиксель (выбрав 1 пиксель, чтобы сделать его менее заметным, подойдет и любая другая сумма) из полной ширины страницы .То есть

var distanceToScroll = (CardCollectionView.Frame.Width - 1) * (pageControlIndex - sourceIndex);

-1 в CardCollectionView.Frame.Width - 1 - это так называемый обходной путь.

Затем вы должны решить эту проблему после анимации.То есть в приведенном выше коде UIView.Animate функция обратного вызова должна иметь одну дополнительную строку:

CardCollectionView.SetContentOffset(
    new CGPoint(CardCollectionView.ContentOffset.X + (pageControlIndex - sourceIndex), CardCollectionView.ContentOffset.Y), 
    false);

Тогда UIView.Animate будет выглядеть так:

UIView.Animate(0.5, 0, UIViewAnimationOptions.TransitionNone,
    () =>
    {
        CollectionView.SetContentOffset(
            new CGPoint(CollectionView.ContentOffset.X + distanceToScroll, CollectionView.ContentOffset.Y),
            false);
    },
    () =>
    {
        CardCollectionView.SetContentOffset(
            new CGPoint(CardCollectionView.ContentOffset.X + (pageControlIndex - sourceIndex), CardCollectionView.ContentOffset.Y), 
            false);
        CollectionSource.DecelerationEnded(CollectionView);
    });

Теперь пользовательская анимация будет работать очень плавно ?

...