using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
+using Tizen.NUI.Accessibility;
namespace Tizen.NUI.Components
{
/// <summary>
/// ScrollEventArgs is a class to record scroll event arguments which will sent to user.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public class ScrollEventArgs : EventArgs
{
- Position position;
+ private Position position;
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="position">Current scroll position</param>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
+ /// <since_tizen> 8 </since_tizen>
public ScrollEventArgs(Position position)
{
this.position = position;
}
/// <summary>
- /// [Draft] Current scroll position.
+ /// Current position of ContentContainer.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public Position Position
{
get
}
/// <summary>
- /// [Draft] This class provides a View that can scroll a single View with a layout. This View can be a nest of Views.
+ /// This class provides a View that can scroll a single View with a layout. This View can be a nest of Views.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public class ScrollableBase : Control
{
static bool LayoutDebugScrollableBase = false; // Debug flag
private Direction mScrollingDirection = Direction.Vertical;
private bool mScrollEnabled = true;
+ private int mScrollDuration = 125;
private int mPageWidth = 0;
+ private float mPageFlickThreshold = 0.4f;
+ private float mScrollingEventThreshold = 0.00001f;
private class ScrollableBaseCustomLayout : LayoutGroup
{
// Size of ScrollableBase is changed. Change Page width too.
scrollableBase.mPageWidth = (int)MeasuredWidth.Size.AsRoundedValue();
+ scrollableBase.OnScrollingChildRelayout(null , null);
}
protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
/// <summary>
/// The direction axis to scroll.
/// </summary>
- /// <since_tizen> 6 </since_tizen>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public enum Direction
{
/// <summary>
/// Horizontal axis.
/// </summary>
- /// <since_tizen> 6 </since_tizen>
+ /// <since_tizen> 8 </since_tizen>
Horizontal,
/// <summary>
/// Vertical axis.
/// </summary>
- /// <since_tizen> 6 </since_tizen>
+ /// <since_tizen> 8 </since_tizen>
Vertical
}
/// <summary>
- /// [Draft] Scrolling direction mode.
+ /// Scrolling direction mode.
/// Default is Vertical scrolling.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public Direction ScrollingDirection
{
get
}
/// <summary>
- /// [Draft] Enable or disable scrolling.
+ /// Enable or disable scrolling.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public bool ScrollEnabled
{
get
}
/// <summary>
- /// [Draft] Pages mode, enables moving to the next or return to current page depending on pan displacement.
+ /// Pages mode, enables moving to the next or return to current page depending on pan displacement.
/// Default is false.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public bool SnapToPage { set; get; } = false;
/// <summary>
- /// [Draft] Get current page.
- /// Working propery with SnapToPage property.
+ /// Get current page.
+ /// Working property with SnapToPage property.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public int CurrentPage { get; private set; } = 0;
/// <summary>
- /// [Draft] Duration of scroll animation.
+ /// Duration of scroll animation.
+ /// Default value is 125ms.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
+ public int ScrollDuration
+ {
+ set
+ {
+ mScrollDuration = value >= 0 ? value : mScrollDuration;
+ }
+ get
+ {
+ return mScrollDuration;
+ }
+ }
- public int ScrollDuration { set; get; } = 125;
/// <summary>
- /// [Draft] Scroll Available area.
+ /// Scroll Available area.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public Vector2 ScrollAvailableArea { set; get; }
/// <summary>
/// An event emitted when user starts dragging ScrollableBase, user can subscribe or unsubscribe to this event handler.<br />
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public event EventHandler<ScrollEventArgs> ScrollDragStarted;
/// <summary>
/// An event emitted when user stops dragging ScrollableBase, user can subscribe or unsubscribe to this event handler.<br />
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public event EventHandler<ScrollEventArgs> ScrollDragEnded;
/// <summary>
/// An event emitted when the scrolling slide animation starts, user can subscribe or unsubscribe to this event handler.<br />
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public event EventHandler<ScrollEventArgs> ScrollAnimationStarted;
/// <summary>
/// An event emitted when the scrolling slide animation ends, user can subscribe or unsubscribe to this event handler.<br />
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public event EventHandler<ScrollEventArgs> ScrollAnimationEnded;
/// <summary>
/// An event emitted when scrolling, user can subscribe or unsubscribe to this event handler.<br />
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public event EventHandler<ScrollEventArgs> Scrolling;
/// <summary>
- /// Scrollbar for ScrollableBase.<br />
+ /// Scrollbar for ScrollableBase.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public ScrollbarBase Scrollbar
{
get
{
scrollBar.Unparent();
}
-
scrollBar = value;
- scrollBar.Name = "ScrollBar";
- base.Add(scrollBar);
- if (hideScrollbar)
- {
- scrollBar.Hide();
- }
- else
+ if (scrollBar != null)
{
- scrollBar.Show();
- }
+ scrollBar.Name = "ScrollBar";
+ base.Add(scrollBar);
- SetScrollbar();
+ if (hideScrollbar)
+ {
+ scrollBar.Hide();
+ }
+ else
+ {
+ scrollBar.Show();
+ }
+
+ SetScrollbar();
+ }
}
}
/// <summary>
- /// [Draft] Always hide Scrollbar.
+ /// Always hide Scrollbar.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
- public bool HideScrollBar
+ /// <since_tizen> 8 </since_tizen>
+ public bool HideScrollbar
{
get
{
/// <summary>
/// Container which has content of ScrollableBase.
/// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public View ContentContainer { get; private set; }
/// <summary>
/// Set the layout on this View. Replaces any existing Layout.
/// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public new LayoutItem Layout
{
get
/// <summary>
/// List of children of Container.
/// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public new List<View> Children
{
get
/// <summary>
/// Deceleration rate of scrolling by finger.
- /// Rate should be 0 < rate < 1.
+ /// Rate should be bigger than 0 and smaller than 1.
+ /// Default value is 0.998f;
/// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public float DecelerationRate
{
get
}
set
{
- decelerationRate = value;
+ decelerationRate = (value < 1 && value > 0) ? value : decelerationRate;
logValueOfDeceleration = (float)Math.Log(value);
}
}
public float DecelerationThreshold { get; set; } = 0.1f;
/// <summary>
- /// Page will be changed when velocity of panning is over threshold.
+ /// Scrolling event will be thrown when this amount of scroll positino is changed.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public float PageFlickThreshold { get; set; } = 0.4f;
+ public float ScrollingEventThreshold
+ {
+ get
+ {
+ return mScrollingEventThreshold;
+ }
+ set
+ {
+ if (mScrollingEventThreshold != value && value > 0)
+ {
+ ContentContainer.RemovePropertyNotification(propertyNotification);
+ propertyNotification = ContentContainer.AddPropertyNotification("position", PropertyCondition.Step(value));
+ propertyNotification.Notified += OnPropertyChanged;
+ mScrollingEventThreshold = value;
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Page will be changed when velocity of panning is over threshold.
+ /// The unit of threshold is pixel per milisec.
+ /// </summary>
+ /// <since_tizen> 8 </since_tizen>
+ public float PageFlickThreshold
+ {
+ get
+ {
+ return mPageFlickThreshold;
+ }
+ set
+ {
+ mPageFlickThreshold = value >= 0f ? value : mPageFlickThreshold;
+ }
+ }
/// <summary>
/// Alphafunction for scroll animation.
private float ratioOfScreenWidthToCompleteScroll = 0.5f;
private float totalDisplacementForPan = 0.0f;
private Size previousContainerSize = new Size();
+ private Size previousSize = new Size();
private PropertyNotification propertyNotification;
private float noticeAnimationEndBeforePosition = 0.0f;
private bool readyToNotice = false;
+
+ /// <summary>
+ /// Notice before animation is finished.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
// Let's consider more whether this needs to be set as protected.
public float NoticeAnimationEndBeforePosition { get => noticeAnimationEndBeforePosition; set => noticeAnimationEndBeforePosition = value; }
-
// Let's consider more whether this needs to be set as protected.
private float finalTargetPosition;
private float logValueOfDeceleration = 0.0f;
private float decelerationRate = 0.0f;
+ private View mVerticalTopShadowView;
+ private View mVerticalBottomShadowView;
+ private const int mVerticalShadowScaleHeightLimit = 64 * 3;
+ private const int mVerticalShadowAnimationDuration = 300;
+ private Animation mVerticalShadowAnimation;
+ private bool isVerticalShadowShown = false;
+ private float mStartShowShadowDisplacement;
+
/// <summary>
- /// [Draft] Constructor
+ /// Default Constructor
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public ScrollableBase() : base()
{
DecelerationRate = 0.998f;
Layout = new AbsoluteLayout() { SetPositionByLayout = false },
};
ContentContainer.Relayout += OnScrollingChildRelayout;
- propertyNotification = ContentContainer.AddPropertyNotification("position", PropertyCondition.Step(1.0f));
+ propertyNotification = ContentContainer.AddPropertyNotification("position", PropertyCondition.Step(mScrollingEventThreshold));
propertyNotification.Notified += OnPropertyChanged;
base.Add(ContentContainer);
};
mInterruptTouchingChild.TouchEvent += OnIterruptTouchingChildTouched;
Scrollbar = new Scrollbar();
+
+ //Show vertical shadow when panning down (or up) on the scroll top (or end).
+ mVerticalTopShadowView = new View
+ {
+ BackgroundImage = StyleManager.GetFrameworkResourcePath("nui_component_default_scroll_over_shooting_top.png"),
+ Opacity = 1.0f,
+ SizeHeight = 0.0f,
+ PositionUsesPivotPoint = true,
+ ParentOrigin = NUI.ParentOrigin.TopCenter,
+ PivotPoint = NUI.PivotPoint.TopCenter,
+ };
+ mVerticalBottomShadowView = new View
+ {
+ BackgroundImage = StyleManager.GetFrameworkResourcePath("nui_component_default_scroll_over_shooting_bottom.png"),
+ Opacity = 1.0f,
+ SizeHeight = 0.0f,
+ PositionUsesPivotPoint = true,
+ ParentOrigin = NUI.ParentOrigin.BottomCenter,
+ PivotPoint = NUI.PivotPoint.BottomCenter,
+ };
+
+ AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "ScrollableBase");
}
private bool OnIterruptTouchingChildTouched(object source, View.TouchEventArgs args)
/// Called after a child has been added to the owning view.
/// </summary>
/// <param name="view">The child which has been added.</param>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public override void Add(View view)
{
ContentContainer.Add(view);
/// Called after a child has been removed from the owning view.
/// </summary>
/// <param name="view">The child which has been removed.</param>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public override void Remove(View view)
{
if (SnapToPage && CurrentPage == Children.IndexOf(view) && CurrentPage == Children.Count - 1)
private void OnScrollingChildRelayout(object source, EventArgs args)
{
// Size is changed. Calculate maxScrollDistance.
- bool isSizeChanged = previousContainerSize.Width != ContentContainer.Size.Width || previousContainerSize.Height != ContentContainer.Size.Height;
+ bool isSizeChanged = previousContainerSize.Width != ContentContainer.Size.Width || previousContainerSize.Height != ContentContainer.Size.Height
+ || previousSize.Width != Size.Width || previousSize.Height != Size.Height;
if (isSizeChanged)
{
}
previousContainerSize = ContentContainer.Size;
+ previousSize = Size;
}
/// <summary>
- /// The composition of a Scrollbar can vary depending on how you use ScrollableBase.
+ /// The composition of a Scrollbar can vary depending on how you use ScrollableBase.
/// Set the composition that will go into the ScrollableBase according to your ScrollableBase.
/// </summary>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
+ /// <since_tizen> 8 </since_tizen>
[EditorBrowsable(EditorBrowsableState.Never)]
protected virtual void SetScrollbar()
{
/// Scrolls to the item at the specified index.
/// </summary>
/// <param name="index">Index of item.</param>
- /// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public void ScrollToIndex(int index)
{
if (ContentContainer.ChildCount - 1 < index || index < 0)
float contentLength = isHorizontal ? ContentContainer.Size.Width : ContentContainer.Size.Height;
float currentPosition = isHorizontal ? ContentContainer.CurrentPosition.X : ContentContainer.CurrentPosition.Y;
- scrollBar.Update(contentLength, Math.Abs(currentPosition));
+ scrollBar?.Update(contentLength, Math.Abs(currentPosition));
CheckPreReachedTargetPosition();
}
/// </summary>
/// <param name="position">Destination.</param>
/// <param name="animate">Scroll with or without animation</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
+ /// <since_tizen> 8 </since_tizen>
public void ScrollTo(float position, bool animate)
{
float currentPositionX = ContentContainer.CurrentPosition.X != 0 ? ContentContainer.CurrentPosition.X : ContentContainer.Position.X;
{
ContentContainer.PositionY = finalTargetPosition;
}
-
}
}
if (type == DisposeTypes.Explicit)
{
+ StopVerticalShadowAnimation();
StopScroll();
if (mPanGestureDetector != null)
mPanGestureDetector.Dispose();
mPanGestureDetector = null;
}
+
+ propertyNotification.Dispose();
}
base.Dispose(type);
}
AnimateChildTo(ScrollDuration, destinationX);
}
+ private void AttachShadowView()
+ {
+ // stop animation if necessary.
+ StopVerticalShadowAnimation();
+
+ base.Add(mVerticalTopShadowView);
+ base.Add(mVerticalBottomShadowView);
+
+ mVerticalTopShadowView.Size = new Size(SizeWidth, 0.0f);
+ mVerticalTopShadowView.Opacity = 1.0f;
+
+ mVerticalBottomShadowView.Size = new Size(SizeWidth, 0.0f);
+ mVerticalBottomShadowView.Opacity = 1.0f;
+
+ // at the beginning, height of vertical shadow is 0, so it is invisible.
+ isVerticalShadowShown = false;
+ }
+
+ private void DragVerticalShadow(float displacement)
+ {
+ if ((int)displacement > 0) // downwards
+ {
+ // check if reaching at the top.
+ if ((int)finalTargetPosition != 0)
+ return;
+
+ // save start displacement, and re-calculate displacement.
+ if (!isVerticalShadowShown)
+ {
+ mStartShowShadowDisplacement = displacement;
+ }
+ isVerticalShadowShown = true;
+
+ float newDisplacement = displacement < mStartShowShadowDisplacement ? 0 : displacement - mStartShowShadowDisplacement;
+
+ // scale limit of width is 60%.
+ float widthScale = newDisplacement / mVerticalShadowScaleHeightLimit;
+ mVerticalTopShadowView.SizeWidth = widthScale > 0.6f ? SizeWidth * 0.4f : SizeWidth * (1.0f - widthScale);
+
+ // scale limit of height is 300%.
+ mVerticalTopShadowView.SizeHeight = newDisplacement > mVerticalShadowScaleHeightLimit ? mVerticalShadowScaleHeightLimit : newDisplacement;
+ }
+ else if ((int)displacement < 0) // upwards
+ {
+ // check if reaching at the bottom.
+ if (-(int)finalTargetPosition != (int)maxScrollDistance)
+ return;
+
+ // save start displacement, and re-calculate displacement.
+ if (!isVerticalShadowShown)
+ {
+ mStartShowShadowDisplacement = displacement;
+ }
+ isVerticalShadowShown = true;
+
+ float newDisplacement = mStartShowShadowDisplacement < displacement ? 0 : mStartShowShadowDisplacement - displacement;
+
+ // scale limit of width is 60%.
+ float widthScale = newDisplacement / mVerticalShadowScaleHeightLimit;
+ mVerticalBottomShadowView.SizeWidth = widthScale > 0.6f ? SizeWidth * 0.4f : SizeWidth * (1.0f - widthScale);
+
+ // scale limit of height is 300%.
+ mVerticalBottomShadowView.SizeHeight = newDisplacement > mVerticalShadowScaleHeightLimit ? mVerticalShadowScaleHeightLimit : newDisplacement;
+ }
+ else
+ {
+ // if total displacement is 0, shadow would become invisible.
+ isVerticalShadowShown = false;
+ }
+ }
+
+ private void PlayVerticalShadowAnimation()
+ {
+ // stop animation if necessary.
+ StopVerticalShadowAnimation();
+
+ if (mVerticalShadowAnimation == null)
+ {
+ mVerticalShadowAnimation = new Animation(mVerticalShadowAnimationDuration);
+ mVerticalShadowAnimation.Finished += OnVerticalShadowAnimationFinished;
+ }
+
+ View targetView = totalDisplacementForPan < 0 ? mVerticalBottomShadowView : mVerticalTopShadowView;
+ mVerticalShadowAnimation.AnimateTo(targetView, "SizeWidth", SizeWidth);
+ mVerticalShadowAnimation.AnimateTo(targetView, "SizeHeight", 0.0f);
+ mVerticalShadowAnimation.AnimateTo(targetView, "Opacity", 0.0f);
+ mVerticalShadowAnimation.Play();
+ }
+
+ private void StopVerticalShadowAnimation()
+ {
+ if (mVerticalShadowAnimation == null || mVerticalShadowAnimation.State != Animation.States.Playing)
+ return;
+
+ Debug.WriteLineIf(LayoutDebugScrollableBase, "gesture finished. Stop Vertical Shadow Animation Playing.");
+ mVerticalShadowAnimation.Stop(Animation.EndActions.Cancel);
+ OnVerticalShadowAnimationFinished(null, null);
+ mVerticalShadowAnimation.Clear();
+ }
+
+ private void OnVerticalShadowAnimationFinished(object sender, EventArgs e)
+ {
+ base.Remove(mVerticalTopShadowView);
+ base.Remove(mVerticalBottomShadowView);
+
+ mVerticalTopShadowView.Size = new Size(SizeWidth, 0.0f);
+ mVerticalBottomShadowView.Size = new Size(SizeWidth, 0.0f);
+
+ // after animation finished, height & opacity of vertical shadow both are 0, so it is invisible.
+ isVerticalShadowShown = false;
+ }
+
private void OnPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
{
+ OnPanGesture(e.PanGesture);
+ }
+
+ private void OnPanGesture(PanGesture panGesture)
+ {
if (SnapToPage && scrollAnimation != null && scrollAnimation.State == Animation.States.Playing)
{
return;
}
- if (e.PanGesture.State == Gesture.StateType.Started)
+ if (panGesture.State == Gesture.StateType.Started)
{
readyToNotice = false;
base.Add(mInterruptTouchingChild);
+ AttachShadowView();
Debug.WriteLineIf(LayoutDebugScrollableBase, "Gesture Start");
if (scrolling && !SnapToPage)
{
totalDisplacementForPan = 0.0f;
OnScrollDragStarted();
}
- else if (e.PanGesture.State == Gesture.StateType.Continuing)
+ else if (panGesture.State == Gesture.StateType.Continuing)
{
if (ScrollingDirection == Direction.Horizontal)
{
- ScrollBy(e.PanGesture.Displacement.X, false);
- totalDisplacementForPan += e.PanGesture.Displacement.X;
+ ScrollBy(panGesture.Displacement.X, false);
+ totalDisplacementForPan += panGesture.Displacement.X;
}
else
{
- ScrollBy(e.PanGesture.Displacement.Y, false);
- totalDisplacementForPan += e.PanGesture.Displacement.Y;
+ // if vertical shadow is shown, does not scroll.
+ if (!isVerticalShadowShown)
+ {
+ ScrollBy(panGesture.Displacement.Y, false);
+ }
+ totalDisplacementForPan += panGesture.Displacement.Y;
+ DragVerticalShadow(totalDisplacementForPan);
}
Debug.WriteLineIf(LayoutDebugScrollableBase, "OnPanGestureDetected Continue totalDisplacementForPan:" + totalDisplacementForPan);
}
- else if (e.PanGesture.State == Gesture.StateType.Finished)
+ else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
{
+ PlayVerticalShadowAnimation();
OnScrollDragEnded();
StopScroll(); // Will replace previous animation so will stop existing one.
scrollAnimation.Finished += ScrollAnimationFinished;
}
+ float panVelocity = (ScrollingDirection == Direction.Horizontal) ? panGesture.Velocity.X : panGesture.Velocity.Y;
+
if (SnapToPage)
{
- PageSnap((ScrollingDirection == Direction.Horizontal) ? e.PanGesture.Velocity.X : e.PanGesture.Velocity.Y);
+ PageSnap(panVelocity);
}
else
{
- Decelerating((ScrollingDirection == Direction.Horizontal) ? e.PanGesture.Velocity.X : e.PanGesture.Velocity.Y);
+ if (panVelocity == 0)
+ {
+ float currentScrollPosition = (ScrollingDirection == Direction.Horizontal ? ContentContainer.CurrentPosition.X : ContentContainer.CurrentPosition.Y);
+ scrollAnimation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.Linear);
+ scrollAnimation.Duration = 0;
+ scrollAnimation.AnimateTo(ContentContainer, (ScrollingDirection == Direction.Horizontal) ? "PositionX" : "PositionY", currentScrollPosition);
+ scrollAnimation.Play();
+ }
+ else
+ {
+ Decelerating(panVelocity, scrollAnimation);
+ }
}
totalDisplacementForPan = 0;
}
}
+ internal override bool OnAccessibilityPan(PanGesture gestures)
+ {
+ if (SnapToPage && scrollAnimation != null && scrollAnimation.State == Animation.States.Playing)
+ {
+ return false;
+ }
+
+ OnPanGesture(gestures);
+ return true;
+ }
+
private float CustomScrollAlphaFunction(float progress)
{
if (panAnimationDelta == 0)
}
}
- private void Decelerating(float velocity)
+ /// <summary>
+ /// you can override it to custom your decelerating
+ /// </summary>
+ /// <param name="velocity">Velocity of current pan.</param>
+ /// <param name="animation">Scroll animation.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void Decelerating(float velocity, Animation animation)
{
// Decelerating using deceleration equation ===========
//
// X(∞) = V0 * d / (1 - d); <-- Result using inifit T can be final position because T is tending to infinity.
//
// Because of final T is tending to inifity, we should use threshold value to finish.
- // Final T = log(-threshold * log d / |V0| ) / log d;
+ // Final T = log(-threshold * log d / |V0| ) / log d;
velocityOfLastPan = Math.Abs(velocity);
finalTargetPosition = destination;
customScrollAlphaFunction = new UserAlphaFunctionDelegate(CustomScrollAlphaFunction);
- scrollAnimation.DefaultAlphaFunction = new AlphaFunction(customScrollAlphaFunction);
+ animation.DefaultAlphaFunction = new AlphaFunction(customScrollAlphaFunction);
GC.KeepAlive(customScrollAlphaFunction);
- scrollAnimation.Duration = (int)panAnimationDuration;
- scrollAnimation.AnimateTo(ContentContainer, (ScrollingDirection == Direction.Horizontal) ? "PositionX" : "PositionY", destination);
- scrollAnimation.Play();
- }
-
- protected void OnTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e)
- {
-
+ animation.Duration = (int)panAnimationDuration;
+ animation.AnimateTo(ContentContainer, (ScrollingDirection == Direction.Horizontal) ? "PositionX" : "PositionY", destination);
+ animation.Play();
}
private void ScrollAnimationFinished(object sender, EventArgs e)
return position;
}
+ /// <summary>
+ /// Scroll position given to ScrollTo.
+ /// This is the position in the opposite direction to the position of ContentContainer.
+ /// </summary>
+ /// <since_tizen> 8 </since_tizen>
+ public Position ScrollPosition
+ {
+ get
+ {
+ return new Position(-ContentContainer.Position);
+ }
+ }
+
+ /// <summary>
+ /// Current scroll position in the middle of ScrollTo animation.
+ /// This is the position in the opposite direction to the current position of ContentContainer.
+ /// </summary>
+ /// <since_tizen> 8 </since_tizen>
+ public Position ScrollCurrentPosition
+ {
+ get
+ {
+ return new Position(-ContentContainer.CurrentPosition);
+ }
+ }
+
+ /// <summary>
+ /// Remove all children in ContentContainer.
+ /// </summary>
+ /// <param name="dispose">If true, removed child is disposed.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RemoveAllChildren(bool dispose = false)
+ {
+ RecursiveRemoveChildren(ContentContainer, dispose);
+ }
+
+ private void RecursiveRemoveChildren(View parent, bool dispose)
+ {
+ if (parent == null)
+ {
+ return;
+ }
+ int maxChild = (int)parent.GetChildCount();
+ for (int i = maxChild - 1; i >= 0; --i)
+ {
+ View child = parent.GetChildAt((uint)i);
+ if (child == null)
+ {
+ continue;
+ }
+ RecursiveRemoveChildren(child, dispose);
+ parent.Remove(child);
+ if (dispose)
+ {
+ child.Dispose();
+ }
+ }
+ }
+
}
} // namespace