React Native ile Mobil Uygulama Geliştirme – 10 – Drag & Drop Bileşenini Oluşturma

“React Native ile Mobil Uygulama Geliştirme” başlıklı makalelerimizden bir yenisini daha sizlerle paylaşmak istiyorum. Bu makale, bir dizi makaleden oluşacak olan serisinin 10. kısmıdır. Bir önceki makalede (Part 9), React Native’de Redux Kullanımı ve mobil projelerimizde nasıl kullanacağımızı anlattım.

React Native’de Drag & Drop bileşenini oluşturmayı ve mobil projelerimizde nasıl kullanacağımızı öğreneceğiz.

Bir sonraki React Native uygulamam için beyin fırtınası yaparken, işte ilk adım, bir Drag & Drop bileşenini oluşturabilmek için hareketi izleyen bir API olup olmadığını görmek istedim.
Neyse ki bulması çok zor olmadı: PanResponder’a sahibiz! Bununla hareketi soyut bir durum olarak izleyebilir ve kullanıcı arayüzümüzü buna göre güncelleyebiliriz.

Daha önceki makaleleri okumadıysanız, lütfen buradan başlayın.

Nasıl bir uygulama yapmak istediğimizin kafamızda netleşmesi için aşağıdaki görsele bakabilirsiniz.

Drag Bileşen Oluşturma

PanResponder API belgelerini takip etmenin biraz zor olduğunu buldum, ancak bu örnek ve animasyon kılavuzu gitmeme yardımcı oldu. PanResponder sınıfını içe aktardıktan sonra, componentWillMount() yaşam döngüsü yönteminde .create yöntemiyle başlatırsınız. Bunu constructor() da yazabilirsiniz.

import React, { Component } from "react";
import {
  StyleSheet,
  View,
  PanResponder,
  Animated
} from "react-native";

export default class Draggable extends Component {
  constructor() {
    super();
    this.state = {
      pan: new Animated.ValueXY()
    };
  }

  componentWillMount() {
    // Add a listener for the delta value change
    this._val = { x:0, y:0 }
    this.state.pan.addListener((value) => this._val = value);
    // Initialize PanResponder with move handling
    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: (e, gesture) => true,
      onPanResponderMove: Animated.event([
        null, { dx: this.state.pan.x, dy: this.state.pan.y }
      ])
      // adjusting delta value
      this.state.pan.setValue({ x:0, y:0})
    });
  }

  render() {
    const panStyle = {
      transform: this.state.pan.getTranslateTransform()
    }
    return (
        <Animated.View
          {...this.panResponder.panHandlers}
          style={[panStyle, styles.circle]}
        />
    );
  }
}

let CIRCLE_RADIUS = 30;
let styles = StyleSheet.create({
  circle: {
    backgroundColor: "skyblue",
    width: CIRCLE_RADIUS * 2,
    height: CIRCLE_RADIUS * 2,
    borderRadius: CIRCLE_RADIUS
  }
});

this.panResponder = PanResponder.create(), panResponder’ı başlatır ve bir referans oluşturur. Bunu <Animate.View> bileşenimizde, bir sahne grubundan geçiyormuş gibi {… this.panResponder.panHandlers} ‘ı geçirerek kullanırız.
PanResponder.create() içinde onStartShouldSetPanResponder’ı true olarak ayarladık, böylece panResponder dokunma geri bildirimlerine yanıt verecek. Sonra onPanResponderMove’a bir Animated.event iletiriz: kullanıcının hareket ettiği Animated.View circle bileşenimizin konumunu güncellemek için.
Çevremizin konumunu elde etmek için hesaplanan animasyon değerini this.state.pan.getTranslateTransform() ‘dan alıp Animated.View’a aktardığımız bir dönüştürme stili oluşturmak için kullanırız.
Son olarak, öğenin ikinci dokunuşta atlamaması için delta değerini ayarlıyoruz.
Bu noktada, kullanıcının etkileşime girebileceği sürüklenebilir bir dairemiz var:

Çemberi İlk Konumuna Geri Döndürmek

Bileşeni bıraktıklarında dairenin orijinal konumuna geri dönmesini istiyoruz. Bunu yapmak için onPanResponderRelease’i kullanarak kullanıcı arayüzüne kullanıcı bıraktığında nasıl yanıt vereceğini bildiririz.

componentWillMount() {
  ...
    this.panResponder = PanResponder.create({
      ...
      onPanResponderRelease: (e, gesture) => {
        Animated.spring(this.state.pan, {
          toValue: { x: 0, y: 0 },
          friction: 5
        }).start();
      }
    });

Dairemiz şimdi ilk konumuna geri dönüyor:

Bırakma Alanının Oluşturulması

Artık sürüklemeye sahibiz, bırakmaya ihtiyacımız var. Bırakma alanımızla başka bir bileşen oluşturuyoruz ve içinde Sürüklenebilir bileşenimizi kullanıyoruz:

import React, { Component } from "react";
import { StyleSheet, View, Text } from "react-native";
import Draggable from "./Draggable";

export default class Screen extends Component {
  render() {
    return (
      <View style={styles.mainContainer}>
        <View style={styles.dropZone}>
          <Text style={styles.text}>Drop them here!</Text>
        </View>
        <View style={styles.ballContainer} />
        <View style={styles.row}>
          <Draggable />
          <Draggable />
          <Draggable />
          <Draggable />
          <Draggable />
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  mainContainer: {
    flex: 1
  },
  ballContainer: {
    height:200
  },
  row: {
    flexDirection: "row"
  },  
  dropZone: {
    height: 200,
    backgroundColor: "#00334d"
  },
  text: {
    marginTop: 25,
    marginLeft: 5,
    marginRight: 5,
    textAlign: "center",
    color: "#fff",
    fontSize: 25,
    fontWeight: "bold"
  }
});

Ardından Draggable, onPanResponderRelease işleyicisine biraz mantık ekliyoruz ve bırakma alanında olup olmadığımızı belirlemek için bir işlev ekliyoruz. Not: Burada ekrandaki bırakma bölgesinin konumu hakkında varsayımlarda bulunuyoruz.

...
  constructor()
    super.props();
    this.state = {
      showDraggable: true,
      dropAreaValues: null,
      pan: new Animated.ValueXY(),
      opacity: new Animated.Value(1)
    };
  }
  componentWillMount() {
    ...
    this.panResponder = PanResponder.create({
      ...
      onPanResponderRelease: (e, gesture) => {
        if (this.isDropArea(gesture)) {
          Animated.timing(this.state.opacity, {
          toValue: 0,
          duration: 1000
        }).start(() =>
          this.setState({
             showDraggable: false
          })
        );
      } else {
        Animated.spring(this.state.pan, {
          toValue: { x: 0, y: 0 },
          friction: 5
        }).start();
      }
    }
  isDropArea(gesture) {
    return gesture.moveY < 200;
  }

Uygulamayı çalıştırdığımızda aşağıdaki gibi bir görüntü ortaya çıkar.

PanResponder API’si ilk başta benim için biraz korkutucuydu, ancak şimdi bu, herkesin uygulamalarında kullanıcı deneyimini daha iyi hale getirmek için kullanabileceği harika bir API olduğunu düşünüyorum.
Umarım bu makale, sorularınız veya endişeleriniz olan yorumlarda size ulaşmanıza yardımcı olmuştur. Okuduğunuz için teşekkürler ve iyi kodlamalar!

Lütfen bize görüşlerinizi bildirmekten çekinmeyin.

Kaynak

1-https://blog.reactnativecoach.com/creating-draggable-component-with-react-native-132d30c27cb0

Tavsiye Edilen Yazılar

2 Yorumlar

  1. Merhaba,
    Öncelikle emeğinize sağlık.
    Ama keşke artık functional bir sayfa ve hook larla örnekler görsek. Sanki class yapısı biraz eskidi

    • Merhabalar öncelikle takip ettiğiniz için teşekkürler.
      Önerilerinizi dikkate alacağım yakın zamanda hookslar ve functional örneklerle karşınızda olacağım. Selamlar


Bir Yorum Ekle

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir