У меня есть SwipeView с количеством страниц. Он разработан для небольшого круглого экрана диаметром 2,1 дюйма, и идея состоит в том, чтобы пролистывать влево или вправо между страницами, и каждая страница имеет один или несколько элементов пользовательского интерфейса для взаимодействия. Многие из этих страниц содержат Dial и маленькие /больше ничего. Может быть, кнопка внизу по центру.
При касании (предполагаемое устройство ввода) горизонтальное перетаскивание внутри Dial чаще всего интерпретируется как навигация по SwipeView под ним. Очень редко он распознает, что я хочу отрегулировать циферблат.
С помощью мыши Dial, кажется, довольно надежно захватывает жест перетаскивания, так что даже горизонтальное перетаскивание (например, сверху или снизу циферблата) не позволяет непреднамеренно перемещаться между страницами в SwipeView.
Посмотрите это видео для сравнения поведения касания и мыши (я не смог загрузить его прямо в редакторе StackOverflow, поэтому надеюсь, что ссылка на imgur приемлема)
Есть ли способ дать Dial более высокий приоритет над интерпретацией жестов касания / пролистывания, чтобы пользователь не мог случайно пролистать между страницами? (Больше похоже на поведение мыши)
Я могу обойти это, начав жест вертикально, а затем переместившись в нужное положение, но я бы предпочел не сообщать об этом моему пользователю, и это, кажется, их наиболее частое зависание в этом приложении.
Циферблаты составляют 70% от размера самого окна, поэтому за пределами циферблатов у пользователя достаточно места, чтобы провести пальцем по SwipeView.
Я пытался настроить SwipeView interactive: !(dial1.pressed || dial2.pressed)
и т. д., но это не работает. Казалось бы, свойство .pressed
циферблата не вступает в силу до тех пор, пока циферблат окончательно не будет выбран для обработки ввода. Я бы предпочел, чтобы в данном конкретном случае он вел себя так же, как с мышью.
При рассмотрении SwipeView, который является чисто interactive: false
— так что Dial гарантированно улавливает жесты — мне пришлось бы добавить кнопки на каждый экран для навигации между страницами, и это уберет место, которое у меня есть для другого пользовательского интерфейса. элементы. Страницы набора - единственные, которые вызывают у меня проблемы. На других страницах уже есть 1-3 кнопки в местах, где мало риска конфликтного жеста. Если мне нужно добавить кнопку с любой стороны страницы, это начинает сжимать вещи до такой степени, что становится трудно попасть на предполагаемый размер экрана.
Единственная другая альтернатива, которую я могу придумать на данный момент, — это кнопка редактирования / выполнения (например, модальное диалоговое окно?), но это добавляет некоторые трения, которых я бы предпочел избежать.
Этот код является минимальным воспроизводимым примером, как показано на видео. В последний раз я пробовал в Qt 6.3.0 на Ubuntu 20.04 с сенсорным экраном USB/HDMI.
import QtQuick
import QtQuick.Controls.Basic
Window {
width: 480
height: 480
visible: true
title: "SwipeView Dial Test"
SwipeView {
anchors.fill: parent
Item {
Dial {
id: dial1
anchors.centerIn: parent
width: parent.width * 0.7
height: parent.height * 0.7
}
}
Item {
Dial {
id: dial2
anchors.centerIn: parent
width: parent.width * 0.7
height: parent.height * 0.7
}
}
}
}
Действительно похоже, что есть проблема с обработчиком перетаскивания Dial
. Такое ощущение, что не весь элемент управления покрывается обработчиком перетаскивания, поэтому события подхватываются SwipeView
в неожиданное время.
Я создал обходной путь, заплатив Dial
с помощью DialPatched.qml
.
В моей реализации я создал макет Rectangle
, который находится поверх Dial
. Мнимый прямоугольник теперь будет получать события перетаскивания через свой MouseArea
, который имеет preventStealing: true
. Мы наблюдаем за изменениями в положении мыши и реконструируем значение с помощью Math.atan2()
, чтобы преобразовать векторы в углы и вычислить новое значение для циферблата.
Чтобы увидеть макет прямоугольника, я окрасил его в почти прозрачный «красный цвет», чтобы вы могли видеть и прямоугольник, и циферблат под ним. Если вы собираетесь использовать этот подход, я рекомендую установить непрозрачность на 0 или заменить прямоугольник на элемент-заполнитель.
Кроме того, я внес небольшую поправку в ваш расчет ширины/высоты.
import QtQuick
import QtQuick.Controls
Page {
SwipeView {
anchors.fill: parent
Item {
DialPatched {
id: dial1
anchors.centerIn: parent
debug: debugCheckBox.checked
width: Math.min(parent.width,parent.height) * 0.7
height: width
}
}
Item {
DialPatched {
id: dial2
anchors.centerIn: parent
debug: debugCheckBox.checked
width: Math.min(parent.width,parent.height) * 0.7
height: width
}
}
}
CheckBox { id: debugCheckBox; text: "Debug"; checked: true }
}
// DialPatched.qml
import QtQuick
import QtQuick.Controls
Dial {
id: dial
property bool debug: true
Item {
anchors.fill: parent
Rectangle {
width: parent.width
height: parent.height
color: debug ? "red" : "transparent"
opacity: debug ? 0.05 : 0
property int startX: 0
property int startY: 0
onXChanged: Qt.callLater(mouseMove, startX+x, startY+y)
onYChanged: Qt.callLater(mouseMove, startX+x, startY+y)
MouseArea {
anchors.fill: parent
drag.target: parent
preventStealing: true
onPressed: function (mouse) {
parent.startX = mouse.x;
parent.startY = mouse.y;
parent.Drag.active = true;
}
onReleased: {
parent.Drag.active = false;
parent.x = 0;
parent.y = 0;
}
}
function mouseMove(mx,my) {
if (Drag.active) {
let ang = Math.atan2(height/2 - my, mx - width/2) * 180 / Math.PI;
ang = (360 + 270 - Math.round(ang)) % 360;
dial.value = (ang - 40) / 280 * (dial.to - dial.from) + dial.from;
}
}
}
}
}
Вы можете Попробовать онлайн!