Drag'n'Drop QML में - यह आसान है! या लक्ष्य के 5 चरण

यह पोस्ट " स्मार्ट फोन फॉर स्मार्ट पोस्ट " प्रतियोगिता में भाग ले रही है।

Drag'n'Drop उपयोगकर्ता की बातचीत और चित्रमय वातावरण में एक महत्वपूर्ण रूप से महत्वपूर्ण तत्व है। दुर्भाग्य से, QML में व्यू के लिए कोई अंतर्निहित Drag'n'Drop तंत्र नहीं है। इसलिए, मैंने 16 चित्रों के साथ ग्रिडविद पर आधारित एक छोटा सा उदाहरण लिखा।

यह Drag'n'Drop उदाहरण सही होने का दिखावा नहीं करता है (ऐसे कई अन्य कार्यान्वयन हैं जो नेत्रहीन रूप से अधिक सटीक हैं), लेकिन इसका उद्देश्य यह दिखाना है कि क्यूएमएल एक बहुत ही लचीला और सरल विकास उपकरण है।

सबसे पहले, एक छोटा वीडियो, और एक समान परिणाम प्राप्त करने के लिए कट 5 सरल चरणों के तहत।



चरण 1. एक ग्रिड व्यू बनाएं


चलो एक GridView और एक छोटा मॉडल बनाकर शुरू करते हैं। परीक्षण डेटा के रूप में, मैंने नोकिया N8 से मानक चित्र लिए।
चलो हमारे ग्रिड 4x4 छवि आकार बनाते हैं।
Rectangle { width: 420 height: 420 color: "#000000" Component { id: dndDelegate Item { id: wrapper width: dndGrid.cellWidth height: dndGrid.cellHeight Image { id: itemImage source: imagePath anchors.centerIn: parent width: 90 height: 90 smooth: true fillMode: Image.PreserveAspectFit } } } ListModel { id: dndModel ListElement { imagePath: "images/1.jpg" } // 15  } GridView { id: dndGrid anchors.fill: parent anchors.margins: 10 cellWidth: 100 cellHeight: 100 model: dndModel delegate: dndDelegate } } 

Qmlviewer में शुरू करने के बाद, हम निम्नलिखित चित्र देखेंगे


चरण 2. Drag'nDrop जोड़ें


अब हमें इस ग्रिड में छवियों को खींचने और छोड़ने की क्षमता जोड़ने की आवश्यकता है।

कार्य को सरल बनाने के लिए, ग्रिड व्यू स्क्रॉल करने की क्षमता को अक्षम करें। आप इसके बिना कर सकते हैं (डी'एन'डी के लिए सामान्य प्रेस के बजाय एक लंबे प्रेस का उपयोग करके और इंटरएक्टिव प्रॉपर्टी में हेरफेर करके (जो यह निर्धारित करता है कि ग्रैडव्यू स्क्रॉल करेंगे) इसी माउसएयर कॉलबैक में), लेकिन यह उदाहरण को जटिल करेगा।

हम एक माउसआयर तत्व को पूरे GridView के आकार में भी जोड़ते हैं, जो ड्रैग की शुरुआत में माउस क्लिक को पकड़ लेगा, साथ ही माउस को छोड़ने पर मॉडल में तत्व को वांछित स्थिति में ले जाएगा। इसके अलावा, GridView में हम एक और अतिरिक्त dndContainer तत्व डालेंगे , जिसके बारे में हम बाद में बात करेंगे

अंतिम स्पर्श वर्तमान आइटम को स्थानांतरित करने के लिए (या इसके बजाय, मॉडल में इसका सूचकांक) संग्रहीत करने के लिए हमारे ग्रिड व्यू में एक संपत्ति जोड़ना है।
 property int draggedItemIndex: -1 interactive: false Item { id: dndContainer anchors.fill: parent } MouseArea { id: coords anchors.fill: parent onReleased: { if (dndGrid.draggedItemIndex != -1) { var draggedIndex = dndGrid.draggedItemIndex dndGrid.draggedItemIndex = -1 dndModel.move(draggedIndex,dndGrid.indexAt(mouseX, mouseY),1) } } onPressed: { dndGrid.draggedItemIndex = dndGrid.indexAt(mouseX, mouseY) } } 

हम प्रतिनिधि के साथ inDrag राज्य को जोड़ते हैं, जो इस तत्व के चलने पर सक्रिय हो जाएगा। यह वह जगह है जहाँ हमें dndContainer की आवश्यकता है। हम इसे पकड़ लेंगे (और अधिक सटीक होने के लिए, फिर इस कंटेनर में माता-पिता को बदल दें) हमारा घूमने वाला तत्व। माता-पिता को बदलने के अलावा, हम तत्व के एंकरों को भी खोलते हैं (ताकि यह स्थानांतरित हो सके) और माउस के निर्देशांक के अनुसार x और y सेट करें (और, बाइंडिंग के लिए धन्यवाद, माउस कर्सर की गति के साथ अनकही छवि की स्थिति बदल जाएगी)। जब राज्य निष्क्रिय हो जाता है, तो इन सभी परिवर्तनों को वापस ले लिया जाता है।
 states: [ State { name: "inDrag" when: index == dndGrid.draggedItemIndex PropertyChanges { target: itemImage; parent: dndContainer } PropertyChanges { target: itemImage; anchors.centerIn: undefined } PropertyChanges { target: itemImage; x: coords.mouseX - itemImage.width / 2 } PropertyChanges { target: itemImage; y: coords.mouseY - itemImage.height / 2 } } ] 

दौड़ते हुए हम इस तस्वीर को कुछ इस तरह देखेंगे। अब, हम अपने ग्रिड में तत्वों को सुरक्षित रूप से स्थानांतरित कर सकते हैं।


चरण 3. जंगम आइटम रेंडर करें


ठीक है, हमने यह करना सीखा कि यह लेख किस लिए लिखा गया था (यह सरल है, है न?)। लेकिन स्थानांतरित तत्व लगभग ध्यान देने योग्य नहीं है, बाकी के खिलाफ इसे थोड़ा उजागर करना आवश्यक है। खींचे गए चित्र के चारों ओर एक सफेद फ्रेम जोड़ें।
निम्नलिखित कोड को हमारे आइटम में पेस्ट करें।
 Rectangle { id: imageBorder anchors.fill: parent radius: 5 color: "transparent" border.color: "#ffffff" border.width: 6 opacity: 0 } 

इसके अलावा, किसी तरह उस स्थान को चिन्हित करना अच्छा है जहां से खींची गई वस्तु को लिया गया था। इस स्थान के केंद्र में एक सफेद वृत्त जोड़ें। यह कोड हमारे आइटम के आगे रखा गया है
 Rectangle { id: circlePlaceholder width: 30; height: 30; radius: 30 smooth: true anchors.centerIn: parent color: "#cecece" opacity: 0 } 

जब आप प्रतिनिधि के inDrag राज्य में खींचना शुरू करते हैं, तो उनका प्रदर्शन जोड़ें।
 State { name: "inDrag" when: index == dndGrid.draggedItemIndex PropertyChanges { target: circlePlaceholder; opacity: 1 } PropertyChanges { target: imageBorder; opacity: 1 } PropertyChanges { target: itemImage; parent: dndContainer } PropertyChanges { target: itemImage; anchors.centerIn: undefined } PropertyChanges { target: itemImage; x: coords.mouseX - itemImage.width / 2 } PropertyChanges { target: itemImage; y: coords.mouseY - itemImage.height / 2 } } 

अब हमारा उदाहरण इस तरह दिखता है।


चरण 4. एनीमेशन जोड़ें


खैर, हमारे ग्रिड का आधार Drag'n'Drop के साथ तैयार है। एक सीटी जोड़ें। और अधिक विशेष रूप से, एनीमेशन जोड़ें।

शुरू करने के लिए, हम दो राज्यों को हमारे लंबे समय से पीड़ित आइटम में जोड़ देंगे :

इस प्रकार, हम घसीटे गए को छोड़कर सभी तत्वों को थोड़ा अस्पष्ट करते हैं, जो हमें बाकी की पृष्ठभूमि के खिलाफ उत्तरार्द्ध की अधिक दृश्यता प्रदान करता है।

हम छवि की पारदर्शिता, चौड़ाई और ऊंचाई के लिए एनिमेटेड परिवर्तन भी जोड़ते हैं।
 state: "inactive" states: [ State { name: "greyedOut" when: (dndGrid.draggedItemIndex != -1) && (dndGrid.draggedItemIndex != index) PropertyChanges { target: itemImage; opacity: 0.8} }, State { name: "inactive" when: (dndGrid.draggedItemIndex == -1) || (dndGrid.draggedItemIndex == index) PropertyChanges { target: itemImage; opacity: 1.0} } ] Behavior on width { NumberAnimation { duration: 300; easing.type: Easing.InOutQuad } } Behavior on height { NumberAnimation { duration: 300; easing.type: Easing.InOutQuad } } Behavior on opacity {NumberAnimation { duration: 300; easing.type: Easing.InOutQuad } } 

InDrag राज्य में, हम चित्र की ऊँचाई और चौड़ाई में परिवर्तन और इस अवस्था से किसी अन्य में परिवर्तन (यानी, सक्रिय ड्रैगनेनड्रॉप से ​​सामान्य मोड में संक्रमण) जोड़ते हैं। इस परिवर्तन में, हम एक स्केल एनीमेशन बनाएंगे।
 states: [ State { name: "inDrag" when: index == dndGrid.draggedItemIndex PropertyChanges { target: circlePlaceholder; opacity: 1 } PropertyChanges { target: imageBorder; opacity: 1 } PropertyChanges { target: itemImage; parent: dndContainer } PropertyChanges { target: itemImage; width: 80 } PropertyChanges { target: itemImage; height: 80 } PropertyChanges { target: itemImage; anchors.centerIn: undefined } PropertyChanges { target: itemImage; x: coords.mouseX - itemImage.width / 2 } PropertyChanges { target: itemImage; y: coords.mouseY - itemImage.height / 2 } } ] transitions: [ Transition { from: "inDrag" to: "*" PropertyAnimation { target: itemImage properties: "scale, opacity" easing.overshoot: 1.5 easing.type: "OutBack" from: 0.0 to: 1.0 duration: 750 } } ] 

हम घसीट आइटम के चारों ओर फ्रेम में और खरोंच से सर्कल में पारदर्शिता परिवर्तन एनिमेशन भी जोड़ते हैं।
 Behavior on opacity { NumberAnimation { duration: 300; easing.type: Easing.InOutQuad } } 

नतीजतन, हमें पहले से ही ऐसी तस्वीर मिली।


और यह एक मध्यवर्ती क्षण में फिल्माया गया था, जब एनीमेशन काम करता है।


चरण 5. अंतिम स्पर्श


और, एक निष्कर्ष के रूप में, हम उस स्थिति का एक संकेतक जोड़ेंगे जहां आइटम स्थानांतरित किया जाएगा। हम इसे इस तत्व के बाईं ओर एक ऊर्ध्वाधर पट्टी के रूप में प्रदर्शित करते हैं।

इस तत्व का जनक हमारा ग्रिड व्यू होगा, इसके साथ सभी क्रियाएं एक ही स्थान पर होंगी।

सबसे पहले, ग्रिड व्यू में तीन नए गुण जोड़ें: लक्ष्य तत्व सूचकांक ( संभवड्रॉपइंडेक्स ) और वर्तमान माउस निर्देशांक ( xCoordinateInPossibleDrop और yCoordinateInPossibleDrop )।

साथ ही, इंडिकेटर तत्व को स्वयं जोड़ें। यह एक सामान्य 6x1 पिक्सेल ढाल छवि है जो लंबवत रूप से दोहराई जाती है। संकेतक में दो राज्य हैं: अदृश्य (डिफ़ॉल्ट) और दिखाया गया है । दूसरे राज्य में, संकेतक तत्व को लक्ष्य के बाईं ओर दो चित्रों के बीच रखा गया है। तत्व की स्थिति की गणना अंतिम दो गुणों के आधार पर की जाती है, न कि मॉडल में सूचकांक के आधार पर, जिससे हम तालिका में वर्तमान संख्या स्तंभों पर निर्भर नहीं होते हैं।
 property int possibleDropIndex: -1 property int xCoordinateInPossibleDrop: -1 property int yCoordinateInPossibleDrop: -1 Item { id: dropPosIndicator visible: false height: dndGrid.cellHeight width: 10 Image { visible: parent.visible anchors.centerIn: parent height: parent.height-10 source: "drop-indicator.png" } states: [ State { name: "shown" when: dndGrid.possibleDropIndex != -1 PropertyChanges { target: dropPosIndicator visible: true x: Math.floor(dndGrid.xCoordinateInPossibleDrop/dndGrid.cellWidth) * dndGrid.cellWidth - 5 y: Math.floor(dndGrid.yCoordinateInPossibleDrop/dndGrid.cellHeight) * dndGrid.cellHeight } } ] } 


MouseArea में एक और हैंडलर भी जोड़ें। यहां हमें ड्रॉप स्थान के सूचकांक के साथ एक संपत्ति की आवश्यकता है, ताकि हर बार माउस के निर्देशांक को अपडेट न करें, लेकिन केवल लक्ष्य तत्व को बदलते समय उन्हें बदल दें।
 onPositionChanged: { var newPos = dndGrid.indexAt(mouseX, mouseY) if (newPos != dndGrid.possibleDropIndex) { dndGrid.possibleDropIndex = newPos dndGrid.xCoordinateInPossibleDrop = mouseX dndGrid.yCoordinateInPossibleDrop = mouseY } } 

नतीजतन, हमें ऐसा एक आवेदन मिलता है। पोस्ट की शुरुआत में वीडियो की तरह ही :)


अच्छी तरह से और हाँ, आप पूर्ण स्रोत (प्रत्येक चरण के लिए अलग .qml फ़ाइलों के साथ) डाउनलोड कर सकते हैं

Source: https://habr.com/ru/post/In134377/


All Articles