diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2016-11-28 10:57:45 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2016-12-14 19:46:05 +0000 |
commit | d49ab00f2b9c99da48d9ddef2b0627a86d54b95e (patch) | |
tree | dde0f77d4353f3cc6adfef085ba19ab78ac7bc57 /src | |
parent | bc6414762e48f12f6680ee6bb667c49c64fbd32a (diff) |
SwipeDelegate: transition swipe.position
Previously the value of swipe.position jumped on mouse/touch release,
or when open() or close() was called. Transitioning the swipe.position
value smoothly to the target value makes it possible to use it as
opacity/scale/etc. for the side items.
Notice that this is backwards compatible with the old behavior. If no
transition is set, the value jumps the same way it did before. In that
case, Behavior on x makes the movement smooth.
Task-number: QTBUG-57242
Change-Id: Id9c06b5b08fa73f2f575787e16dc6e20e4ccb545
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/imports/controls/SwipeDelegate.qml | 18 | ||||
-rw-r--r-- | src/imports/controls/material/SwipeDelegate.qml | 18 | ||||
-rw-r--r-- | src/imports/controls/universal/SwipeDelegate.qml | 18 | ||||
-rw-r--r-- | src/quicktemplates2/qquickswipe_p.h | 8 | ||||
-rw-r--r-- | src/quicktemplates2/qquickswipedelegate.cpp | 109 |
5 files changed, 110 insertions, 61 deletions
diff --git a/src/imports/controls/SwipeDelegate.qml b/src/imports/controls/SwipeDelegate.qml index 099ee117..1c900b52 100644 --- a/src/imports/controls/SwipeDelegate.qml +++ b/src/imports/controls/SwipeDelegate.qml @@ -52,6 +52,8 @@ T.SwipeDelegate { padding: 12 spacing: 12 + swipe.rebound: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } } + contentItem: Text { leftPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 rightPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 @@ -63,27 +65,11 @@ T.SwipeDelegate { visible: control.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } background: Rectangle { color: control.visualFocus ? (control.down ? Default.focusPressedColor : Default.delegateFocusColor) : (control.down ? Default.delegatePressedColor : Default.backgroundColor) - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } } diff --git a/src/imports/controls/material/SwipeDelegate.qml b/src/imports/controls/material/SwipeDelegate.qml index c6240910..4247ddf1 100644 --- a/src/imports/controls/material/SwipeDelegate.qml +++ b/src/imports/controls/material/SwipeDelegate.qml @@ -54,6 +54,8 @@ T.SwipeDelegate { bottomPadding: 8 spacing: 16 + swipe.rebound: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } } + contentItem: Text { leftPadding: !control.mirrored ? (control.indicator ? control.indicator.width + control.spacing : 0) : 0 rightPadding: control.mirrored ? (control.indicator ? control.indicator.width + control.spacing : 0) : 0 @@ -65,14 +67,6 @@ T.SwipeDelegate { visible: control.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } background: Rectangle { @@ -98,13 +92,5 @@ T.SwipeDelegate { color: control.Material.rippleColor enabled: control.swipe.position === 0 } - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } } diff --git a/src/imports/controls/universal/SwipeDelegate.qml b/src/imports/controls/universal/SwipeDelegate.qml index 0b888e70..193d1ab1 100644 --- a/src/imports/controls/universal/SwipeDelegate.qml +++ b/src/imports/controls/universal/SwipeDelegate.qml @@ -54,6 +54,8 @@ T.SwipeDelegate { topPadding: padding - 1 bottomPadding: padding + 1 + swipe.rebound: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } } + contentItem: Text { leftPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 rightPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 @@ -68,14 +70,6 @@ T.SwipeDelegate { opacity: enabled ? 1.0 : 0.2 color: control.Universal.foreground - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } background: Rectangle { @@ -94,13 +88,5 @@ T.SwipeDelegate { opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6 } } - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } } diff --git a/src/quicktemplates2/qquickswipe_p.h b/src/quicktemplates2/qquickswipe_p.h index bedf5b1f..2201bb06 100644 --- a/src/quicktemplates2/qquickswipe_p.h +++ b/src/quicktemplates2/qquickswipe_p.h @@ -56,12 +56,13 @@ QT_BEGIN_NAMESPACE class QQmlComponent; class QQuickItem; +class QQuickTransition; class QQuickSwipePrivate; class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipe : public QObject { Q_OBJECT - Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged FINAL) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) // REVISION 2 Q_PROPERTY(QQmlComponent *left READ left WRITE setLeft NOTIFY leftChanged FINAL) @@ -70,6 +71,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipe : public QObject Q_PROPERTY(QQuickItem *leftItem READ leftItem NOTIFY leftItemChanged FINAL) Q_PROPERTY(QQuickItem *behindItem READ behindItem NOTIFY behindItemChanged FINAL) Q_PROPERTY(QQuickItem *rightItem READ rightItem NOTIFY rightItemChanged FINAL) + Q_PROPERTY(QQuickTransition *rebound READ rebound WRITE setRebound NOTIFY reboundChanged FINAL) // REVISION 2 public: explicit QQuickSwipe(QQuickSwipeDelegate *control); @@ -101,6 +103,9 @@ public: QQuickItem *rightItem() const; void setRightItem(QQuickItem *item); + QQuickTransition *rebound() const; + void setRebound(QQuickTransition *rebound); + Q_REVISION(2) Q_INVOKABLE void open(QQuickSwipeDelegate::Side side); Q_REVISION(1) Q_INVOKABLE void close(); @@ -115,6 +120,7 @@ Q_SIGNALS: void leftItemChanged(); void behindItemChanged(); void rightItemChanged(); + /*Q_REVISION(2)*/ void reboundChanged(); private: Q_DISABLE_COPY(QQuickSwipe) diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp index 2f7e7382..5504dfc8 100644 --- a/src/quicktemplates2/qquickswipedelegate.cpp +++ b/src/quicktemplates2/qquickswipedelegate.cpp @@ -44,6 +44,9 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtGui/qpa/qplatformtheme.h> #include <QtQml/qqmlinfo.h> +#include <QtQuick/private/qquickanimation_p.h> +#include <QtQuick/private/qquicktransition_p.h> +#include <QtQuick/private/qquicktransitionmanager_p_p.h> QT_BEGIN_NAMESPACE @@ -113,6 +116,48 @@ namespace { }; } +class QQuickSwipeTransitionManager : public QQuickTransitionManager +{ +public: + QQuickSwipeTransitionManager(QQuickSwipe *swipe); + + void transition(QQuickTransition *rebound, qreal position); + +protected: + void finished() override; + +private: + QQuickSwipe *m_swipe; +}; + +QQuickSwipeTransitionManager::QQuickSwipeTransitionManager(QQuickSwipe *swipe) + : m_swipe(swipe) +{ +} + +void QQuickSwipeTransitionManager::transition(QQuickTransition *rebound, qreal position) +{ + qmlExecuteDeferred(rebound); + + QQmlProperty defaultTarget(m_swipe, QLatin1String("position")); + QQmlListProperty<QQuickAbstractAnimation> animations = rebound->animations(); + const int count = animations.count(&animations); + for (int i = 0; i < count; ++i) { + QQuickAbstractAnimation *anim = animations.at(&animations, i); + anim->setDefaultTarget(defaultTarget); + } + + QList<QQuickStateAction> actions; + actions << QQuickStateAction(m_swipe, QLatin1String("position"), position); + QQuickTransitionManager::transition(actions, rebound, m_swipe); +} + +void QQuickSwipeTransitionManager::finished() +{ + const qreal pos = m_swipe->position(); + m_swipe->setComplete(qFuzzyCompare(qAbs(pos), 1.0)); +} + class QQuickSwipePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QQuickSwipe) @@ -130,7 +175,9 @@ public: right(nullptr), leftItem(nullptr), behindItem(nullptr), - rightItem(nullptr) + rightItem(nullptr), + rebound(nullptr), + transitionManager(nullptr) { } @@ -152,6 +199,9 @@ public: bool hasDelegates() const; + bool isTransitioning() const; + void transition(qreal position); + QQuickSwipeDelegate *control; // Same range as position, but is set before press events so that we can // keep track of which direction the user must swipe when using left and right delegates. @@ -169,6 +219,8 @@ public: QQuickItem *leftItem; QQuickItem *behindItem; QQuickItem *rightItem; + QQuickTransition *rebound; + QScopedPointer<QQuickSwipeTransitionManager> transitionManager; }; QQuickSwipePrivate *QQuickSwipePrivate::get(QQuickSwipe *swipe) @@ -358,6 +410,26 @@ bool QQuickSwipePrivate::hasDelegates() const return left || right || behind; } +bool QQuickSwipePrivate::isTransitioning() const +{ + return transitionManager && transitionManager->isRunning(); +} + +void QQuickSwipePrivate::transition(qreal position) +{ + Q_Q(QQuickSwipe); + if (!rebound) { + q->setPosition(position); + q->setComplete(qFuzzyCompare(qAbs(position), 1.0)); + return; + } + + if (!transitionManager) + transitionManager.reset(new QQuickSwipeTransitionManager(q)); + + transitionManager->transition(rebound, position); +} + QQuickSwipe::QQuickSwipe(QQuickSwipeDelegate *control) : QObject(*(new QQuickSwipePrivate(control))) { @@ -592,6 +664,22 @@ void QQuickSwipe::setEnabled(bool enabled) emit enabledChanged(); } +QQuickTransition *QQuickSwipe::rebound() const +{ + Q_D(const QQuickSwipe); + return d->rebound; +} + +void QQuickSwipe::setRebound(QQuickTransition *rebound) +{ + Q_D(QQuickSwipe); + if (rebound == d->rebound) + return; + + d->rebound = rebound; + emit reboundChanged(); +} + void QQuickSwipe::open(QQuickSwipeDelegate::Side side) { Q_D(QQuickSwipe); @@ -600,8 +688,7 @@ void QQuickSwipe::open(QQuickSwipeDelegate::Side side) || (!d->right && !d->behind && side == QQuickSwipeDelegate::Right)) return; - setPosition(side); - setComplete(true); + d->transition(side); d->wasComplete = true; d->velocityCalculator.reset(); d->positionBeforePress = d->position; @@ -610,8 +697,7 @@ void QQuickSwipe::open(QQuickSwipeDelegate::Side side) void QQuickSwipe::close() { Q_D(QQuickSwipe); - setPosition(0); - setComplete(false); + d->transition(0.0); d->wasComplete = false; d->positionBeforePress = 0.0; d->velocityCalculator.reset(); @@ -748,6 +834,8 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv position = distance > 0 ? normalizedDistance - 1.0 : normalizedDistance + 1.0; } + if (swipePrivate->isTransitioning()) + swipePrivate->transitionManager->cancel(); swipe.setPosition(position); } } else { @@ -794,17 +882,14 @@ bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *item, QMous const qreal swipeVelocity = swipePrivate->velocityCalculator.velocity().x(); if (swipePrivate->position > 0.5 || (swipePrivate->position > 0.0 && swipeVelocity > exposeVelocityThreshold)) { - swipe.setPosition(1.0); - swipe.setComplete(true); + swipePrivate->transition(1.0); swipePrivate->wasComplete = true; } else if (swipePrivate->position < -0.5 || (swipePrivate->position < 0.0 && swipeVelocity < -exposeVelocityThreshold)) { - swipe.setPosition(-1.0); - swipe.setComplete(true); + swipePrivate->transition(-1.0); swipePrivate->wasComplete = true; - } else { - swipe.setPosition(0.0); - swipe.setComplete(false); + } else if (!swipePrivate->isTransitioning()) { + swipePrivate->transition(0.0); swipePrivate->wasComplete = false; } |