How to implement GRID/TILED Image View with scroll

2020-05-29 10:06发布

问题:

I want to implement GRID/TILED Image View where tile images will be drawn on the fly after being downloaded. I want to be able to do pinch/zoom and other touch actions in it. Say, If I pan the view, new tiles will be loaded and drawn on the view fully or partially. I couldn't find a way to do it with any existing UI control. Also those existing UI controls can not be subclassed and do not have any paint()/onDraw method (like view/canvas in android) to override. May be imageView with scrollview can solve the problem. The other option might be using foreign Window. In both cases I am not sure how they can be implemented or how gestures will be handled in those cases.Or if there any other way to do it. Please give me some insights to solve it.

回答1:

Create a CustomImageView that would load image from remote and put that CustomImageView in a ListView with GridListLayout. You can use ListItemProvider class to customize your ListView. I have given code for all necessary classes below.

//main.qml

import bb.cascades 1.0
import my.library 1.0 //Custom library where CustomImageView and our ListProvider resides

Page {
    content: ScrollView {
        gestureHandlers: [
            PinchHandler {
                onPinchUpdated: {
                    scrollView.zoomToPoint(event.midPointX, event.midPointY, event.pinchRatio)
                }
            }
        ]
        id: scrollView
        scrollViewProperties {
            scrollMode: ScrollMode.None
            pinchToZoomEnabled: true
        }
        ListView {
            overlapTouchPolicy: OverlapTouchPolicy.Allow
            objectName: "listView"
            layout: GridListLayout {
                columnCount: 2
            }
            listItemProvider: CustomImageViewProvider { //Our list item provider
            }
            listItemComponents: [
                ListItemComponent {
                    CustomImageView { //CustomImageView to load image from remote via internet
                    }
                }
            ]
            dataModel: XmlDataModel {
                source: "model/path.xml"
            }
        }
    }
}

//CustomImageView.cpp CustomControl to load image form remote location via internet

CustomImageView::CustomImageView(Container *parent) :
    CustomControl(parent) {
    Container *contentContainer = new Container();
    DockLayout *contentLayout = new DockLayout();
    contentContainer->setLayout(contentLayout);

    mItemImage = ImageView::create("");
    mItemImage->setHorizontalAlignment(HorizontalAlignment::Fill);
    mItemImage->setVerticalAlignment(VerticalAlignment::Fill);

    contentContainer->add(mItemImage);

    setRoot(contentContainer);
}

void CustomImageView::updateItem(const QString imagePath) {
    WebServiceRequest *webServiceRequest = new WebServiceRequest(imagePath);
    connect(webServiceRequest, SIGNAL(complete(QByteArray, bool)), this,
            SLOT(onComplete(QByteArray, bool)));
    webServiceRequest->getResponse();
}

void CustomImageView::onComplete(QByteArray data, bool success) {
    if (success) {
        mItemImage->setImage(Image(data));
        mItemImage->setVisible(true);
    } else {
        qDebug() << "Request failed";
    }
}

void CustomImageView::select(bool select) {
}

void CustomImageView::reset(bool selected, bool activated) {
    mItemImage->setVisible(false);
}

void CustomImageView::activate(bool activate) {
}

//WebServiceRequest.cpp This class used by CustomImageView to send request for the image via internet

WebServiceRequest::WebServiceRequest(QString url) {
    webServiceUrl = url;
}

WebServiceRequest::~WebServiceRequest() {
}

void WebServiceRequest::getResponse() {
    QNetworkAccessManager* netManager = new QNetworkAccessManager();
    if (!netManager) {
        qDebug() << "Unable to create QNetworkAccessManager!";
        emit complete("Unable to create QNetworkAccessManager!", false);
        return;
    }

    QUrl url(webServiceUrl);
    QNetworkRequest req(url);

    QNetworkReply* ipReply = netManager->get(req);
    connect(ipReply, SIGNAL(finished()), this, SLOT(onReply()));
}

void WebServiceRequest::onReply() {
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    QString response;
    bool success = false;
    if (reply) {
        if (reply->error() == QNetworkReply::NoError) {
            int available = reply->bytesAvailable();
            if (available > 0) {
                success = true;
                emit complete(reply->readAll(), success);
            }
        } else {
            response =
                    QString("Error: ") + reply->errorString()
                        + QString(" status:")
                        + reply->attribute(
                                    QNetworkRequest::HttpStatusCodeAttribute).toString();
        }
        reply->deleteLater();
    }
}

//CustomImageViewProvider.cpp This is our ListItemProvider used to customize our ListView

CustomImageViewProvider::CustomImageViewProvider() {
}

VisualNode * CustomImageViewProvider::createItem(ListView* list,
        const QString &type) {
    CustomImageView *myCustomImageView = new CustomImageView();
    return myCustomImageView;
}

void CustomImageViewProvider::updateItem(ListView* list,
        bb::cascades::VisualNode *listItem, const QString &type,
        const QVariantList &indexPath, const QVariant &data) {
    QVariantMap map = data.value<QVariantMap>();
    CustomImageView *myCustomImageView = static_cast<CustomImageView *>(listItem);
    qDebug() << indexPath;
    QString imagePath = map["path"].toString();
    myCustomImageView->updateItem(imagePath);
}

Register CustomImageView & CustomImageViewProvider with qml before creating and setting the root of main.qml in constructor. So that they are available in our qml

qmlRegisterType < CustomImageView > ("my.library", 1, 0, "CustomImageView");
qmlRegisterType < CustomImageViewProvider > ("my.library", 1, 0, "CustomImageViewProvider");

//Path.xml All path are stored in this file which is used as DataModel in list view

<root>
    <image path="http://upload.wikimedia.org/wikipedia/commons/e/eb/A_landscape_in_Peradeniya,_Sri_Lanka.jpg"/>
    <image path="http://lejournaldelaphotographie.com/system/photos/54840/med_fernando-brito_lost-in-the-landscape_1-jpg.jpg"/>
    <image path="http://st.houzz.com/simgs/17713aee00b8b8b7_15-7678/modern-landscape.jpg"/>

    <image path="http://cdn.c.photoshelter.com/img-get/I0000kRJbKDHBT30/s/900/720/Landscape-sunset-15.jpg"/>
    <image path="http://www.cashmoredesign.com/images/large/landscape-5.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/11/50b7d0ddb3fc4b239a0000f2_arteology-atelier-37-2_-atelier37-2_arteologie-34-528x396.jpg"/>

    <image path="http://upload.wikimedia.org/wikipedia/en/e/e8/Berchem,_Nicolaes_~_Landscape_with_Herdsmen_Gathering_Sticks,_early_1650s,_oil_on_panel,_private_collection,_New_York.jpg"/>
    <image path="http://www.taschen.com/media/images/960/teaser_mi_arch_now_landscape_top_1203301047_id_536230.jpg"/>
    <image path="http://lasersandlights.com/images/medium/landscape%20bliss%20spright.jpg"/>

    <image path="http://uploads0.wikipaintings.org/images/pieter-bruegel-the-elder/landscape-with-the-flight-into-egypt-1563.jpg"/>
    <image path="http://middo.me/wp-content/uploads/2012/07/Landscape-with-calm-river-1024x640.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/07/500de84928ba0d609d000038_fort-werk-aan-t-spoel-rietveld-landscape_rob6999kopierl-528x352.jpg"/>

        <image path="http://upload.wikimedia.org/wikipedia/commons/e/eb/A_landscape_in_Peradeniya,_Sri_Lanka.jpg"/>
    <image path="http://lejournaldelaphotographie.com/system/photos/54840/med_fernando-brito_lost-in-the-landscape_1-jpg.jpg"/>
    <image path="http://st.houzz.com/simgs/17713aee00b8b8b7_15-7678/modern-landscape.jpg"/>

    <image path="http://cdn.c.photoshelter.com/img-get/I0000kRJbKDHBT30/s/900/720/Landscape-sunset-15.jpg"/>
    <image path="http://www.cashmoredesign.com/images/large/landscape-5.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/11/50b7d0ddb3fc4b239a0000f2_arteology-atelier-37-2_-atelier37-2_arteologie-34-528x396.jpg"/>

    <image path="http://upload.wikimedia.org/wikipedia/en/e/e8/Berchem,_Nicolaes_~_Landscape_with_Herdsmen_Gathering_Sticks,_early_1650s,_oil_on_panel,_private_collection,_New_York.jpg"/>
    <image path="http://www.taschen.com/media/images/960/teaser_mi_arch_now_landscape_top_1203301047_id_536230.jpg"/>
    <image path="http://lasersandlights.com/images/medium/landscape%20bliss%20spright.jpg"/>

    <image path="http://uploads0.wikipaintings.org/images/pieter-bruegel-the-elder/landscape-with-the-flight-into-egypt-1563.jpg"/>
    <image path="http://middo.me/wp-content/uploads/2012/07/Landscape-with-calm-river-1024x640.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/07/500de84928ba0d609d000038_fort-werk-aan-t-spoel-rietveld-landscape_rob6999kopierl-528x352.jpg"/>

        <image path="http://upload.wikimedia.org/wikipedia/commons/e/eb/A_landscape_in_Peradeniya,_Sri_Lanka.jpg"/>
    <image path="http://lejournaldelaphotographie.com/system/photos/54840/med_fernando-brito_lost-in-the-landscape_1-jpg.jpg"/>
    <image path="http://st.houzz.com/simgs/17713aee00b8b8b7_15-7678/modern-landscape.jpg"/>

    <image path="http://cdn.c.photoshelter.com/img-get/I0000kRJbKDHBT30/s/900/720/Landscape-sunset-15.jpg"/>
    <image path="http://www.cashmoredesign.com/images/large/landscape-5.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/11/50b7d0ddb3fc4b239a0000f2_arteology-atelier-37-2_-atelier37-2_arteologie-34-528x396.jpg"/>

    <image path="http://upload.wikimedia.org/wikipedia/en/e/e8/Berchem,_Nicolaes_~_Landscape_with_Herdsmen_Gathering_Sticks,_early_1650s,_oil_on_panel,_private_collection,_New_York.jpg"/>
    <image path="http://www.taschen.com/media/images/960/teaser_mi_arch_now_landscape_top_1203301047_id_536230.jpg"/>
    <image path="http://lasersandlights.com/images/medium/landscape%20bliss%20spright.jpg"/>

    <image path="http://uploads0.wikipaintings.org/images/pieter-bruegel-the-elder/landscape-with-the-flight-into-egypt-1563.jpg"/>
    <image path="http://middo.me/wp-content/uploads/2012/07/Landscape-with-calm-river-1024x640.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/07/500de84928ba0d609d000038_fort-werk-aan-t-spoel-rietveld-landscape_rob6999kopierl-528x352.jpg"/>

        <image path="http://upload.wikimedia.org/wikipedia/commons/e/eb/A_landscape_in_Peradeniya,_Sri_Lanka.jpg"/>
    <image path="http://lejournaldelaphotographie.com/system/photos/54840/med_fernando-brito_lost-in-the-landscape_1-jpg.jpg"/>
    <image path="http://st.houzz.com/simgs/17713aee00b8b8b7_15-7678/modern-landscape.jpg"/>

    <image path="http://cdn.c.photoshelter.com/img-get/I0000kRJbKDHBT30/s/900/720/Landscape-sunset-15.jpg"/>
    <image path="http://www.cashmoredesign.com/images/large/landscape-5.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/11/50b7d0ddb3fc4b239a0000f2_arteology-atelier-37-2_-atelier37-2_arteologie-34-528x396.jpg"/>

    <image path="http://upload.wikimedia.org/wikipedia/en/e/e8/Berchem,_Nicolaes_~_Landscape_with_Herdsmen_Gathering_Sticks,_early_1650s,_oil_on_panel,_private_collection,_New_York.jpg"/>
    <image path="http://www.taschen.com/media/images/960/teaser_mi_arch_now_landscape_top_1203301047_id_536230.jpg"/>
    <image path="http://lasersandlights.com/images/medium/landscape%20bliss%20spright.jpg"/>

    <image path="http://uploads0.wikipaintings.org/images/pieter-bruegel-the-elder/landscape-with-the-flight-into-egypt-1563.jpg"/>
    <image path="http://middo.me/wp-content/uploads/2012/07/Landscape-with-calm-river-1024x640.jpg"/>
    <image path="http://ad009cdnb.archdaily.net/wp-content/uploads/2012/07/500de84928ba0d609d000038_fort-werk-aan-t-spoel-rietveld-landscape_rob6999kopierl-528x352.jpg"/>
</root>