Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickitemviewtransition.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <QtQuick/qquickitem.h>
7#include <QtQuick/private/qquicktransition_p.h>
8#include <QtQuick/private/qquicktransitionmanager_p_p.h>
9
11
14
15
17{
18public:
21
22 void startTransition(QQuickItemViewTransitionableItem *item, int index, QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem);
23
25 QQuickItemViewTransitionableItem *m_item;
29
30protected:
32};
33
34
42
44{
45 if (m_transitioner)
46 m_transitioner->runningJobs.remove(this);
47}
48
49void QQuickItemViewTransitionJob::startTransition(QQuickItemViewTransitionableItem *item, int index, QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem)
50{
51 if (type == QQuickItemViewTransitioner::NoTransition)
52 return;
53 if (!item) {
54 qWarning("startTransition(): invalid item");
55 return;
56 }
57 if (!transitioner) {
58 qWarning("startTransition(): invalid transitioner");
59 return;
60 }
61
62 QQuickTransition *trans = transitioner->transitionObject(type, isTargetItem);
63 if (!trans) {
64 qWarning("QQuickItemView: invalid view transition!");
65 return;
66 }
67
68 m_item = item;
69 m_transitioner = transitioner;
70 m_toPos = to;
71 m_type = type;
72 m_isTarget = isTargetItem;
73
75 static_cast<QQuickViewTransitionAttached*>(qmlAttachedPropertiesObject<QQuickViewTransitionAttached>(trans));
76 if (attached) {
77 attached->m_index = index;
78 attached->m_item = item->item;
79 attached->m_destination = to;
80 attached->m_targetIndexes = m_transitioner->targetIndexes(type);
81 attached->m_targetItems = m_transitioner->targetItems(type);
82 emit attached->indexChanged();
83 emit attached->itemChanged();
84 emit attached->destinationChanged();
85 emit attached->targetIndexesChanged();
86 emit attached->targetItemsChanged();
87 }
88
89 QQuickStateOperation::ActionList actions;
90 actions << QQuickStateAction(item->item, QLatin1String("x"), QVariant(to.x()));
91 actions << QQuickStateAction(item->item, QLatin1String("y"), QVariant(to.y()));
92
93 actions[0].fromValue = item->itemX();
94 actions[1].fromValue = item->itemY();
95 m_transitioner->runningJobs << this;
96 QQuickTransitionManager::transition(actions, trans, item->item);
97}
98
100{
101 QQuickTransitionManager::finished();
102
103 if (m_transitioner) {
104 RETURN_IF_DELETED(m_transitioner->finishedTransition(this, m_item));
105 m_transitioner = nullptr;
106 }
107
108 m_item = nullptr;
109 m_toPos.setX(0);
110 m_toPos.setY(0);
111 m_type = QQuickItemViewTransitioner::NoTransition;
112 m_isTarget = false;
113}
114
115
116QQuickItemViewTransitioner::QQuickItemViewTransitioner()
117 : populateTransition(nullptr)
118 , addTransition(nullptr), addDisplacedTransition(nullptr)
119 , moveTransition(nullptr), moveDisplacedTransition(nullptr)
120 , removeTransition(nullptr), removeDisplacedTransition(nullptr)
121 , displacedTransition(nullptr)
122 , changeListener(nullptr)
123 , usePopulateTransition(false)
124{
125}
126
127QQuickItemViewTransitioner::~QQuickItemViewTransitioner()
128{
129 typedef QSet<QQuickItemViewTransitionJob *>::iterator JobIt;
130
131 for (JobIt it = runningJobs.begin(), end = runningJobs.end(); it != end; ++it)
132 (*it)->m_transitioner = nullptr;
133}
134
135bool QQuickItemViewTransitioner::canTransition(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const
136{
137 if (!asTarget
138 && type != NoTransition && type != PopulateTransition
139 && displacedTransition && displacedTransition->enabled()) {
140 return true;
141 }
142
143 switch (type) {
144 case NoTransition:
145 break;
146 case PopulateTransition:
147 return usePopulateTransition
148 && populateTransition && populateTransition->enabled();
149 case AddTransition:
150 if (asTarget)
151 return addTransition && addTransition->enabled();
152 else
153 return addDisplacedTransition && addDisplacedTransition->enabled();
154 case MoveTransition:
155 if (asTarget)
156 return moveTransition && moveTransition->enabled();
157 else
158 return moveDisplacedTransition && moveDisplacedTransition->enabled();
159 case RemoveTransition:
160 if (asTarget)
161 return removeTransition && removeTransition->enabled();
162 else
163 return removeDisplacedTransition && removeDisplacedTransition->enabled();
164 }
165 return false;
166}
167
168void QQuickItemViewTransitioner::transitionNextReposition(QQuickItemViewTransitionableItem *item, QQuickItemViewTransitioner::TransitionType type, bool isTarget)
169{
170 item->setNextTransition(type, isTarget);
171}
172
173void QQuickItemViewTransitioner::addToTargetLists(QQuickItemViewTransitioner::TransitionType type, QQuickItemViewTransitionableItem *item, int index)
174{
175 switch (type) {
176 case NoTransition:
177 break;
178 case PopulateTransition:
179 case AddTransition:
180 addTransitionIndexes << index;
181 addTransitionTargets << item->item;
182 break;
183 case MoveTransition:
184 moveTransitionIndexes << index;
185 moveTransitionTargets << item->item;
186 break;
187 case RemoveTransition:
188 removeTransitionIndexes << index;
189 removeTransitionTargets << item->item;
190 break;
191 }
192}
193
194void QQuickItemViewTransitioner::resetTargetLists()
195{
196 addTransitionIndexes.clear();
197 addTransitionTargets.clear();
198
199 removeTransitionIndexes.clear();
200 removeTransitionTargets.clear();
201
202 moveTransitionIndexes.clear();
203 moveTransitionTargets.clear();
204}
205
206QQuickTransition *QQuickItemViewTransitioner::transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const
207{
208 if (type == QQuickItemViewTransitioner::NoTransition)
209 return nullptr;
210
211 if (type == PopulateTransition)
212 asTarget = true; // no separate displaced transition
213
214 QQuickTransition *trans = nullptr;
215 switch (type) {
216 case NoTransition:
217 break;
218 case PopulateTransition:
219 trans = populateTransition;
220 break;
221 case AddTransition:
222 trans = asTarget ? addTransition : addDisplacedTransition;
223 break;
224 case MoveTransition:
225 trans = asTarget ? moveTransition : moveDisplacedTransition;
226 break;
227 case RemoveTransition:
228 trans = asTarget ? removeTransition : removeDisplacedTransition;
229 break;
230 }
231
232 if (!asTarget && (!trans || !trans->enabled()))
233 trans = displacedTransition;
234 if (trans && trans->enabled())
235 return trans;
236 return nullptr;
237}
238
239const QList<int> &QQuickItemViewTransitioner::targetIndexes(QQuickItemViewTransitioner::TransitionType type) const
240{
241 switch (type) {
242 case NoTransition:
243 break;
244 case PopulateTransition:
245 case AddTransition:
246 return addTransitionIndexes;
247 case MoveTransition:
248 return moveTransitionIndexes;
249 case RemoveTransition:
250 return removeTransitionIndexes;
251 }
252
253 return qquickitemviewtransition_emptyIndexes;
254}
255
256const QList<QObject *> &QQuickItemViewTransitioner::targetItems(QQuickItemViewTransitioner::TransitionType type) const
257{
258 switch (type) {
259 case NoTransition:
260 break;
261 case PopulateTransition:
262 case AddTransition:
263 return addTransitionTargets;
264 case MoveTransition:
265 return moveTransitionTargets;
266 case RemoveTransition:
267 return removeTransitionTargets;
268 }
269
270 return qquickitemviewtransition_emptyTargets;
271}
272
273void QQuickItemViewTransitioner::finishedTransition(QQuickItemViewTransitionJob *job, QQuickItemViewTransitionableItem *item)
274{
275 if (!runningJobs.contains(job))
276 return;
277 runningJobs.remove(job);
278 if (item) {
279 item->finishedTransition();
280 if (changeListener)
281 changeListener->viewItemTransitionFinished(item);
282 }
283}
284
285
286QQuickItemViewTransitionableItem::QQuickItemViewTransitionableItem(QQuickItem *i)
287 : item(i)
288 , transition(nullptr)
289 , nextTransitionType(QQuickItemViewTransitioner::NoTransition)
290 , isTransitionTarget(false)
291 , nextTransitionToSet(false)
292 , nextTransitionFromSet(false)
293 , lastMovedToSet(false)
294 , prepared(false)
295{
296}
297
298QQuickItemViewTransitionableItem::~QQuickItemViewTransitionableItem()
299{
300 delete transition;
301}
302
303qreal QQuickItemViewTransitionableItem::itemX() const
304{
305 if (nextTransitionType != QQuickItemViewTransitioner::NoTransition)
306 return nextTransitionToSet ? nextTransitionTo.x() : item->x();
307 else if (transition && transition->isRunning())
308 return transition->m_toPos.x();
309 else
310 return item->x();
311}
312
313qreal QQuickItemViewTransitionableItem::itemY() const
314{
315 // If item is transitioning to some pos, return that dest pos.
316 // If item was redirected to some new pos before the current transition finished,
317 // return that new pos.
318 if (nextTransitionType != QQuickItemViewTransitioner::NoTransition)
319 return nextTransitionToSet ? nextTransitionTo.y() : item->y();
320 else if (transition && transition->isRunning())
321 return transition->m_toPos.y();
322 else
323 return item->y();
324}
325
326void QQuickItemViewTransitionableItem::moveTo(const QPointF &pos, bool immediate)
327{
328 if (!nextTransitionFromSet && nextTransitionType != QQuickItemViewTransitioner::NoTransition) {
329 nextTransitionFrom = item->position();
330 nextTransitionFromSet = true;
331 }
332
333 lastMovedTo = pos;
334 lastMovedToSet = true;
335
336 if (immediate || !transitionScheduledOrRunning()) {
337 if (immediate)
338 stopTransition();
339 item->setPosition(pos);
340 } else {
341 nextTransitionTo = pos;
342 nextTransitionToSet = true;
343 }
344}
345
346bool QQuickItemViewTransitionableItem::transitionScheduledOrRunning() const
347{
348 return (transition && transition->isRunning())
349 || nextTransitionType != QQuickItemViewTransitioner::NoTransition;
350}
351
352bool QQuickItemViewTransitionableItem::transitionRunning() const
353{
354 return (transition && transition->isRunning());
355}
356
357bool QQuickItemViewTransitionableItem::isPendingRemoval() const
358{
359 if (nextTransitionType == QQuickItemViewTransitioner::RemoveTransition)
360 return isTransitionTarget;
361 if (transition && transition->isRunning() && transition->m_type == QQuickItemViewTransitioner::RemoveTransition)
362 return transition->m_isTarget;
363 return false;
364}
365
366bool QQuickItemViewTransitionableItem::prepareTransition(QQuickItemViewTransitioner *transitioner, int index, const QRectF &viewBounds)
367{
368 if (nextTransitionType == QQuickItemViewTransitioner::NoTransition)
369 return false;
370
371 if (isTransitionTarget) {
372 // If item is not already moving somewhere, set it to not move anywhere.
373 // This ensures that removed targets don't transition to the default (0,0) and that
374 // items set for other transition types only transition if they actually move somewhere.
375 if (!nextTransitionToSet)
376 moveTo(item->position());
377 } else {
378 // don't start displaced transitions that don't move anywhere
379 if (!nextTransitionToSet || (nextTransitionFromSet && nextTransitionFrom == nextTransitionTo)) {
380 clearCurrentScheduledTransition();
381 return false;
382 }
383 }
384
385 bool doTransition = false;
386
387 // For move transitions (both target and displaced) and displaced transitions of other
388 // types, only run the transition if the item is actually moving to another position.
389 switch (nextTransitionType) {
390 case QQuickItemViewTransitioner::NoTransition:
391 {
392 return false;
393 }
394 case QQuickItemViewTransitioner::PopulateTransition:
395 {
396 doTransition = viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height()));
397 break;
398 }
399 case QQuickItemViewTransitioner::AddTransition:
400 case QQuickItemViewTransitioner::RemoveTransition:
401 if (viewBounds.isNull()) {
402 if (isTransitionTarget)
403 doTransition = true;
404 else
405 doTransition = transitionWillChangePosition();
406 } else if (isTransitionTarget) {
407 // For Add targets, do transition if item is moving into visible area
408 // For Remove targets, do transition if item is currently in visible area
409 doTransition = (nextTransitionType == QQuickItemViewTransitioner::AddTransition)
410 ? viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height()))
411 : viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height()));
412 } else {
413 // do transition if moving from or into visible area
414 if (viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height()))
415 || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height()))) {
416 doTransition = transitionWillChangePosition();
417 }
418 }
419 break;
420 case QQuickItemViewTransitioner::MoveTransition:
421 // do transition if moving from or into visible area
422 if (transitionWillChangePosition()) {
423 doTransition = viewBounds.isNull()
424 || viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height()))
425 || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height()));
426 }
427 break;
428 }
429
430 if (doTransition) {
431 // add item to target lists even if canTransition() is false for a target transition,
432 // since the target lists still need to be filled for displaced transitions
433 if (isTransitionTarget)
434 transitioner->addToTargetLists(nextTransitionType, this, index);
435 doTransition = transitioner->canTransition(nextTransitionType, isTransitionTarget);
436 }
437
438 if (!doTransition) {
439 // if transition type is not valid, the previous transition still has to be
440 // canceled so that the item can move immediately to the right position
441 item->setPosition(nextTransitionTo);
442 ACTION_IF_DELETED(this, stopTransition(), return false);
443 }
444
445 prepared = true;
446 return doTransition;
447}
448
449void QQuickItemViewTransitionableItem::startTransition(QQuickItemViewTransitioner *transitioner, int index)
450{
451 if (nextTransitionType == QQuickItemViewTransitioner::NoTransition)
452 return;
453
454 if (!prepared) {
455 qWarning("QQuickViewItem::prepareTransition() not called!");
456 return;
457 }
458
459 if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) {
460 if (transition)
461 RETURN_IF_DELETED(transition->cancel());
462 delete transition;
463 transition = new QQuickItemViewTransitionJob;
464 }
465
466 RETURN_IF_DELETED(transition->startTransition(this, index, transitioner, nextTransitionType, nextTransitionTo, isTransitionTarget));
467 clearCurrentScheduledTransition();
468}
469
470void QQuickItemViewTransitionableItem::completeTransition(QQuickTransition *quickTransition)
471{
472 if (nextTransitionType == QQuickItemViewTransitioner::NoTransition)
473 return;
474
475 if (!prepared) {
476 qWarning("QQuickViewItem::prepareTransition() not called!");
477 return;
478 }
479
480 if (!item) {
481 qWarning("No target for transition!");
482 return;
483 }
484
485 if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) {
486 if (transition)
487 RETURN_IF_DELETED(transition->cancel());
488 delete transition;
489 transition = new QQuickItemViewTransitionJob;
490 }
491
492 QQuickStateOperation::ActionList actions; // not used
493 QList<QQmlProperty> after; // not used
494 QScopedPointer<QQuickTransitionInstance> instance(
495 quickTransition->prepare(actions, after, transition, item));
496 RETURN_IF_DELETED(instance->complete());
497
498 clearCurrentScheduledTransition();
499}
500
501void QQuickItemViewTransitionableItem::setNextTransition(QQuickItemViewTransitioner::TransitionType type, bool isTargetItem)
502{
503 // Don't reset nextTransitionToSet - once it is set, it cannot be changed
504 // until the animation finishes since the itemX() and itemY() may be used
505 // to calculate positions for transitions for other items in the view.
506 nextTransitionType = type;
507 isTransitionTarget = isTargetItem;
508
509 if (!nextTransitionFromSet && lastMovedToSet) {
510 nextTransitionFrom = lastMovedTo;
511 nextTransitionFromSet = true;
512 }
513}
514
515bool QQuickItemViewTransitionableItem::transitionWillChangePosition() const
516{
517 if (transitionRunning() && transition->m_toPos != nextTransitionTo)
518 return true;
519 if (!nextTransitionFromSet)
520 return false;
521 return nextTransitionTo != nextTransitionFrom;
522}
523
524void QQuickItemViewTransitionableItem::resetNextTransitionPos()
525{
526 nextTransitionToSet = false;
527 nextTransitionTo = QPointF();
528}
529
530void QQuickItemViewTransitionableItem::finishedTransition()
531{
532 resetNextTransitionPos();
533}
534
535void QQuickItemViewTransitionableItem::clearCurrentScheduledTransition()
536{
537 // Just clear the current scheduled transition - don't touch the nextTransitionTo
538 // which may have already been set for a previously scheduled transition
539
540 nextTransitionType = QQuickItemViewTransitioner::NoTransition;
541 isTransitionTarget = false;
542 prepared = false;
543 nextTransitionFromSet = false;
544}
545
546void QQuickItemViewTransitionableItem::stopTransition()
547{
548 if (transition)
549 RETURN_IF_DELETED(transition->cancel());
550 delete transition;
551 transition = nullptr;
552 clearCurrentScheduledTransition();
553 resetNextTransitionPos();
554}
555
556
557QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
558 : QObject(parent), m_index(-1)
559{
560}
561/*!
562 \qmltype ViewTransition
563 \nativetype QQuickViewTransitionAttached
564 \inqmlmodule QtQuick
565 \ingroup qtquick-transitions-animations
566 \brief Specifies items under transition in a view.
567
568 With ListView and GridView, it is possible to specify transitions that should be applied whenever
569 the items in the view change as a result of modifications to the view's model. They both have the
570 following properties that can be set to the appropriate transitions to be run for various
571 operations:
572
573 \list
574 \li \c populate - the transition to apply to the items created initially for the view, or when the model changes
575 \li \c add - the transition to apply to items that are added to the view after it has been created
576 \li \c remove - the transition to apply to items that are removed from the view
577 \li \c move - the transition to apply to items that are moved within the view (i.e. as a result
578 of a move operation in the model)
579 \li \c displaced - the generic transition to be applied to any items that are displaced by an
580 add, move or remove operation
581 \li \c addDisplaced, \c removeDisplaced and \c moveDisplaced - the transitions to be applied when
582 items are displaced by add, move, or remove operations, respectively (these override the
583 generic displaced transition if specified)
584 \endlist
585
586 For the \l Row, \l Column, \l Grid and \l Flow positioner types, which operate with collections of child
587 items rather than data models, the following properties are used instead:
588
589 \list
590 \li \c populate - the transition to apply to items that have been added to the positioner at the
591 time of its creation
592 \li \c add - the transition to apply to items that are added to
593 or reparented to the positioner, or items that have become \l {Item::}{visible}
594 \li \c move - the transition to apply to items that have moved within the positioner, including
595 when they are displaced due to the addition or removal of other items, or when items are otherwise
596 rearranged within the positioner, or when items are repositioned due to the resizing of other
597 items in the positioner
598 \endlist
599
600 View transitions have access to a ViewTransition attached property that
601 provides details of the items that are under transition and the operation that triggered the
602 transition. Since view transitions are run once per item, these details can be used to customize
603 each transition for each individual item.
604
605 The ViewTransition attached property provides the following properties specific to the item to
606 which the transition is applied:
607
608 \list
609 \li ViewTransition.item - the item that is under transition
610 \li ViewTransition.index - the index of this item
611 \li ViewTransition.destination - the (x,y) point to which this item is moving for the relevant view operation
612 \endlist
613
614 In addition, ViewTransition provides properties specific to the items which are the target
615 of the operation that triggered the transition:
616
617 \list
618 \li ViewTransition.targetIndexes - the indexes of the target items
619 \li ViewTransition.targetItems - the target items themselves
620 \endlist
621
622 (Note that for the \l Row, \l Column, \l Grid and \l Flow positioner types, the \c move transition only
623 provides these two additional details when the transition is triggered by the addition of items
624 to a positioner.)
625
626 View transitions can be written without referring to any of the attributes listed
627 above. These attributes merely provide extra details that are useful for customising view
628 transitions.
629
630 Following is an introduction to view transitions and the ways in which the ViewTransition
631 attached property can be used to augment view transitions.
632
633
634 \section2 View Transitions: a Simple Example
635
636 Here is a basic example of the use of view transitions. The view below specifies transitions for
637 the \c add and \c displaced properties, which will be run when items are added to the view:
638
639 \snippet qml/viewtransitions/viewtransitions-basic.qml 0
640
641 When the space key is pressed, adding an item to the model, the new item will fade in and
642 increase in scale over 400 milliseconds as it is added to the view. Also, any item that is
643 displaced by the addition of a new item will animate to its new position in the view over
644 400 milliseconds, as specified by the \c displaced transition.
645
646 If five items were inserted in succession at index 0, the effect would be this:
647
648 \image viewtransitions-basic.gif {Five items inserted in succession
649 at top, pushing existing items downward with fade and scale}
650
651 Notice that the NumberAnimation objects above do not need to specify a \c target to animate
652 the appropriate item. Also, the NumberAnimation in the \c addTransition does not need to specify
653 the \c to value to move the item to its correct position in the view. This is because the view
654 implicitly sets the \c target and \c to values with the correct item and final item position
655 values if these properties are not explicitly defined.
656
657 At its simplest, a view transition may just animate an item to its new position following a
658 view operation, just as the \c displaced transition does above, or animate some item properties,
659 as in the \c add transition above. Additionally, a view transition may make use of the
660 ViewTransition attached property to customize animation behavior for different items. Following
661 are some examples of how this can be achieved.
662
663
664 \section2 Using the ViewTransition Attached Property
665
666 As stated, the various ViewTransition properties provide details specific to the individual item
667 being transitioned as well as the operation that triggered the transition. In the animation above,
668 five items are inserted in succession at index 0. When the fifth and final insertion takes place,
669 adding "Item 4" to the view, the \c add transition is run once (for the inserted item) and the
670 \c displaced transition is run four times (once for each of the four existing items in the view).
671
672 At this point, if we examined the \c displaced transition that was run for the bottom displaced
673 item ("Item 0"), the ViewTransition property values provided to this transition would be as follows:
674
675 \table
676 \header
677 \li Property
678 \li Value
679 \li Explanation
680 \row
681 \li ViewTransition.item
682 \li "Item 0" delegate instance
683 \li The "Item 0" \l Rectangle object itself
684 \row
685 \li ViewTransition.index
686 \li \c int value of 4
687 \li The index of "Item 0" within the model following the add operation
688 \row
689 \li ViewTransition.destination
690 \li \l point value of (0, 120)
691 \li The position that "Item 0" is moving to
692 \row
693 \li ViewTransition.targetIndexes
694 \li \c int array, just contains the integer "0" (zero)
695 \li The index of "Item 4", the new item added to the view
696 \row
697 \li ViewTransition.targetItems
698 \li object array, just contains the "Item 4" delegate instance
699 \li The "Item 4" \l Rectangle object - the new item added to the view
700 \endtable
701
702 The ViewTransition.targetIndexes and ViewTransition.targetItems lists provide the items and
703 indexes of all delegate instances that are the targets of the relevant operation. For an add
704 operation, these are all the items that are added into the view; for a remove, these are all
705 the items removed from the view, and so on. (Note these lists will only contain references to
706 items that have been created within the view or its cached items; targets that are not within
707 the visible area of the view or within the item cache will not be accessible.)
708
709 So, while the ViewTransition.item, ViewTransition.index and ViewTransition.destination values
710 vary for each individual transition that is run, the ViewTransition.targetIndexes and
711 ViewTransition.targetItems values are the same for every \c add and \c displaced transition
712 that is triggered by a particular add operation.
713
714
715 \section3 Delaying Animations Based on Index
716
717 Since each view transition is run once for each item affected by the transition, the ViewTransition
718 properties can be used within a transition to define custom behavior for each item's transition.
719 For example, the ListView in the previous example could use this information to create a ripple-type
720 effect on the movement of the displaced items.
721
722 This can be achieved by modifying the \c displaced transition so that it delays the animation of
723 each displaced item based on the difference between its index (provided by ViewTransition.index)
724 and the first removed index (provided by ViewTransition.targetIndexes):
725
726 \snippet qml/viewtransitions/viewtransitions-delayedbyindex.qml 0
727
728 Each displaced item delays its animation by an additional 100 milliseconds, producing a subtle
729 ripple-type effect when items are displaced by the add, like this:
730
731 \image viewtransitions-delayedbyindex.gif {Ripple effect with
732 displaced items moving down in staggered sequence}
733
734
735 \section3 Animating Items to Intermediate Positions
736
737 The ViewTransition.item property gives a reference to the item to which the transition is being
738 applied. This can be used to access any of the item's attributes, custom \c property values,
739 and so on.
740
741 Below is a modification of the \c displaced transition from the previous example. It adds a
742 ParallelAnimation with nested NumberAnimation objects that reference ViewTransition.item to access
743 each item's \c x and \c y values at the start of their transitions. This allows each item to
744 animate to an intermediate position relative to its starting point for the transition, before
745 animating to its final position in the view:
746
747 \snippet qml/viewtransitions/viewtransitions-intermediatemove.qml 0
748
749 Now, a displaced item will first move to a position of (20, 50) relative to its starting
750 position, and then to its final, correct position in the view:
751
752 \image viewtransitions-intermediatemove.gif {Intermediate position
753 animation with items shifting right before moving down}
754
755 Since the final NumberAnimation does not specify a \c to value, the view implicitly sets this
756 value to the item's final position in the view, and so this last animation will move this item
757 to the correct place. If the transition requires the final position of the item for some calculation,
758 this is accessible through ViewTransition.destination.
759
760 Instead of using multiple NumberAnimations, you could use a PathAnimation to animate an item over
761 a curved path. For example, the \c add transition in the previous example could be augmented with
762 a PathAnimation as follows: to animate newly added items along a path:
763
764 \snippet qml/viewtransitions/viewtransitions-pathanim.qml 0
765
766 This animates newly added items along a path. Notice that each path is specified relative to
767 each item's final destination point, so that items inserted at different indexes start their
768 paths from different positions:
769
770 \image viewtransitions-pathanim.gif {Path animation with new items
771 following curved paths from right into the list}
772
773
774 \section2 Handling Interrupted Animations
775
776 A view transition may be interrupted at any time if a different view transition needs to be
777 applied while the original transition is in progress. For example, say Item A is inserted at index 0
778 and undergoes an "add" transition; then, Item B is inserted at index 0 in quick succession before
779 Item A's transition has finished. Since Item B is inserted before Item A, it will displace Item
780 A, causing the view to interrupt Item A's "add" transition mid-way and start a "displaced"
781 transition on Item A instead.
782
783 For simple animations that simply animate an item's movement to its final destination, this
784 interruption is unlikely to require additional consideration. However, if a transition changes other
785 properties, this interruption may cause unwanted side effects. Consider the first example on this
786 page, repeated below for convenience:
787
788 \snippet qml/viewtransitions/viewtransitions-basic.qml 0
789
790 If multiple items are added in rapid succession, without waiting for a previous transition
791 to finish, this is the result:
792
793 \image viewtransitions-interruptedbad.gif {Interrupted transition
794 leaving rapidly added items partially transparent}
795
796 Each newly added item undergoes an \c add transition, but before the transition can finish,
797 another item is added, displacing the previously added item. Because of this, the \c add
798 transition on the previously added item is interrupted and a \c displaced transition is
799 started on the item instead. Due to the interruption, the \c opacity and \c scale animations
800 have not completed, thus producing items with opacity and scale that are below 1.0.
801
802 To fix this, the \c displaced transition should additionally ensure the item properties are
803 set to the end values specified in the \c add transition, effectively resetting these values
804 whenever an item is displaced. In this case, it means setting the item opacity and scale to 1.0:
805
806 \snippet qml/viewtransitions/viewtransitions-interruptedgood.qml 0
807
808 Now, when an item's \c add transition is interrupted, its opacity and scale are animated to 1.0
809 upon displacement, avoiding the erroneous visual effects from before:
810
811 \image viewtransitions-interruptedgood.gif {Corrected interrupted
812 transition with items becoming fully opaque when displaced}
813
814 The same principle applies to any combination of view transitions. An added item may be moved
815 before its add transition finishes, or a moved item may be removed before its moved transition
816 finishes, and so on; so, the rule of thumb is that every transition should handle the same set of
817 properties.
818
819
820 \section2 Restrictions Regarding ScriptAction
821
822 When a view transition is initialized, any property bindings that refer to the ViewTransition
823 attached property are evaluated in preparation for the transition. Due to the nature of the
824 internal construction of a view transition, the attributes of the ViewTransition attached
825 property are only valid for the relevant item when the transition is initialized, and may not be
826 valid when the transition is actually run.
827
828 Therefore, a ScriptAction within a view transition should not refer to the ViewTransition
829 attached property, as it may not refer to the expected values at the time that the ScriptAction
830 is actually invoked. Consider the following example:
831
832 \snippet qml/viewtransitions/viewtransitions-scriptactionbad.qml 0
833
834 When the space key is pressed, three items are moved from index 5 to index 1. For each moved
835 item, the \c moveTransition sequence presumably animates the item's color to "yellow", then
836 animates it to its final position, then changes the item color back to "lightsteelblue" using a
837 ScriptAction. However, when run, the transition does not produce the intended result:
838
839 \image viewtransitions-scriptactionbad.gif {ScriptAction timing issue
840 with moved items remaining yellow except the last}
841
842 Only the last moved item is returned to the "lightsteelblue" color; the others remain yellow. This
843 is because the ScriptAction is not run until after the transition has already been initialized, by
844 which time the ViewTransition.item value has changed to refer to a different item; the item that
845 the script had intended to refer to is not the one held by ViewTransition.item at the time the
846 ScriptAction is actually invoked.
847
848 In this instance, to avoid this issue, the view could set the property using a PropertyAction
849 instead:
850
851 \snippet qml/viewtransitions/viewtransitions-scriptactiongood.qml 0
852
853 When the transition is initialized, the PropertyAction \c target will be set to the respective
854 ViewTransition.item for the transition and will later run with the correct item target as
855 expected.
856 */
857
858/*!
859 \qmlattachedproperty int QtQuick::ViewTransition::index
860
861 This attached property holds the index of the item that is being
862 transitioned.
863
864 Note that if the item is being moved, this property holds the index that
865 the item is moving to, not from.
866*/
867
868/*!
869 \qmlattachedproperty item QtQuick::ViewTransition::item
870
871 This attached property holds the item that is being transitioned.
872
873 \warning This item should not be kept and referred to outside of the transition
874 as it may become invalid as the view changes.
875*/
876
877/*!
878 \qmlattachedproperty point QtQuick::ViewTransition::destination
879
880 This attached property holds the final destination position for the transitioned
881 item within the view.
882
883 This property value is a \l point with \c x and \c y properties.
884*/
885
886/*!
887 \qmlattachedproperty list QtQuick::ViewTransition::targetIndexes
888
889 This attached property holds a list of the indexes of the items in view
890 that are the target of the relevant operation.
891
892 The targets are the items that are the subject of the operation. For
893 an add operation, these are the items being added; for a remove, these
894 are the items being removed; for a move, these are the items being
895 moved.
896
897 For example, if the transition was triggered by an insert operation
898 that added two items at index 1 and 2, this targetIndexes list would
899 have the value [1,2].
900
901 \note The targetIndexes list only contains the indexes of items that are actually
902 in view, or will be in the view once the relevant operation completes.
903
904 \sa QtQuick::ViewTransition::targetItems
905*/
906
907/*!
908 \qmlattachedproperty list QtQuick::ViewTransition::targetItems
909
910 This attached property holds the list of items in view that are the
911 target of the relevant operation.
912
913 The targets are the items that are the subject of the operation. For
914 an add operation, these are the items being added; for a remove, these
915 are the items being removed; for a move, these are the items being
916 moved.
917
918 For example, if the transition was triggered by an insert operation
919 that added two items at index 1 and 2, this targetItems list would
920 contain these two items.
921
922 \note The targetItems list only contains items that are actually
923 in view, or will be in the view once the relevant operation completes.
924
925 \warning The objects in this list should not be kept and referred to
926 outside of the transition as the items may become invalid. The targetItems
927 are only valid when the Transition is initially created; this also means
928 they should not be used by ScriptAction objects in the Transition, which are
929 not evaluated until the transition is run.
930
931 \sa QtQuick::ViewTransition::targetIndexes
932*/
934{
935 return QQmlListProperty<QObject>(this, &m_targetItems);
936}
937
939{
940 return new QQuickViewTransitionAttached(obj);
941}
942
943QT_END_NAMESPACE
944
945#include "moc_qquickitemviewtransition_p.cpp"
QQuickItemViewTransitioner * m_transitioner
void startTransition(QQuickItemViewTransitionableItem *item, int index, QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem)
QQuickItemViewTransitionableItem * m_item
QQmlListProperty< QObject > targetItems()
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE QList< int > qquickitemviewtransition_emptyIndexes
static QList< QObject * > qquickitemviewtransition_emptyTargets