QML PinchArea не работает должным образом с QML Flickable

Итак, я реализовал простую программу просмотра изображений и хотел реализовать масштабирование внутри Flickable. Посмотрев несколько примеров, я наткнулся на это и подумал, что могу сделать что-то подобное. Однако, когда я тестировал код (Qt 5.13 на Android), он не работал должным образом. Проблема в том, что когда изображение масштабируется, PinchArea перестает работать, и пользователь не может уменьшить масштаб, в то время как Flickable по-прежнему позволяет «пролистывать» изображение (на этом уровне масштабирования). Вот код, в котором я не нашел ни одной ошибки:

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Flickable Image Zoom Example")

    Page {
        id: imagePage

        property string imgUrl: "qrc:/messi.jpg"
        property string strHpTitle: ""
        property string strThumbnailUrl: ""

        anchors.fill: parent
        Flickable {
            id: imageFlickable
            anchors.fill: parent
            contentWidth: imageContainer.width; contentHeight: imageContainer.height
            clip: true
            onHeightChanged: if (imagePreview.status === Image.Ready) imagePreview.fitToScreen();

            Item {
                id: imageContainer
                width: Math.max(imagePreview.width * imagePreview.scale, imageFlickable.width)
                height: Math.max(imagePreview.height * imagePreview.scale, imageFlickable.height)

                Image {
                    id: imagePreview

                    property real prevScale

                    function fitToScreen() {
                        scale = Math.min(imageFlickable.width / width, imageFlickable.height / height, 1)
                        pinchArea.minScale = scale
                        prevScale = scale
                    }

                    anchors.centerIn: parent
                    fillMode: Image.PreserveAspectFit
                    cache: false
                    asynchronous: true
                    source: imagePage.imgUrl
                    sourceSize.height: 1000;
                    smooth: !imageFlickable.moving

                    onStatusChanged: {
                        if (status == Image.Ready) {
                            fitToScreen()
                        }
                    }
                    onScaleChanged: {
                        if ((width * scale) > imageFlickable.width) {
                            var xoff = (imageFlickable.width / 2 + imageFlickable.contentX) * scale / prevScale;
                            imageFlickable.contentX = xoff - imageFlickable.width / 2
                        }
                        if ((height * scale) > imageFlickable.height) {
                            var yoff = (imageFlickable.height / 2 + imageFlickable.contentY) * scale / prevScale;
                            imageFlickable.contentY = yoff - imageFlickable.height / 2
                        }
                        prevScale = scale
                    }
                }
            }

            PinchArea {
                id: pinchArea

                property real minScale: 1.0
                property real maxScale: 3.0

                anchors.fill: parent
                pinch.target: imagePreview
                pinch.minimumScale: minScale
                pinch.maximumScale: maxScale
                pinch.dragAxis: Pinch.XandYAxis

                onPinchFinished: {
                    imageFlickable.returnToBounds()
                }
            }
        }
    }
}

person reckless    schedule 14.08.2019    source источник


Ответы (1)


Итак, я нашел решение этой проблемы. Проблема (я думаю) связана с ошибкой. По какой-то странной причине Flickable в моем коде крадет события касания из PinchArea, поэтому события касания с защемлением игнорируются и передаются Flickable. Чтобы решить эту проблему, я нашел обходной путь, заключающийся в создании MouseArea внутри PinchArea, это позволяет PinchArea получать события касания, чтобы Flickable не крала их. Итак, с обходным решением мой код имеет следующую структуру:

Flickable{
   PinchArea{
      MouseArea{ anchors.fill: parent} // this is the workaround
   }
   Item{}
}

Я сообщил об ошибке здесь и загрузил небольшое видео, показывающее причину.

person reckless    schedule 15.08.2019