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