How to make Drag and drop in NativeScript

Raj Bhatt
Raj Bhatt
Apr 14, 2020 · 4 min read
An IDE tools image while programming
An IDE tools image while programming

Background

Recently I worked on a mobile application which required cool functionality that includes the scenario where the user should be able to rearrange items using gestures. The whole process is to create a puzzle that the user needs to be set in the right order, Sounds crazy.

Application is built using NativeScript-Vue. To fulfil requirements, I used Nativescript Gesture API for the implementation, after applying lots of gestures I ended up with a panning gesture to create drag and drop functionality.

We are going to make drag and drop functionality in ios and Android using NativeScript built with Vue. Here is an animated image of what we are going to build in the next steps.

Here, its GitHub repository https://github.com/rjbhatt110/nativescript-drag-drop-fn of this implementation.

Image for post
Image for post

A dropArea (Grey-boxes) and random ordered draggable Object (Color-boxes) appear on the screen. Using gestures, the user is able to drag an object to the drop area to set the right order.

Getting Started

Create a New Project

Before creating a new project I assume that you already set up a NativeScript environment on your system.

Let’s create a new project. From the terminal or command line, execute the following command.

vue init nativescript-vue/vue-cli-template <project-name>
cd <project-name>
tns platform add ios
tns platform add android
tns run ios
tns run android

Developing Basic Drag and drop Features

Starting with the basic code of drag and drop features. open app.vuefile and After that, we begin with UI structure by adding an Image of dropArea with @pan event and its reference dropArea0 on it.

After adding a UI, it’s time to include logic by adding the following javascript code.

In the above code, we take reference of UI element in the mounted() a method. Later on, we use that reference as nativeview to access properties of an image using onPan() events which handle three states of panning gesture.

onPan() event args.states === 2 we assign our deltaX and deltaY to translateX and translateY which create dragging.

Adding a More UI Element and make it draggable

Next thing is to add more elements in UI code that contain four dropArea (Grey-boxes) and four draggable Object (Color-boxes) with arrays named boxArray which bind into an image tag with v-for attributes.

We are also updating our logic as well by passing an event, index and dragObject to onPan() a method as an argument. after that, we create boxArray for a binding UI element that we used in the v-for loop and add all references in mounted() a method.

Handling dropArea and dragObject

It’s time to play with animation, The following code implements scale up animation when an object comes over the drop area. So, we have to write this code for other drop areas as well.

if (this.$refs[ref][0].nativeView.getLocationOnScreen().x >=
this.dropArea0.getLocationOnScreen().x &&
this.$refs[ref][0].nativeView.getLocationOnScreen().x <=
this.dropArea0.getLocationOnScreen().x + this.dropArea0.width &&
this.$refs[ref][0].nativeView.getLocationOnScreen().y >=
this.dropArea0.getLocationOnScreen().y &&
this.$refs[ref][0].nativeView.getLocationOnScreen().y <=
this.dropArea0.getLocationOnScreen().y + this.dropArea0.height
) {
this.dropArea0.scaleX = 1.1;
this.dropArea0.scaleY = 1.1;
} else {
this.dropArea0.scaleX = 1;
this.dropArea0.scaleY = 1;
}

Now we are going to manage animation of the draggable object and start implementation that creates a swappable object from one dropArea to another.

For handling swap between two objects, we use switch case to manage different positions that get by array index. At the end of this condition, we splice boxArray that helps to get our final position of an object.

if (
// <========== Drop Area 0 ===========>
this.$refs[ref][0].nativeView.getLocationOnScreen().x >=
this.dropArea0.getLocationOnScreen().x &&
this.$refs[ref][0].nativeView.getLocationOnScreen().x <=
this.dropArea0.getLocationOnScreen().x + this.dropArea0.width &&
this.$refs[ref][0].nativeView.getLocationOnScreen().y >=
this.dropArea0.getLocationOnScreen().y &&
this.$refs[ref][0].nativeView.getLocationOnScreen().y <=
this.dropArea0.getLocationOnScreen().y + this.dropArea0.height
) {
this.translateX = this.$refs[ref][0].nativeView.translateX;
this.translateY = this.$refs[ref][0].nativeView.translateY;
this.dropArea0.scaleX = 1;
this.dropArea0.scaleY = 1;
if (this.$refs[ref][0].nativeView.translateX >= -30) {
this.$refs[ref][0].nativeView.translateX = 0;
} else {
this.$refs[ref][0].nativeView.translateX = -160;
}
if (this.$refs[ref][0].nativeView.translateY >= -30) {
this.$refs[ref][0].nativeView.translateY = 0;
} else {
this.$refs[ref][0].nativeView.translateY = -140;
}
// Translate Animation Start 0
// Handle Animation for swipe object from different position
switch (ref) {case 1:
if (this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX >= 0) {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateX = 160 - this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX;
} else {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateX = 160 + this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX;
}
if (this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY >= 0) {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateY = 0 - this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY;
} else {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateY = 0 + this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY;
}
break;
case 2:
if (this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX >= 0) {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateX = 0 - this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX;
} else {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateX = 0 + this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX;
}
if (this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY >= 0) {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateY =140 - this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY;
} else {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateY = 140 + this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY;
}
break;
case 3:
if (this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX >= 0) {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateX = 160 -
this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX;
} else {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateX = 160 + this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateX;
}
if (this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY >= 0) {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateY = 140 -
this.$refs[this.boxArray.indexOf(this.boxArray[0])][0].nativeView.translateY;
} else {
this.$refs[this.boxArray.indexOf(this.boxArray[0])]
[0].nativeView.translateY = 140 + this.$refs[this.boxArray.indexOf(this.boxArray[0])][0]
.nativeView.translateY;
}
break;
}
// Translate Animation End 0
// Array that control Position drag item
this.boxArray.splice(ref, 1, this.boxArray[0]);
this.boxArray.splice(0, 1, box);
}

Final Code

Finally, It’s time to put everything together adding all elements, code and animation to achieve an expected result.

ashutec

We offer software and product development services.

Raj Bhatt

Written by

Raj Bhatt

Software Engineer at Ashutec Solutions Pvt Ltd

ashutec

ashutec

We offer software and product development services. We architect, design and develop Web, Mobile, and Desktop applications. We deliver quality, reliable and cost-effective solutions using fixed cost, time and material models and open to other models as per needs of client.

Raj Bhatt

Written by

Raj Bhatt

Software Engineer at Ashutec Solutions Pvt Ltd

ashutec

ashutec

We offer software and product development services. We architect, design and develop Web, Mobile, and Desktop applications. We deliver quality, reliable and cost-effective solutions using fixed cost, time and material models and open to other models as per needs of client.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store