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
649
650 Notice that the NumberAnimation objects above do not need to specify a \c target to animate
651 the appropriate item. Also, the NumberAnimation in the \c addTransition does not need to specify
652 the \c to value to move the item to its correct position in the view. This is because the view
653 implicitly sets the \c target and \c to values with the correct item and final item position
654 values if these properties are not explicitly defined.
655
656 At its simplest, a view transition may just animate an item to its new position following a
657 view operation, just as the \c displaced transition does above, or animate some item properties,
658 as in the \c add transition above. Additionally, a view transition may make use of the
659 ViewTransition attached property to customize animation behavior for different items. Following
660 are some examples of how this can be achieved.
661
662
663 \section2 Using the ViewTransition Attached Property
664
665 As stated, the various ViewTransition properties provide details specific to the individual item
666 being transitioned as well as the operation that triggered the transition. In the animation above,
667 five items are inserted in succession at index 0. When the fifth and final insertion takes place,
668 adding "Item 4" to the view, the \c add transition is run once (for the inserted item) and the
669 \c displaced transition is run four times (once for each of the four existing items in the view).
670
671 At this point, if we examined the \c displaced transition that was run for the bottom displaced
672 item ("Item 0"), the ViewTransition property values provided to this transition would be as follows:
673
674 \table
675 \header
676 \li Property
677 \li Value
678 \li Explanation
679 \row
680 \li ViewTransition.item
681 \li "Item 0" delegate instance
682 \li The "Item 0" \l Rectangle object itself
683 \row
684 \li ViewTransition.index
685 \li \c int value of 4
686 \li The index of "Item 0" within the model following the add operation
687 \row
688 \li ViewTransition.destination
689 \li \l point value of (0, 120)
690 \li The position that "Item 0" is moving to
691 \row
692 \li ViewTransition.targetIndexes
693 \li \c int array, just contains the integer "0" (zero)
694 \li The index of "Item 4", the new item added to the view
695 \row
696 \li ViewTransition.targetItems
697 \li object array, just contains the "Item 4" delegate instance
698 \li The "Item 4" \l Rectangle object - the new item added to the view
699 \endtable
700
701 The ViewTransition.targetIndexes and ViewTransition.targetItems lists provide the items and
702 indexes of all delegate instances that are the targets of the relevant operation. For an add
703 operation, these are all the items that are added into the view; for a remove, these are all
704 the items removed from the view, and so on. (Note these lists will only contain references to
705 items that have been created within the view or its cached items; targets that are not within
706 the visible area of the view or within the item cache will not be accessible.)
707
708 So, while the ViewTransition.item, ViewTransition.index and ViewTransition.destination values
709 vary for each individual transition that is run, the ViewTransition.targetIndexes and
710 ViewTransition.targetItems values are the same for every \c add and \c displaced transition
711 that is triggered by a particular add operation.
712
713
714 \section3 Delaying Animations Based on Index
715
716 Since each view transition is run once for each item affected by the transition, the ViewTransition
717 properties can be used within a transition to define custom behavior for each item's transition.
718 For example, the ListView in the previous example could use this information to create a ripple-type
719 effect on the movement of the displaced items.
720
721 This can be achieved by modifying the \c displaced transition so that it delays the animation of
722 each displaced item based on the difference between its index (provided by ViewTransition.index)
723 and the first removed index (provided by ViewTransition.targetIndexes):
724
725 \snippet qml/viewtransitions/viewtransitions-delayedbyindex.qml 0
726
727 Each displaced item delays its animation by an additional 100 milliseconds, producing a subtle
728 ripple-type effect when items are displaced by the add, like this:
729
730 \image viewtransitions-delayedbyindex.gif
731
732
733 \section3 Animating Items to Intermediate Positions
734
735 The ViewTransition.item property gives a reference to the item to which the transition is being
736 applied. This can be used to access any of the item's attributes, custom \c property values,
737 and so on.
738
739 Below is a modification of the \c displaced transition from the previous example. It adds a
740 ParallelAnimation with nested NumberAnimation objects that reference ViewTransition.item to access
741 each item's \c x and \c y values at the start of their transitions. This allows each item to
742 animate to an intermediate position relative to its starting point for the transition, before
743 animating to its final position in the view:
744
745 \snippet qml/viewtransitions/viewtransitions-intermediatemove.qml 0
746
747 Now, a displaced item will first move to a position of (20, 50) relative to its starting
748 position, and then to its final, correct position in the view:
749
750 \image viewtransitions-intermediatemove.gif
751
752 Since the final NumberAnimation does not specify a \c to value, the view implicitly sets this
753 value to the item's final position in the view, and so this last animation will move this item
754 to the correct place. If the transition requires the final position of the item for some calculation,
755 this is accessible through ViewTransition.destination.
756
757 Instead of using multiple NumberAnimations, you could use a PathAnimation to animate an item over
758 a curved path. For example, the \c add transition in the previous example could be augmented with
759 a PathAnimation as follows: to animate newly added items along a path:
760
761 \snippet qml/viewtransitions/viewtransitions-pathanim.qml 0
762
763 This animates newly added items along a path. Notice that each path is specified relative to
764 each item's final destination point, so that items inserted at different indexes start their
765 paths from different positions:
766
767 \image viewtransitions-pathanim.gif
768
769
770 \section2 Handling Interrupted Animations
771
772 A view transition may be interrupted at any time if a different view transition needs to be
773 applied while the original transition is in progress. For example, say Item A is inserted at index 0
774 and undergoes an "add" transition; then, Item B is inserted at index 0 in quick succession before
775 Item A's transition has finished. Since Item B is inserted before Item A, it will displace Item
776 A, causing the view to interrupt Item A's "add" transition mid-way and start a "displaced"
777 transition on Item A instead.
778
779 For simple animations that simply animate an item's movement to its final destination, this
780 interruption is unlikely to require additional consideration. However, if a transition changes other
781 properties, this interruption may cause unwanted side effects. Consider the first example on this
782 page, repeated below for convenience:
783
784 \snippet qml/viewtransitions/viewtransitions-basic.qml 0
785
786 If multiple items are added in rapid succession, without waiting for a previous transition
787 to finish, this is the result:
788
789 \image viewtransitions-interruptedbad.gif
790
791 Each newly added item undergoes an \c add transition, but before the transition can finish,
792 another item is added, displacing the previously added item. Because of this, the \c add
793 transition on the previously added item is interrupted and a \c displaced transition is
794 started on the item instead. Due to the interruption, the \c opacity and \c scale animations
795 have not completed, thus producing items with opacity and scale that are below 1.0.
796
797 To fix this, the \c displaced transition should additionally ensure the item properties are
798 set to the end values specified in the \c add transition, effectively resetting these values
799 whenever an item is displaced. In this case, it means setting the item opacity and scale to 1.0:
800
801 \snippet qml/viewtransitions/viewtransitions-interruptedgood.qml 0
802
803 Now, when an item's \c add transition is interrupted, its opacity and scale are animated to 1.0
804 upon displacement, avoiding the erroneous visual effects from before:
805
806 \image viewtransitions-interruptedgood.gif
807
808 The same principle applies to any combination of view transitions. An added item may be moved
809 before its add transition finishes, or a moved item may be removed before its moved transition
810 finishes, and so on; so, the rule of thumb is that every transition should handle the same set of
811 properties.
812
813
814 \section2 Restrictions Regarding ScriptAction
815
816 When a view transition is initialized, any property bindings that refer to the ViewTransition
817 attached property are evaluated in preparation for the transition. Due to the nature of the
818 internal construction of a view transition, the attributes of the ViewTransition attached
819 property are only valid for the relevant item when the transition is initialized, and may not be
820 valid when the transition is actually run.
821
822 Therefore, a ScriptAction within a view transition should not refer to the ViewTransition
823 attached property, as it may not refer to the expected values at the time that the ScriptAction
824 is actually invoked. Consider the following example:
825
826 \snippet qml/viewtransitions/viewtransitions-scriptactionbad.qml 0
827
828 When the space key is pressed, three items are moved from index 5 to index 1. For each moved
829 item, the \c moveTransition sequence presumably animates the item's color to "yellow", then
830 animates it to its final position, then changes the item color back to "lightsteelblue" using a
831 ScriptAction. However, when run, the transition does not produce the intended result:
832
833 \image viewtransitions-scriptactionbad.gif
834
835 Only the last moved item is returned to the "lightsteelblue" color; the others remain yellow. This
836 is because the ScriptAction is not run until after the transition has already been initialized, by
837 which time the ViewTransition.item value has changed to refer to a different item; the item that
838 the script had intended to refer to is not the one held by ViewTransition.item at the time the
839 ScriptAction is actually invoked.
840
841 In this instance, to avoid this issue, the view could set the property using a PropertyAction
842 instead:
843
844 \snippet qml/viewtransitions/viewtransitions-scriptactiongood.qml 0
845
846 When the transition is initialized, the PropertyAction \c target will be set to the respective
847 ViewTransition.item for the transition and will later run with the correct item target as
848 expected.
849 */
850
851/*!
852 \qmlattachedproperty int QtQuick::ViewTransition::index
853
854 This attached property holds the index of the item that is being
855 transitioned.
856
857 Note that if the item is being moved, this property holds the index that
858 the item is moving to, not from.
859*/
860
861/*!
862 \qmlattachedproperty item QtQuick::ViewTransition::item
863
864 This attached property holds the item that is being transitioned.
865
866 \warning This item should not be kept and referred to outside of the transition
867 as it may become invalid as the view changes.
868*/
869
870/*!
871 \qmlattachedproperty point QtQuick::ViewTransition::destination
872
873 This attached property holds the final destination position for the transitioned
874 item within the view.
875
876 This property value is a \l point with \c x and \c y properties.
877*/
878
879/*!
880 \qmlattachedproperty list QtQuick::ViewTransition::targetIndexes
881
882 This attached property holds a list of the indexes of the items in view
883 that are the target of the relevant operation.
884
885 The targets are the items that are the subject of the operation. For
886 an add operation, these are the items being added; for a remove, these
887 are the items being removed; for a move, these are the items being
888 moved.
889
890 For example, if the transition was triggered by an insert operation
891 that added two items at index 1 and 2, this targetIndexes list would
892 have the value [1,2].
893
894 \note The targetIndexes list only contains the indexes of items that are actually
895 in view, or will be in the view once the relevant operation completes.
896
897 \sa QtQuick::ViewTransition::targetItems
898*/
899
900/*!
901 \qmlattachedproperty list QtQuick::ViewTransition::targetItems
902
903 This attached property holds the list of items in view that are the
904 target of the relevant operation.
905
906 The targets are the items that are the subject of the operation. For
907 an add operation, these are the items being added; for a remove, these
908 are the items being removed; for a move, these are the items being
909 moved.
910
911 For example, if the transition was triggered by an insert operation
912 that added two items at index 1 and 2, this targetItems list would
913 contain these two items.
914
915 \note The targetItems list only contains items that are actually
916 in view, or will be in the view once the relevant operation completes.
917
918 \warning The objects in this list should not be kept and referred to
919 outside of the transition as the items may become invalid. The targetItems
920 are only valid when the Transition is initially created; this also means
921 they should not be used by ScriptAction objects in the Transition, which are
922 not evaluated until the transition is run.
923
924 \sa QtQuick::ViewTransition::targetIndexes
925*/
927{
928 return QQmlListProperty<QObject>(this, &m_targetItems);
929}
930
932{
933 return new QQuickViewTransitionAttached(obj);
934}
935
936QT_END_NAMESPACE
937
938#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()
static QT_BEGIN_NAMESPACE QList< int > qquickitemviewtransition_emptyIndexes
static QList< QObject * > qquickitemviewtransition_emptyTargets