From 75034433e28c31e99ce28a2013c3967a7e165bf1 Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Thu, 24 Apr 2014 11:14:06 +0100 Subject: [PATCH] Improve fast scrolling performance in ItemView Change-Id: I4105319807124bc6c3a5218612eecae4f3685d10 Signed-off-by: David Steele --- .../controls/scroll-bar/scroll-bar-impl.cpp | 54 ++++++++++++++++++++-- .../internal/controls/scroll-bar/scroll-bar-impl.h | 13 +++++- .../scrollable/item-view/item-view-impl.cpp | 28 ++++++++--- .../controls/scrollable/item-view/item-view-impl.h | 23 ++++++++- .../controls/scrollable/item-view/grid-layout.cpp | 2 +- 5 files changed, 106 insertions(+), 14 deletions(-) diff --git a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp index 7ae50af..21582a0 100755 --- a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp +++ b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp @@ -15,6 +15,7 @@ // #include +#include using namespace Dali; @@ -26,6 +27,7 @@ const Vector4 DEFAULT_INDICATOR_NINE_PATCH_BORDER(0.0f, 12.0f, 14.0f, 14.0f); const float DEFAULT_SLIDER_DEPTH(1.0f); const float INDICATOR_SHOW_TIME(0.5f); const float INDICATOR_HIDE_TIME(0.5f); +const float DEFAULT_PAN_GESTURE_PROCESS_TIME(16.7f); // 16.7 milliseconds, i.e. one frame /** * Indicator size constraint @@ -126,7 +128,9 @@ TypeRegistration mType( typeid(Toolkit::ScrollBar), typeid(Toolkit::Control), Cr } ScrollBar::ScrollBar() -: mScrollStart(0.0f) +: mScrollStart(0.0f), + mIsPanning(false), + mCurrentScrollPosition(0.0f) { } @@ -274,6 +278,21 @@ void ScrollBar::Hide() mAnimation.Play(); } +bool ScrollBar::OnPanGestureProcessTick() +{ + // Update the scroll position property. + mScrollPositionObject.SetProperty( Toolkit::ScrollConnector::SCROLL_POSITION, mCurrentScrollPosition ); + + Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(Self().GetParent()); + if(itemView) + { + // Refresh ItemView immediately when the scroll position is changed. + GetImpl(itemView).DoRefresh(mCurrentScrollPosition, false); // No need to cache extra items. + } + + return true; +} + void ScrollBar::OnPan( PanGesture gesture ) { if(mScrollPositionObject) @@ -282,9 +301,19 @@ void ScrollBar::OnPan( PanGesture gesture ) { case Gesture::Started: { + if( !mTimer ) + { + // Make sure the pan gesture is only being processed once per frame. + mTimer = Timer::New( DEFAULT_PAN_GESTURE_PROCESS_TIME ); + mTimer.TickSignal().Connect( this, &ScrollBar::OnPanGestureProcessTick ); + mTimer.Start(); + } + Show(); mScrollStart = mScrollPositionObject.GetProperty( Toolkit::ScrollConnector::SCROLL_POSITION ); mGestureDisplacement = Vector3::ZERO; + mIsPanning = true; + break; } case Gesture::Continuing: @@ -294,16 +323,33 @@ void ScrollBar::OnPan( PanGesture gesture ) Vector3 span = Self().GetCurrentSize() - mIndicator.GetCurrentSize(); const float domainSize = fabs(mScrollConnector.GetMaxLimit() - mScrollConnector.GetMinLimit()); - float position = mScrollStart - mGestureDisplacement.y * domainSize / span.y; - position = std::min(mScrollConnector.GetMaxLimit(), std::max(position, mScrollConnector.GetMinLimit())); - mScrollPositionObject.SetProperty( Toolkit::ScrollConnector::SCROLL_POSITION, position ); + mCurrentScrollPosition = mScrollStart - mGestureDisplacement.y * domainSize / span.y; + mCurrentScrollPosition = std::min(mScrollConnector.GetMaxLimit(), std::max(mCurrentScrollPosition, mScrollConnector.GetMinLimit())); + break; } default: { + mIsPanning = false; + + if( mTimer ) + { + // Destroy the timer when pan gesture is finished. + mTimer.Stop(); + mTimer.TickSignal().Disconnect( this, &ScrollBar::OnPanGestureProcessTick ); + mTimer.Reset(); + } + break; } } + + Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(Self().GetParent()); + if(itemView) + { + // Disable automatic refresh in ItemView during fast scrolling + GetImpl(itemView).SetRefreshEnabled(!mIsPanning); + } } } diff --git a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h index c938c7e..909e4fe 100755 --- a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h +++ b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h @@ -141,6 +141,12 @@ private: */ void OnScrollPositionNotified(PropertyNotification& source); + /** + * Process the pan gesture per predefined timeout until the gesture is finished. + * @return True if the timer should be kept running. + */ + bool OnPanGestureProcessTick(); + private: Constrainable mScrollPositionObject; ///< From mScrollConnector @@ -149,9 +155,14 @@ private: ImageActor mIndicator; ///< Image of scroll indicator. Animation mAnimation; ///< Scroll indicator Show/Hide Animation. - float mScrollStart; ///< Scroll Start position (start of drag) + float mScrollStart; ///< Scroll Start position (start of drag) Vector3 mGestureDisplacement; ///< Gesture Displacement. + bool mIsPanning; ///< Whether the scroll bar is being panned. + float mCurrentScrollPosition; ///< The current scroll position updated by the pan gesture + + Timer mTimer; ///< The timer to process the pan gesture after the gesture is started. + Property::Index mPropertyIndicatorPosition; ///< Indicatore Position ("indicator-position") PropertyNotification mPositionNotification; ///< Stores the property notification used for scroll position changes diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp index 5caa208..001291f 100644 --- a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp @@ -410,7 +410,8 @@ ItemView::ItemView(ItemFactory& factory) mScrollOvershoot(0.0f), mIsFlicking(false), mGestureState(Gesture::Clear), - mAddingItems(false) + mAddingItems(false), + mRefreshEnabled(true) { SetRequiresMouseWheelEvents(true); SetKeyboardNavigationSupport(true); @@ -565,7 +566,7 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz } // Refresh the new layout - ItemRange range = GetItemRange(*mActiveLayout, targetSize, true/*reserve extra*/); + ItemRange range = GetItemRange(*mActiveLayout, targetSize, GetCurrentLayoutPosition(0), true/*reserve extra*/); AddActorsWithinRange( range, durationSeconds ); // Scroll to an appropriate layout position @@ -636,14 +637,22 @@ AlphaFunction ItemView::GetDefaultAlphaFunction() const void ItemView::OnRefreshNotification(PropertyNotification& source) { + if(mRefreshEnabled) + { + // Only refresh the cache during normal scrolling + DoRefresh(GetCurrentLayoutPosition(0), true); + } +} + +void ItemView::DoRefresh(float currentLayoutPosition, bool cacheExtra) +{ if (mActiveLayout) { - ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, true/*reserve extra*/); + ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, currentLayoutPosition, cacheExtra/*reserve extra*/); RemoveActorsOutsideRange( range ); AddActorsWithinRange( range, 0.0f/*immediate*/ ); - Vector3 currentScrollPosition = GetCurrentScrollPosition(); - mScrollUpdatedSignalV2.Emit( currentScrollPosition ); + mScrollUpdatedSignalV2.Emit( Vector3(0.0f, currentLayoutPosition, 0.0f) ); } } @@ -714,6 +723,11 @@ float ItemView::GetRefreshInterval() const return mRefreshIntervalLayoutPositions; } +void ItemView::SetRefreshEnabled(bool enabled) +{ + mRefreshEnabled = enabled; +} + Actor ItemView::GetItem(unsigned int itemId) const { Actor actor; @@ -1030,13 +1044,13 @@ void ItemView::SetupActor( Item item, float durationSeconds ) } } -ItemRange ItemView::GetItemRange(ItemLayout& layout, const Vector3& layoutSize, bool reserveExtra) +ItemRange ItemView::GetItemRange(ItemLayout& layout, const Vector3& layoutSize, float layoutPosition, bool reserveExtra) { unsigned int itemCount = mItemFactory.GetNumberOfItems(); ItemRange available(0u, itemCount); - ItemRange range = layout.GetItemsWithinArea( GetCurrentLayoutPosition(0), layoutSize ); + ItemRange range = layout.GetItemsWithinArea( layoutPosition, layoutSize ); if (reserveExtra) { diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h index 038a567..5f42a61 100644 --- a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h +++ b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h @@ -243,6 +243,25 @@ public: */ void ScrollTo(const Vector3& position, float duration); + /** + * @brief Set whether to enable automatic refresh or not. When refresh is disabled, + * ItemView will not automatically refresh the cache in the given interval when the + * layout position is changed. This is useful in some cases, for example, automatic + * refresh is not needed during fast scrolling, otherwise it will cache unneeded + * items when the layout position changes quickly. + * + * @param[in] enabled True to enable automatic refresh or false to disable it. + */ + void SetRefreshEnabled(bool enabled); + + /** + * @brief Helper to perform the refresh. + * + * @param[in] currentLayoutPosition The current layout position. + * @param[in] cacheExtra Whether to cache extra items during refresh. + */ + void DoRefresh(float currentLayoutPosition, bool cacheExtra); + private: /** @@ -379,7 +398,7 @@ private: * @param[in] range The range of items. * @param[in] reserveExtra True if reserve items should be included. */ - ItemRange GetItemRange(ItemLayout& layout, const Vector3& layoutSize, bool reserveExtra); + ItemRange GetItemRange(ItemLayout& layout, const Vector3& layoutSize, float layoutPosition, bool reserveExtra); // Input Handling @@ -543,6 +562,8 @@ private: Property::Index mPropertyPosition; ///< The physical position of the first item within the layout Property::Index mPropertyMinimumLayoutPosition; ///< The minimum valid layout position in the layout. Property::Index mPropertyScrollSpeed; ///< The current scroll speed of item view + + bool mRefreshEnabled; ///< Whether to refresh the cache automatically }; } // namespace Internal diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/grid-layout.cpp b/dali-toolkit/public-api/controls/scrollable/item-view/grid-layout.cpp index b10700b..eb3bfd8 100644 --- a/dali-toolkit/public-api/controls/scrollable/item-view/grid-layout.cpp +++ b/dali-toolkit/public-api/controls/scrollable/item-view/grid-layout.cpp @@ -500,7 +500,7 @@ ItemRange GridLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layout int firstVisibleItem = -(static_cast(firstItemPosition / mImpl->mNumberOfColumns)) * mImpl->mNumberOfColumns; int firstItemIndex = std::max(0, firstVisibleItem - static_cast(mImpl->mNumberOfColumns)); - int lastItemIndex = std::max(0, firstVisibleItem + (itemsPerPage - 1)); + int lastItemIndex = std::max(0, firstVisibleItem + itemsPerPage); return ItemRange(firstItemIndex, lastItemIndex); } -- 2.7.4