Dragging and dropping UI elements

How to move NativeScript UI elements around with touch dragging and collision detection.

  •         
    import { Component, ElementRef, OnInit, ViewChild } from "@angular/core";
    import { PanGestureEventData } from "ui/gestures";
    import { Image } from "ui/image";
    import { GridLayout } from "ui/layouts/grid-layout";
    import { AnimationCurve } from "ui/enums";
    
    @Component({
      selector: "my-app",
      template: `
        <ActionBar title="Drag and Drop"></ActionBar>
        <GridLayout #container width="100%" height="400" backgroundColor="gray">
              <Image #dragImage width="100" height="100" horizontalAlignment="left" verticalAlignment="top" (pan)="onPan($event)" src="~/images/apple.jpg"></Image>
        </GridLayout>
      `
    })
    export class AppComponent implements OnInit {
      @ViewChild("container") container: ElementRef;
      itemContainer: GridLayout;
    
      @ViewChild("dragImage") dragImage: ElementRef;
      dragImageItem: Image;
      prevDeltaX: number;
      prevDeltaY: number;
    
      public ngOnInit() {
        this.itemContainer = <GridLayout>this.container.nativeElement;
    
        this.dragImageItem = <Image>this.dragImage.nativeElement;
        this.dragImageItem.translateX = 0;
        this.dragImageItem.translateY = 0;
        this.dragImageItem.scaleX = 1;
        this.dragImageItem.scaleY = 1
      }
    
      onPan(args: PanGestureEventData) {
        //console.log("Pan delta: [" + args.deltaX + ", " + args.deltaY + "] state: " + args.state);
        if (args.state === 1) // down
        {
          this.prevDeltaX = 0;
          this.prevDeltaY = 0;
        }
        else if (args.state === 2) // panning
        {
          this.dragImageItem.translateX += args.deltaX - this.prevDeltaX;
          this.dragImageItem.translateY += args.deltaY - this.prevDeltaY;
    
          this.prevDeltaX = args.deltaX;
          this.prevDeltaY = args.deltaY;
    
          // calculate the conversion from DPI to pixels
          let convFactor = this.dragImageItem.width / this.dragImageItem.getMeasuredWidth();
          let edgeX = (this.itemContainer.getMeasuredWidth() - this.dragImageItem.getMeasuredWidth()) * convFactor;
          let edgeY = (this.itemContainer.getMeasuredHeight() - this.dragImageItem.getMeasuredHeight()) * convFactor;      
    
          // X border
          if (this.dragImageItem.translateX < 0) {
            this.dragImageItem.translateX = 0;
          }
          else if (this.dragImageItem.translateX > edgeX) {
            this.dragImageItem.translateX = edgeX;
          }
    
          // Y border
          if (this.dragImageItem.translateY < 0) {
            this.dragImageItem.translateY = 0;
          }
          else if (this.dragImageItem.translateY > edgeY) {
            this.dragImageItem.translateY = edgeY;
          }
        }
        else if (args.state === 3) // up
        {      
          this.dragImageItem.animate({
            translate: { x: 0, y: 0 },
            duration: 1000,
            curve: AnimationCurve.cubicBezier(0.1, 0.1, 0.1, 1)
          });      
        }
      }
    }