if (type == DisposeTypes.Explicit)
{
- mLayout.StopScroll();
+ if (mLayout != null)
+ {
+ mLayout.StopScroll(false);
+ }
if (mAdapter != null)
{
{
offset = range - extent;
}
+ if (offset < 0)
+ {
+ offset = 0;
+ }
if (mScrollBar.Direction == ScrollBar.DirectionType.Vertical)
{
mScrollBar.ThumbSize = new Size(thickness, length);
{
if (e.PanGesture.State == Gesture.StateType.Started)
{
- mLayout.StopScroll();
+ mLayout.StopScroll(true);
}
else if (e.PanGesture.State == Gesture.StateType.Continuing)
{
if (mLayout.CanScrollVertically())
{
- mLayout.ScrollVerticallyBy(e.PanGesture.Displacement.Y, mRecycler, true);
+ mLayout.ScrollVerticallyBy((int)e.PanGesture.Displacement.Y, mRecycler, true);
}
else if (mLayout.CanScrollHorizontally())
{
- mLayout.ScrollHorizontallyBy(e.PanGesture.Displacement.X, mRecycler, true);
+ mLayout.ScrollHorizontallyBy((int)e.PanGesture.Displacement.X, mRecycler, true);
}
ShowScrollBar();
{
if (mLayout.CanScrollVertically())
{
- mLayout.ScrollVerticallyBy(e.PanGesture.Velocity.Y * 600, mRecycler, false);
+ mLayout.ScrollVerticallyBy((int)e.PanGesture.Velocity.Y * 600, mRecycler, false);
}
else if (mLayout.CanScrollHorizontally())
{
- mLayout.ScrollHorizontallyBy(e.PanGesture.Velocity.X * 600, mRecycler, false);
+ mLayout.ScrollHorizontallyBy((int)e.PanGesture.Velocity.X * 600, mRecycler, false);
}
ShowScrollBar(1200, true);
}
Down
}
+ private readonly int SCROLL_ANIMATION_DURATION = 500;
+
private FlexibleView mFlexibleView;
private ChildHelper mChildHelper;
public void LayoutChild(ViewHolder child, float left, float top, float width, float height)
{
View itemView = child.ItemView;
- itemView.SizeWidth = width - itemView.Margin.Start - itemView.Margin.End;
- itemView.SizeHeight = height - itemView.Margin.Top - itemView.Margin.Bottom;
- itemView.PositionX = left + itemView.Margin.Start;
- itemView.PositionY = top + itemView.Margin.Top;
+ itemView.SizeWidth = (int)(width - itemView.Margin.Start - itemView.Margin.End);
+ itemView.SizeHeight = (int)(height - itemView.Margin.Top - itemView.Margin.Bottom);
+ itemView.PositionX = (int)(left + itemView.Margin.Start);
+ itemView.PositionY = (int)(top + itemView.Margin.Top);
}
/// <summary>
return;
}
- if (mScrollAni == null)
- {
- mScrollAni = new Animation();
- mScrollAni.Finished += OnScrollAnimationFinished;
- }
- else if (mScrollAni.State == Animation.States.Playing)
+ if (dx == 0)
{
- //StopScroll();
- mScrollAni.Stop(Animation.EndActions.StopFinal);
+ return;
}
- mScrollAni.Duration = 500;
- mScrollAni.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSquare);
-
- mScrollAni.Clear();
int childCount = mChildHelper.GetChildCount();
if (immediate == true)
for (int i = childCount - 1; i >= 0; i--)
{
ViewHolder v = mChildHelper.GetChildAt(i);
- v.ItemView.PositionX += dx;
+ v.ItemView.PositionX = (int)(v.ItemView.PositionX + dx);
}
}
else
{
+ if (mScrollAni == null)
+ {
+ mScrollAni = new Animation();
+ mScrollAni.Duration = SCROLL_ANIMATION_DURATION;
+ mScrollAni.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSquare);
+ }
+
+ // avoid out of boundary of flexibleview. delta value might be used for shadow.
+ // this must be done before animation clear.
+ if (childCount > 0)
+ {
+ ViewHolder vh = mChildHelper.GetChildAt(0);
+ if (vh.LayoutPosition == 0)
+ {
+ if ((int)(vh.ItemView.PositionX + dx) != 0)
+ {
+ dx = (int)(0 - vh.ItemView.PositionX);
+ }
+ }
+
+ vh = mChildHelper.GetChildAt(childCount - 1);
+ if (vh.LayoutPosition == ItemCount - 1)
+ {
+ if ((int)(vh.ItemView.PositionX + dx) != (int)Width)
+ {
+ dx = (int)(Width - vh.ItemView.PositionX);
+ }
+ }
+ }
+
+ // save position before animation clear.
+ float[] childrenPositon = new float[childCount];
+ for (int i = childCount - 1; i >= 0; i--)
+ {
+ ViewHolder v = mChildHelper.GetChildAt(i);
+ childrenPositon[i] = (int)v.ItemView.PositionX;
+ }
+
+ mScrollAni.Clear();
+ mScrollAni.Finished += OnScrollAnimationFinished;
+
for (int i = childCount - 1; i >= 0; i--)
{
ViewHolder v = mChildHelper.GetChildAt(i);
- mScrollAni.AnimateTo(v.ItemView, "PositionX", v.ItemView.PositionX + dx);
+
+ // set position again because position might be changed after animation clear.
+ v.ItemView.PositionX = childrenPositon[i];
+
+ mScrollAni.AnimateTo(v.ItemView, "PositionX", (int)(v.ItemView.PositionX + dx));
}
mScrollAni.Play();
}
return;
}
- if (mScrollAni == null)
- {
- mScrollAni = new Animation();
- mScrollAni.Finished += OnScrollAnimationFinished;
- }
- else if (mScrollAni.State == Animation.States.Playing)
+ if (dy == 0)
{
- //StopScroll();
- mScrollAni.Stop(Animation.EndActions.StopFinal);
+ return;
}
- mScrollAni.Duration = 500;
- mScrollAni.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSquare);
-
- mScrollAni.Clear();
int childCount = mChildHelper.GetChildCount();
if (immediate == true)
for (int i = childCount - 1; i >= 0; i--)
{
ViewHolder v = mChildHelper.GetChildAt(i);
- v.ItemView.PositionY += dy;
+ v.ItemView.PositionY = (int)(v.ItemView.PositionY + dy);
}
}
else
{
+ if (mScrollAni == null)
+ {
+ mScrollAni = new Animation();
+ mScrollAni.Duration = SCROLL_ANIMATION_DURATION;
+ mScrollAni.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSquare);
+ }
+
+ // avoid out of boundary of flexibleview. delta value might be used for shadow.
+ // this must be done before animation clear.
+ if (childCount > 0)
+ {
+ ViewHolder vh = mChildHelper.GetChildAt(0);
+ if (vh.LayoutPosition == 0)
+ {
+ if ((int)(vh.ItemView.PositionY + dy) != 0)
+ {
+ dy = (int)(0 - vh.ItemView.PositionY);
+ }
+ }
+
+ vh = mChildHelper.GetChildAt(childCount - 1);
+ if (vh.LayoutPosition == ItemCount - 1)
+ {
+ if ((int)(vh.ItemView.PositionY + dy) != (int)Height)
+ {
+ dy = (int)(Height - vh.ItemView.PositionY);
+ }
+ }
+ }
+
+ // save position before animation clear.
+ float[] childPositon = new float[childCount];
+ for (int i = childCount - 1; i >= 0; i--)
+ {
+ ViewHolder v = mChildHelper.GetChildAt(i);
+ childPositon[i] = (int)v.ItemView.PositionY;
+ }
+
+ mScrollAni.Clear();
+ mScrollAni.Finished += OnScrollAnimationFinished;
+
for (int i = childCount - 1; i >= 0; i--)
{
ViewHolder v = mChildHelper.GetChildAt(i);
- mScrollAni.AnimateTo(v.ItemView, "PositionY", v.ItemView.PositionY + dy);
+
+ // set position again because position might be changed after animation clear.
+ v.ItemView.PositionY = childPositon[i];
+
+ mScrollAni.AnimateTo(v.ItemView, "PositionY", (int)(v.ItemView.PositionY + dy));
}
mScrollAni.Play();
}
mChildHelper = recyclerView.mChildHelper;
}
- internal void StopScroll()
+ internal void StopScroll(bool doSomethingAfterAnimationStopped)
{
if (mScrollAni != null && mScrollAni.State == Animation.States.Playing)
{
- mScrollAni.Stop(Animation.EndActions.StopFinal);
- mScrollAni.Clear();
- OnScrollAnimationFinished(mScrollAni, null);
+ mScrollAni.Finished -= OnScrollAnimationFinished;
+ mScrollAni.Stop();
+
+ if (doSomethingAfterAnimationStopped)
+ {
+ OnScrollAnimationFinished(mScrollAni, null);
+ }
}
}
private void OnScrollAnimationFinished(object sender, EventArgs e)
{
- RecycleChildrenInt(mFlexibleView.mRecycler);
+ foreach (ViewHolder holder in mPendingRecycleViews)
+ {
+ holder.PendingRecycle = false;
+ }
+ mPendingRecycleViews.Clear();
+
+ int start = NO_POSITION;
+ ViewHolder firstItemView = FindFirstVisibleItemView();
+ if (firstItemView != null)
+ start = firstItemView.LayoutPosition;
+ else
+ start = 0;
+
+ int itemCount = ChildCount;
+
+ int end = NO_POSITION;
+ ViewHolder lastItemView = FindLastVisibleItemView();
+ if (lastItemView != null)
+ end = lastItemView.LayoutPosition;
+ else
+ end = itemCount - 1;
+
+ List<ViewHolder> removedViewList = new List<ViewHolder>();
+ for (int i = 0; i < itemCount; i++)
+ {
+ ViewHolder v = GetChildAt(i);
+
+ //if item view of holder is visible, it should not be recycled.
+ if (v.LayoutPosition >= start && v.LayoutPosition <= end)
+ continue;
+
+ removedViewList.Add(v);
+ }
+
+ for (int i = 0; i < removedViewList.Count; i++)
+ {
+ ViewHolder v = removedViewList[i];
+ v.PendingRecycle = false;
+ mFlexibleView.mRecycler.RecycleView(v);
+ mChildHelper.RemoveView(v);
+ }
+
+ // relayout
+ mFlexibleView.OnRelayout(null, null);
}
private void AddViewInternal(ViewHolder holder, int index, bool disappearing)
}
}
+ protected virtual ViewHolder FindFirstVisibleItemView()
+ {
+ return null;
+ }
+
+ protected virtual ViewHolder FindLastVisibleItemView()
+ {
+ return null;
+ }
+
private void RecycleChildrenInt(FlexibleView.Recycler recycler)
{
- foreach(ViewHolder holder in mPendingRecycleViews)
+ foreach (ViewHolder holder in mPendingRecycleViews)
{
holder.PendingRecycle = false;
recycler.RecycleView(holder);
{
get
{
- return ItemView.PositionX - ItemView.Margin.Start;
+ return (int)(ItemView.PositionX - ItemView.Margin.Start);
}
}
{
get
{
- return ItemView.PositionX + ItemView.SizeWidth + ItemView.Margin.End;
+ return (int)(ItemView.PositionX + ItemView.SizeWidth + ItemView.Margin.End);
}
}
{
get
{
- return ItemView.PositionY - ItemView.Margin.Top;
+ return (int)(ItemView.PositionY - ItemView.Margin.Top);
}
}
{
get
{
- return ItemView.PositionY + ItemView.SizeHeight + ItemView.Margin.Bottom;
+ return (int)(ItemView.PositionY + ItemView.SizeHeight + ItemView.Margin.Bottom);
}
}
public void PutRecycledView(ViewHolder view)
{
int viewType = view.ItemViewType;
+ if (viewType >= mMaxTypeCount)
+ {
+ return;
+ }
if (mScrap[viewType] == null)
{
mScrap[viewType] = new List<ViewHolder>();
{
index = mViewList.Count;
}
+
mViewList.Insert(index, holder);
if (!itemViewTable.ContainsKey(holder.ItemView.ID))
return false;
}
- FlexibleView.ViewHolder anchorChild = FindFirstCompleteVisibleItemView();
- if (anchorChild != null)
+ FlexibleView.ViewHolder anchorChild = FindFirstVisibleItemView();
+ if (anchorChild == null)
{
- return false;
+ Log.Error("flexibleview", $"exception occurs when updating anchor information!");
+ anchorChild = GetChildAt(0);
}
anchorInfo.Position = anchorChild.LayoutPosition;
anchorInfo.Coordinate = mOrientationHelper.GetViewHolderStart(anchorChild);
{
// get the first child in the direction we are going
FlexibleView.ViewHolder child = GetChildClosestToEnd();
- //Log.Fatal("TV.FLUX.Component", $"==========> child:{child.LayoutGroupIndex}-{child.LayoutItemIndex} childEnd:{orientationHelper.GetItemEnd(child)} # {orientationHelper.GetEnd()}");
-
if (child != null)
{
if (child.ItemView.Focusable == false || mOrientationHelper.GetViewHolderEnd(child) + scrolled < mOrientationHelper.GetEnd())
{
- layoutState.Available = MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace();
+ layoutState.Available = (int)(MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace());
layoutState.Extra = 0;
layoutState.ScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
layoutState.Recycle = false;
else
{
FlexibleView.ViewHolder child = GetChildClosestToStart();
-
if (child != null)
{
if (child.ItemView.Focusable == false || mOrientationHelper.GetViewHolderStart(child) + scrolled > 0)
{
- layoutState.Available = MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace();
+ layoutState.Available = (int)(MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace());
layoutState.Extra = 0;
layoutState.ScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
layoutState.Recycle = false;
private void RecycleViewsFromEnd(FlexibleView.Recycler recycler, float dt, bool immediate)
{
- int childCount = ChildCount;
if (dt < 0)
{
return;
}
+ int childCount = ChildCount;
float limit = mOrientationHelper.GetEnd() - dt;
if (mShouldReverseLayout)
{
mLayoutState.Recycle = true;
int layoutDirection = dy < 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
float absDy = Math.Abs(dy);
+
UpdateLayoutState(layoutDirection, absDy, true);
+
float consumed = mLayoutState.ScrollingOffset
+ Fill(recycler, mLayoutState, false, immediate);
}
float scrolled = absDy > consumed ? -layoutDirection * consumed : dy;
-
Cache(recycler, mLayoutState, immediate, scrolled);
mOrientationHelper.OffsetChildren(scrolled, immediate);
mLayoutState.Available -= scrollingOffset;
}
mLayoutState.ScrollingOffset = scrollingOffset;
-
}
// Convenience method to find the child closes to start. Caller should check it has enough
mLayoutState.Extra = mOrientationHelper.GetStartAfterPadding();
}
- private FlexibleView.ViewHolder FindFirstVisibleItemView()
+ protected override FlexibleView.ViewHolder FindFirstVisibleItemView()
{
int childCount = ChildCount;
if (mShouldReverseLayout == false)
for (int i = 0; i < childCount; i++)
{
FlexibleView.ViewHolder child = GetChildAt(i);
- if ((int)mOrientationHelper.GetViewHolderEnd(child) > 0)
+ int end = (int)mOrientationHelper.GetViewHolderEnd(child);
+ if (end >= 0 && end < (int)mOrientationHelper.GetEnd())
{
return child;
}
for (int i = childCount - 1; i >= 0; i--)
{
FlexibleView.ViewHolder child = GetChildAt(i);
- if ((int)mOrientationHelper.GetViewHolderEnd(child) > 0)
+ int end = (int)mOrientationHelper.GetViewHolderEnd(child);
+ if (end >= 0 && end < (int)mOrientationHelper.GetEnd())
{
return child;
}
for (int i = 0; i < childCount; i++)
{
FlexibleView.ViewHolder child = GetChildAt(i);
- if ((int)mOrientationHelper.GetViewHolderStart(child) > 0)
+ int start = (int)mOrientationHelper.GetViewHolderStart(child);
+ if (start > 0 && start < (int)mOrientationHelper.GetEnd())
{
return child;
}
for (int i = childCount - 1; i >= 0; i--)
{
FlexibleView.ViewHolder child = GetChildAt(i);
- if ((int)mOrientationHelper.GetViewHolderStart(child) > 0)
+ int start = (int)mOrientationHelper.GetViewHolderStart(child);
+ if (start > 0 && start < (int)mOrientationHelper.GetEnd())
{
return child;
}
return null;
}
- private FlexibleView.ViewHolder FindLastVisibleItemView()
+ protected override FlexibleView.ViewHolder FindLastVisibleItemView()
{
int childCount = ChildCount;
if (mShouldReverseLayout == false)
for (int i = childCount - 1; i >= 0; i--)
{
FlexibleView.ViewHolder child = GetChildAt(i);
- if ((int)mOrientationHelper.GetViewHolderStart(child) < (int)mOrientationHelper.GetEnd())
+ int start = (int)mOrientationHelper.GetViewHolderStart(child);
+ if (start > 0 && start < (int)mOrientationHelper.GetEnd())
{
return child;
}
for (int i = 0; i < childCount; i++)
{
FlexibleView.ViewHolder child = GetChildAt(i);
- if ((int)mOrientationHelper.GetViewHolderStart(child) < (int)mOrientationHelper.GetEnd())
+ int start = (int)mOrientationHelper.GetViewHolderStart(child);
+ if (start > 0 && start < (int)mOrientationHelper.GetEnd())
{
return child;
}