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
qquickswipeview.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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
7#include <QtQml/qqmlinfo.h>
8#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
9
11
12/*!
13 \qmltype SwipeView
14 \inherits Container
15//! \nativetype QQuickSwipeView
16 \inqmlmodule QtQuick.Controls
17 \since 5.7
18 \ingroup qtquickcontrols-navigation
19 \ingroup qtquickcontrols-containers
20 \ingroup qtquickcontrols-focusscopes
21 \brief Enables the user to navigate pages by swiping sideways.
22
23 SwipeView provides a swipe-based navigation model.
24
25 \image qtquickcontrols-swipeview.gif
26 {Swipe view swiping between pages}
27
28 SwipeView is populated with a set of pages. One page is visible at a time.
29 The user can navigate between the pages by swiping sideways. Notice that
30 SwipeView itself is entirely non-visual. It is recommended to combine it
31 with PageIndicator, to give the user a visual clue that there are multiple
32 pages.
33
34 \snippet qtquickcontrols-swipeview-indicator.qml 1
35
36 As shown above, SwipeView is typically populated with a static set of
37 pages that are defined inline as children of the view. It is also possible
38 to \l {Container::addItem()}{add}, \l {Container::insertItem()}{insert},
39 \l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove}
40 pages dynamically at run time.
41
42 \include container-currentindex.qdocinc {file} {SwipeView} {TabBar}
43
44 It is generally not advisable to add excessive amounts of pages to a
45 SwipeView. However, when the amount of pages grows larger, or individual
46 pages are relatively complex, it may be desirable to free up resources by
47 unloading pages that are outside the immediate reach of the user.
48 The following example presents how to use \l Loader to keep a maximum of
49 three pages simultaneously instantiated.
50
51 \code
52 SwipeView {
53 Repeater {
54 model: 6
55 Loader {
56 active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem
57 sourceComponent: Text {
58 text: index
59 Component.onCompleted: console.log("created:", index)
60 Component.onDestruction: console.log("destroyed:", index)
61 }
62 }
63 }
64 }
65 \endcode
66
67 \note SwipeView takes over the geometry management of items added to the
68 view. Using anchors on the items is not supported, and any \c width
69 or \c height assignment will be overridden by the view. Notice that
70 this only applies to the root of the item. Specifying width and height,
71 or using anchors for its children works as expected.
72
73 \sa TabBar, PageIndicator, {Customizing SwipeView}, {Navigation Controls}, {Container Controls},
74 {Focus Management in Qt Quick Controls}
75*/
76
78{
79 Q_DECLARE_PUBLIC(QQuickSwipeView)
80
81public:
84
85 static QQuickSwipeViewPrivate *get(QQuickSwipeView *view);
86
87 void itemImplicitWidthChanged(QQuickItem *item) override;
88 void itemImplicitHeightChanged(QQuickItem *item) override;
89
90 qreal getContentWidth() const override;
91 qreal getContentHeight() const override;
92
93 bool interactive = true;
95};
96
98{
99public:
100 Q_DECLARE_PUBLIC(QQuickSwipeViewAttached)
101
106
109 void setCurrentIndex(int i);
110
112 int index = -1;
113 int currentIndex = -1;
114};
115
116void QQuickSwipeViewPrivate::resizeItem(int index, QQuickItem *item)
117{
118 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
119 // TODO: expose QQuickAnchorLine so we can test for other conflicting anchors
120 if (anchors && (anchors->fill() || anchors->centerIn()) && !item->property("_q_QQuickSwipeView_warned").toBool()) {
121 qmlWarning(item) << "SwipeView has detected conflicting anchors. Unable to layout the item.";
122 item->setProperty("_q_QQuickSwipeView_warned", true);
123 }
124 if (orientation == Qt::Horizontal)
125 item->setPosition({index * (contentItem->width() + spacing), 0});
126 else
127 item->setPosition({0, index * (contentItem->height() + spacing)});
128 item->setSize(QSizeF(contentItem->width(), contentItem->height()));
129}
130
132{
133 Q_Q(QQuickSwipeView);
134 const int count = q->count();
135 for (int i = 0; i < count; ++i) {
136 QQuickItem *item = itemAt(i);
137 if (item)
138 resizeItem(i, item);
139 }
140}
141
143{
144 return view->d_func();
145}
146
148{
149 Q_Q(QQuickSwipeView);
150 QQuickContainerPrivate::itemImplicitWidthChanged(item);
151 if (item == q->currentItem())
152 updateImplicitContentWidth();
153}
154
156{
157 Q_Q(QQuickSwipeView);
158 QQuickContainerPrivate::itemImplicitHeightChanged(item);
159 if (item == q->currentItem())
160 updateImplicitContentHeight();
161}
162
164{
165 Q_Q(const QQuickSwipeView);
166 QQuickItem *currentItem = q->currentItem();
167 return currentItem ? currentItem->implicitWidth() : 0;
168}
169
171{
172 Q_Q(const QQuickSwipeView);
173 QQuickItem *currentItem = q->currentItem();
174 return currentItem ? currentItem->implicitHeight() : 0;
175}
176
177QQuickSwipeView::QQuickSwipeView(QQuickItem *parent)
178 : QQuickContainer(*(new QQuickSwipeViewPrivate), parent)
179{
180 Q_D(QQuickSwipeView);
181 d->changeTypes |= QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
182 setFlag(ItemIsFocusScope);
183 setActiveFocusOnTab(true);
184 QObjectPrivate::connect(this, &QQuickContainer::currentItemChanged, d, &QQuickControlPrivate::updateImplicitContentSize);
185}
186
187/*!
188 \since QtQuick.Controls 2.1 (Qt 5.8)
189 \qmlproperty bool QtQuick.Controls::SwipeView::interactive
190
191 This property describes whether the user can interact with the SwipeView.
192 The user cannot swipe a view that is not interactive.
193
194 The default value is \c true.
195*/
196bool QQuickSwipeView::isInteractive() const
197{
198 Q_D(const QQuickSwipeView);
199 return d->interactive;
200}
201
202void QQuickSwipeView::setInteractive(bool interactive)
203{
204 Q_D(QQuickSwipeView);
205 if (d->interactive == interactive)
206 return;
207
208 d->interactive = interactive;
209 emit interactiveChanged();
210}
211
212/*!
213 \since QtQuick.Controls 2.2 (Qt 5.9)
214 \qmlproperty enumeration QtQuick.Controls::SwipeView::orientation
215
216 This property holds the orientation.
217
218 Possible values:
219 \value Qt.Horizontal Horizontal (default)
220 \value Qt.Vertical Vertical
221
222 \sa horizontal, vertical
223*/
224Qt::Orientation QQuickSwipeView::orientation() const
225{
226 Q_D(const QQuickSwipeView);
227 return d->orientation;
228}
229
230void QQuickSwipeView::setOrientation(Qt::Orientation orientation)
231{
232 Q_D(QQuickSwipeView);
233 if (d->orientation == orientation)
234 return;
235
236 d->orientation = orientation;
237 if (isComponentComplete())
238 d->resizeItems();
239 emit orientationChanged();
240}
241
242/*!
243 \since QtQuick.Controls 2.3 (Qt 5.10)
244 \qmlproperty bool QtQuick.Controls::SwipeView::horizontal
245 \readonly
246
247 This property holds whether the swipe view is horizontal.
248
249 \sa orientation
250*/
251bool QQuickSwipeView::isHorizontal() const
252{
253 Q_D(const QQuickSwipeView);
254 return d->orientation == Qt::Horizontal;
255}
256
257/*!
258 \since QtQuick.Controls 2.3 (Qt 5.10)
259 \qmlproperty bool QtQuick.Controls::SwipeView::vertical
260 \readonly
261
262 This property holds whether the swipe view is vertical.
263
264 \sa orientation
265*/
266bool QQuickSwipeView::isVertical() const
267{
268 Q_D(const QQuickSwipeView);
269 return d->orientation == Qt::Vertical;
270}
271
272QQuickSwipeViewAttached *QQuickSwipeView::qmlAttachedProperties(QObject *object)
273{
274 return new QQuickSwipeViewAttached(object);
275}
276
277void QQuickSwipeView::componentComplete()
278{
279 Q_D(QQuickSwipeView);
280 QQuickContainer::componentComplete();
281 d->resizeItems();
282}
283
284void QQuickSwipeView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
285{
286 Q_D(QQuickSwipeView);
287 QQuickContainer::geometryChange(newGeometry, oldGeometry);
288 d->resizeItems();
289}
290
291void QQuickSwipeView::itemAdded(int index, QQuickItem *item)
292{
293 Q_D(QQuickSwipeView);
294 if (isComponentComplete())
295 d->resizeItem(index, item);
296 QQuickSwipeViewAttached *attached = qobject_cast<QQuickSwipeViewAttached *>(qmlAttachedPropertiesObject<QQuickSwipeView>(item));
297 if (attached)
298 QQuickSwipeViewAttachedPrivate::get(attached)->update(this, index);
299}
300
301void QQuickSwipeView::itemMoved(int index, QQuickItem *item)
302{
303 QQuickSwipeViewAttached *attached = qobject_cast<QQuickSwipeViewAttached *>(qmlAttachedPropertiesObject<QQuickSwipeView>(item));
304 if (attached)
305 QQuickSwipeViewAttachedPrivate::get(attached)->update(this, index);
306}
307
308void QQuickSwipeView::itemRemoved(int, QQuickItem *item)
309{
310 QQuickSwipeViewAttached *attached = qobject_cast<QQuickSwipeViewAttached *>(qmlAttachedPropertiesObject<QQuickSwipeView>(item));
311 if (attached)
312 QQuickSwipeViewAttachedPrivate::get(attached)->update(nullptr, -1);
313}
314
315#if QT_CONFIG(accessibility)
316QAccessible::Role QQuickSwipeView::accessibleRole() const
317{
318 return QAccessible::PageTabList;
319}
320#endif
321
322/*!
323 \qmlattachedproperty int QtQuick.Controls::SwipeView::index
324 \readonly
325
326 This attached property holds the index of each child item in the SwipeView.
327
328 It is attached to each child item of the SwipeView.
329*/
330
331/*!
332 \qmlattachedproperty bool QtQuick.Controls::SwipeView::isCurrentItem
333 \readonly
334
335 This attached property is \c true if this child is the current item.
336
337 It is attached to each child item of the SwipeView.
338*/
339
340/*!
341 \qmlattachedproperty bool QtQuick.Controls::SwipeView::isNextItem
342 \since QtQuick.Controls 2.1 (Qt 5.8)
343 \readonly
344
345 This attached property is \c true if this child is the next item.
346
347 It is attached to each child item of the SwipeView.
348*/
349
350/*!
351 \qmlattachedproperty bool QtQuick.Controls::SwipeView::isPreviousItem
352 \since QtQuick.Controls 2.1 (Qt 5.8)
353 \readonly
354
355 This attached property is \c true if this child is the previous item.
356
357 It is attached to each child item of the SwipeView.
358*/
359
360/*!
361 \qmlattachedproperty SwipeView QtQuick.Controls::SwipeView::view
362 \readonly
363
364 This attached property holds the view that manages this child item.
365
366 It is attached to each child item of the SwipeView.
367*/
368
370{
371 setCurrentIndex(swipeView ? swipeView->currentIndex() : -1);
372}
373
375{
376 if (i == currentIndex)
377 return;
378
379 Q_Q(QQuickSwipeViewAttached);
380 const bool wasCurrent = q->isCurrentItem();
381 const bool wasNext = q->isNextItem();
382 const bool wasPrevious = q->isPreviousItem();
383
384 currentIndex = i;
385 if (wasCurrent != q->isCurrentItem())
386 emit q->isCurrentItemChanged();
387 if (wasNext != q->isNextItem())
388 emit q->isNextItemChanged();
389 if (wasPrevious != q->isPreviousItem())
390 emit q->isPreviousItemChanged();
391}
392
393void QQuickSwipeViewAttachedPrivate::update(QQuickSwipeView *newView, int newIndex)
394{
395 Q_Q(QQuickSwipeViewAttached);
396 int oldIndex = index;
397 QQuickSwipeView *oldView = swipeView;
398
399 index = newIndex;
400 swipeView = newView;
401
402 if (oldView != newView) {
403 if (oldView) {
404 disconnect(oldView, &QQuickSwipeView::currentIndexChanged,
405 this, &QQuickSwipeViewAttachedPrivate::updateCurrentIndex);
406 }
407 if (newView) {
408 connect(newView, &QQuickSwipeView::currentIndexChanged,
409 this, &QQuickSwipeViewAttachedPrivate::updateCurrentIndex);
410 }
411 emit q->viewChanged();
412 }
413 if (oldIndex != newIndex)
414 emit q->indexChanged();
415
416 updateCurrentIndex();
417}
418
419QQuickSwipeViewAttached::QQuickSwipeViewAttached(QObject *parent)
420 : QObject(*(new QQuickSwipeViewAttachedPrivate), parent)
421{
422 if (!qobject_cast<QQuickItem *>(parent))
423 qmlWarning(parent) << "SwipeView: attached properties must be accessed from within a child item";
424}
425
426int QQuickSwipeViewAttached::index() const
427{
428 Q_D(const QQuickSwipeViewAttached);
429 return d->index;
430}
431
432bool QQuickSwipeViewAttached::isCurrentItem() const
433{
434 Q_D(const QQuickSwipeViewAttached);
435 return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex;
436}
437
438QQuickSwipeView *QQuickSwipeViewAttached::view() const
439{
440 Q_D(const QQuickSwipeViewAttached);
441 return d->swipeView;
442}
443
444bool QQuickSwipeViewAttached::isNextItem() const
445{
446 Q_D(const QQuickSwipeViewAttached);
447 return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex + 1;
448}
449
450bool QQuickSwipeViewAttached::isPreviousItem() const
451{
452 Q_D(const QQuickSwipeViewAttached);
453 return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex - 1;
454}
455
456QT_END_NAMESPACE
457
458#include "moc_qquickswipeview_p.cpp"
void updateCurrentIndex()
\qmlattachedproperty int QtQuick.Controls::SwipeView::index \readonly
Enables the user to navigate pages by swiping sideways.
void itemImplicitWidthChanged(QQuickItem *item) override
qreal getContentHeight() const override
qreal getContentWidth() const override
static QQuickSwipeViewPrivate * get(QQuickSwipeView *view)
Qt::Orientation orientation
void itemImplicitHeightChanged(QQuickItem *item) override
Combined button and popup list for selecting options.