Görünümlerle sürükle ve bırak işlevini uygulayın

Etkinliklere yanıt vererek görünümlerde sürükle ve bırak sürecini uygulayabilirsiniz sürükleyip bırakma işlemini tetikleyebilen ve tüketen bir etkinliktir.

Sürüklemeyi başlat

Kullanıcı genellikle dokunup tıklayarak veya tıklayarak ve bir hareketle basılı tutarken, sürüklemek istedikleri bir öğeyi basılı tutar.

Bunu bir View içinde işlemek için bir ClipData nesnesi ve Şunun için ClipData.Item nesnesi: taşınmakta olan verileri içerebilir. ClipData kapsamında, aşağıdaki özelliklere sahip meta verileri sağlayın: şurada saklanır: ClipDescription nesne ClipData içinde yer alıyor. Sürükleme ve bırakma işlemi için veri taşıma işlemi için gerçek bir nesne yerine null öğesini kullanmak isteyebilirsiniz.

Örneğin, bu kod snippet'i bir dokunma ve bekletme şunu içeren bir ClipData nesnesi oluşturarak bir ImageView üzerinde hareketi etiketi (veya etiketi):ImageView

Kotlin

// Create a string for the ImageView label.
val IMAGEVIEW_TAG = "icon bitmap"
...
val imageView = ImageView(context).apply {
    // Set the bitmap for the ImageView from an icon bitmap defined elsewhere.
    setImageBitmap(iconBitmap)
    tag = IMAGEVIEW_TAG
    setOnLongClickListener { v ->
        // Create a new ClipData. This is done in two steps to provide
        // clarity. The convenience method ClipData.newPlainText() can
        // create a plain text ClipData in one step.

        // Create a new ClipData.Item from the ImageView object's tag.
        val item = ClipData.Item(v.tag as? CharSequence)

        // Create a new ClipData using the tag as a label, the plain text
        // MIME type, and the already-created item. This creates a new
        // ClipDescription object within the ClipData and sets its MIME type
        // to "text/plain".
        val dragData = ClipData(
            v.tag as? CharSequence,
            arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN),
            item)

        // Instantiate the drag shadow builder. We use this imageView object
        // to create the default builder.
        val myShadow = View.DragShadowBuilder(view: this)

        // Start the drag.
        v.startDragAndDrop(dragData,  // The data to be dragged.
                            myShadow,  // The drag shadow builder.
                            null,      // No need to use local data.
                            0          // Flags. Not currently used, set to 0.
        )

        // Indicate that the long-click is handled.
        true
    }
}

Java

// Create a string for the ImageView label.
private static final String IMAGEVIEW_TAG = "icon bitmap";
...
// Create a new ImageView.
ImageView imageView = new ImageView(context);

// Set the bitmap for the ImageView from an icon bitmap defined elsewhere.
imageView.setImageBitmap(iconBitmap);

// Set the tag.
imageView.setTag(IMAGEVIEW_TAG);

// Set a long-click listener for the ImageView using an anonymous listener
// object that implements the OnLongClickListener interface.
imageView.setOnLongClickListener( v -> {

    // Create a new ClipData. This is done in two steps to provide clarity. The
    // convenience method ClipData.newPlainText() can create a plain text
    // ClipData in one step.

    // Create a new ClipData.Item from the ImageView object's tag.
    ClipData.Item item = new ClipData.Item((CharSequence) v.getTag());

    // Create a new ClipData using the tag as a label, the plain text MIME type,
    // and the already-created item. This creates a new ClipDescription object
    // within the ClipData and sets its MIME type to "text/plain".
    ClipData dragData = new ClipData(
            (CharSequence) v.getTag(),
            new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN },
            item);

    // Instantiate the drag shadow builder. We use this imageView object
    // to create the default builder.
    View.DragShadowBuilder myShadow = new View.DragShadowBuilder(imageView);

    // Start the drag.
    v.startDragAndDrop(dragData,  // The data to be dragged.
                            myShadow,  // The drag shadow builder.
                            null,      // No need to use local data.
                            0          // Flags. Not currently used, set to 0.
    );

    // Indicate that the long-click is handled.
    return true;
});

Sürükleme başlangıcına yanıt verme

Sürükleme işlemi sırasında sistem, sürükleme etkinliklerini sürükleme etkinliğine gönderir Geçerli düzendeki View nesnelerin işleyicileri. Dinleyiciler işlem türünü almak için DragEvent.getAction() aranıyor. Bir sürüklemenin başında bu yöntem ACTION_DRAG_STARTED değerini döndürür.

ACTION_DRAG_STARTED işlem türündeki bir etkinliğe yanıt olarak, sürükleme etkinliği dinleyici şunları yapmalıdır:

  1. Telefonla arama DragEvent.getClipDescription() ve döndürülen ClipDescription öğesindeki MIME türü yöntemlerini kullanın ve dinleyicinin sürüklenen verileri kabul edip edemeyeceğini belirler.

    Sürükleme ve bırakma işlemi veri hareketini temsil etmiyorsa bu durum gerekmez.

  2. Sürükleme etkinliği işleyicisi bir bırakmayı kabul edebiliyorsa bunu bildirmek için true değerini döndürmesi gerekir dinleyiciye sürükleme etkinliklerini göndermeye devam etmesini sağlar. Dinleyici düşüş kabul edemiyor, dinleyicinin false değerini döndürmesi gerekiyor ve sistem durur sistem, kod gönderene kadar işleyiciye sürükleme Sürükleyip bırakma işlemini tamamlamak için ACTION_DRAG_ENDED tuşlarına basın.

ACTION_DRAG_STARTED etkinliği için aşağıdaki DragEvent yöntemleri aynı değildir geçerli: getClipData(), getX(), getY() ve getResult().

Sürükleme sırasındaki etkinlikleri işleme

Sürükleme işlemi sırasında, yanıt olarak true değerini döndüren etkinlik işleyicileri sürükleyin ACTION_DRAG_STARTED sürükleme etkinliği, sürükleme etkinliklerini almaya devam eder. Türler bir işleyicinin sürükleme sırasında aldığı sürükleme etkinliklerinin sayısı, sürükleme gölgesi ve dinleyicinin View görünürlüğü. Dinleyiciler sürüklemeyi etkinliklerini dikkate alarak View görünümünü değiştirmeleri gerekip gerekmediğine karar verir.

Sürükleme işlemi sırasında DragEvent.getAction(), şu üç değerden birini döndürür:

  • ACTION_DRAG_ENTERED: dinleyici, temas noktası ( kullanıcının parmağının veya faresinin altındayken fareyi işaret ederek işleyicinin View sınırlayıcı kutusu.
  • ACTION_DRAG_LOCATION: dinleyici bir ACTION_DRAG_ENTERED etkinliği aldığında yeni bir etkinlik alır. Temas noktası belirlenene kadar her hareket ettiğinde ACTION_DRAG_LOCATION etkinliği Kullanıcı ACTION_DRAG_EXITED etkinliği alır. getX() ve getY() yöntemleri temas noktasının X ve Y koordinatlarını döndürür.
  • ACTION_DRAG_EXITED: Bu etkinlik işlemi türü, daha önce alan adını almış bir dinleyiciye gönderilir. ACTION_DRAG_ENTERED. Etkinlik, sürükleme gölgesi temas noktası olduğunda gönderilir dinleyicinin View öğesinin sınırlayıcı kutusundan dışarıya doğru hareket eder sınırlayıcı kutudur.

Sürükleme etkinliği işleyicinin bu işlem türlerinin hiçbirine tepki vermesi gerekmez. Eğer işleyici sisteme bir değer döndürürse bu değer yoksayılır.

Aşağıda, bu işlem türlerinin her birine yanıt vermeyle ilgili bazı yönergeler verilmiştir:

  • Dinleyici, ACTION_DRAG_ENTERED veya ACTION_DRAG_LOCATION mesajına yanıt olarak View öğesinin görünümünü değiştirerek potansiyel bir düşüşe ihtiyacınız vardır.
  • ACTION_DRAG_LOCATION işlem türüne sahip bir etkinlik şunun için geçerli veriler içeriyor: getX() ve getY(), temas noktasının konumuna karşılık gelir. İlgili içeriği oluşturmak için kullanılan dinleyici, bu bilgileri kullanarak View görünümünü veya kullanıcının uygulamayı, temas noktasını bırakabileceği içerik.
  • ACTION_DRAG_EXITED komutuna yanıt olarak, dinleyicinin tüm görünümleri sıfırlaması gerekir ACTION_DRAG_ENTERED veya ACTION_DRAG_LOCATION. Bu, kullanıcıya View öğesinin doğru olmadığını gösterir düşmesine yardımcı olur.

Düşüş karşısında yanıt verin

Kullanıcı bir View üzerinde sürükleme gölgesini serbest bıraktığında ve daha önce View sürüklenen içeriği kabul edebildiğini bildirirse, sistem bir etkinliği ACTION_DROP işlem türündeki View öğesine sürükleyin.

Sürükleme etkinliği işleyicisi aşağıdakileri yapmalıdır:

  1. Orijinal ClipData nesnesini almak için getClipData() komutunu çağırın startDragAndDrop() verileri işlememiz gerekir. Sürükleme ve bırakma işlemi verileri temsil etmiyorsa bu gerekli değildir.

  2. Düşüşün başarıyla işlendiğini belirtmek için true boole değerini döndürün, veya değilse false. Döndürülen değer, Nihai ACTION_DRAG_ENDED etkinliği için getResult(). Eğer bir ACTION_DROP etkinliği göndermez (getResult() tarafından döndürülen değer) ACTION_DRAG_ENDED etkinliği false.

Bir ACTION_DROP etkinliği için getX() ve getY(), şu koordinat sistemini kullanır: düşüşü alan View, her bir öğenin X ve Y konumunu geri döndürür. bir temas noktası bulunuyor.

Kullanıcı, sürükleme etkinliği olan bir View üzerindeki sürükleme gölgesini serbest bırakabilir. dinleyici sürükleme etkinlikleri, uygulamanızın kullanıcı arayüzündeki boş bölgeler veya uygulamanızın dışındaki alanlar üzerinde çalışırsanız Android, işlem içeren bir etkinlik göndermez. ACTION_DROP türünde bir etkinlik gönderir ve yalnızca ACTION_DRAG_ENDED etkinliği gönderir.

Sürükleme bitişine yanıt verme

Kullanıcı sürükleme gölgesini serbest bıraktıktan hemen sonra sistem bir sürükleme gönderir. tüm sürükleme etkinliği işleyicileri için ACTION_DRAG_ENDED işlem türüne sahip etkinlik tercih edebilirsiniz. Bu, sürükleme işleminin tamamlandığını gösterir.

Her sürükleme etkinliği işleyicisi aşağıdakileri yapmalıdır:

  1. Dinleyici işlem sırasında görünümünü değiştirirse sıfırlanmalıdır. kullanıcıya görsel bir gösterge olarak varsayılan görünümüne işlemi tamamlandı.
  2. Dinleyici isteğe bağlı olarak getResult() numaralı telefonu arayarak işlemidir. Dinleyici bir işlem etkinliğine yanıt olarak true değerini döndürürse ACTION_DROP yazıp getResult(), true boole değerini döndürür. Diğer tüm durumlarda getResult(), sistemin şu durumlar dahil olmak üzere false boole değerini döndürür: ACTION_DROP etkinliği göndermiyor.
  3. Dinleyici, bırakma işleminin başarıyla tamamlandığını belirtmek için işlevi, sisteme true boole değerini döndürmelidir. false adlı ürünü geri vermediğinizde, gölgenin kaynağına geri dönmesini gösteren görsel işaret kullanıcıya işlemin başarısız olduğunu bildirin.

Sürükleme etkinliklerine yanıt verme: Örnek

Tüm sürükleme etkinlikleri, sürükleme etkinliği yönteminiz veya işleyiciniz tarafından alınır. İlgili içeriği oluşturmak için kullanılan aşağıdaki kod snippet'i, sürükleme etkinliklerine yanıt verme örneğidir:

Kotlin

val imageView = ImageView(this)

// Set the drag event listener for the View.
imageView.setOnDragListener { v, e ->

    // Handle each of the expected events.
    when (e.action) {
        DragEvent.ACTION_DRAG_STARTED -> {
            // Determine whether this View can accept the dragged data.
            if (e.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
                // As an example, apply a blue color tint to the View to
                // indicate that it can accept data.
                (v as? ImageView)?.setColorFilter(Color.BLUE)

                // Invalidate the view to force a redraw in the new tint.
                v.invalidate()

                // Return true to indicate that the View can accept the dragged
                // data.
                true
            } else {
                // Return false to indicate that, during the current drag and
                // drop operation, this View doesn't receive events again until
                // ACTION_DRAG_ENDED is sent.
                false
            }
        }
        DragEvent.ACTION_DRAG_ENTERED -> {
            // Apply a green tint to the View.
            (v as? ImageView)?.setColorFilter(Color.GREEN)

            // Invalidate the view to force a redraw in the new tint.
            v.invalidate()

            // Return true. The value is ignored.
            true
        }

        DragEvent.ACTION_DRAG_LOCATION ->
            // Ignore the event.
            true
        DragEvent.ACTION_DRAG_EXITED -> {
            // Reset the color tint to blue.
            (v as? ImageView)?.setColorFilter(Color.BLUE)

            // Invalidate the view to force a redraw in the new tint.
            v.invalidate()

            // Return true. The value is ignored.
            true
        }
        DragEvent.ACTION_DROP -> {
            // Get the item containing the dragged data.
            val item: ClipData.Item = e.clipData.getItemAt(0)

            // Get the text data from the item.
            val dragData = item.text

            // Display a message containing the dragged data.
            Toast.makeText(this, "Dragged data is $dragData", Toast.LENGTH_LONG).show()

            // Turn off color tints.
            (v as? ImageView)?.clearColorFilter()

            // Invalidate the view to force a redraw.
            v.invalidate()

            // Return true. DragEvent.getResult() returns true.
            true
        }

        DragEvent.ACTION_DRAG_ENDED -> {
            // Turn off color tinting.
            (v as? ImageView)?.clearColorFilter()

            // Invalidate the view to force a redraw.
            v.invalidate()

            // Do a getResult() and display what happens.
            when(e.result) {
                true ->
                    Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG)
                else ->
                    Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG)
            }.show()

            // Return true. The value is ignored.
            true
        }
        else -> {
            // An unknown action type is received.
            Log.e("DragDrop Example", "Unknown action type received by View.OnDragListener.")
            false
        }
    }
}

Java

View imageView = new ImageView(this);

// Set the drag event listener for the View.
imageView.setOnDragListener( (v, e) -> {

    // Handle each of the expected events.
    switch(e.getAction()) {

        case DragEvent.ACTION_DRAG_STARTED:

            // Determine whether this View can accept the dragged data.
            if (e.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {

                // As an example, apply a blue color tint to the View to
                // indicate that it can accept data.
                ((ImageView)v).setColorFilter(Color.BLUE);

                // Invalidate the view to force a redraw in the new tint.
                v.invalidate();

                // Return true to indicate that the View can accept the dragged
                // data.
                return true;

            }

            // Return false to indicate that, during the current drag-and-drop
            // operation, this View doesn't receive events again until
            // ACTION_DRAG_ENDED is sent.
            return false;

        case DragEvent.ACTION_DRAG_ENTERED:

            // Apply a green tint to the View.
            ((ImageView)v).setColorFilter(Color.GREEN);

            // Invalidate the view to force a redraw in the new tint.
            v.invalidate();

            // Return true. The value is ignored.
            return true;

        case DragEvent.ACTION_DRAG_LOCATION:

            // Ignore the event.
            return true;

        case DragEvent.ACTION_DRAG_EXITED:

            // Reset the color tint to blue.
            ((ImageView)v).setColorFilter(Color.BLUE);

            // Invalidate the view to force a redraw in the new tint.
            v.invalidate();

            // Return true. The value is ignored.
            return true;

        case DragEvent.ACTION_DROP:

            // Get the item containing the dragged data.
            ClipData.Item item = e.getClipData().getItemAt(0);

            // Get the text data from the item.
            CharSequence dragData = item.getText();

            // Display a message containing the dragged data.
            Toast.makeText(this, "Dragged data is " + dragData, Toast.LENGTH_LONG).show();

            // Turn off color tints.
            ((ImageView)v).clearColorFilter();

            // Invalidate the view to force a redraw.
            v.invalidate();

            // Return true. DragEvent.getResult() returns true.
            return true;

        case DragEvent.ACTION_DRAG_ENDED:

            // Turn off color tinting.
            ((ImageView)v).clearColorFilter();

            // Invalidate the view to force a redraw.
            v.invalidate();

            // Do a getResult() and displays what happens.
            if (e.getResult()) {
                Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG).show();
            }

            // Return true. The value is ignored.
            return true;

        // An unknown action type is received.
        default:
            Log.e("DragDrop Example","Unknown action type received by View.OnDragListener.");
            break;
    }

    return false;

});

Sürükleme gölgesini özelleştirme

Şuradaki yöntemleri geçersiz kılarak özelleştirilmiş bir myDragShadowBuilder tanımlayabilirsiniz: View.DragShadowBuilder. Aşağıdaki kod snippet'i, küçük bir TextView için dikdörtgen, gri sürükleme gölgesi:

Kotlin

private class MyDragShadowBuilder(view: View) : View.DragShadowBuilder(view) {

    private val shadow = ColorDrawable(Color.LTGRAY)

    // Define a callback that sends the drag shadow dimensions and touch point
    // back to the system.
    override fun onProvideShadowMetrics(size: Point, touch: Point) {

            // Set the width of the shadow to half the width of the original
            // View.
            val width: Int = view.width / 2

            // Set the height of the shadow to half the height of the original
            // View.
            val height: Int = view.height / 2

            // The drag shadow is a ColorDrawable. Set its dimensions to
            // be the same as the Canvas that the system provides. As a result,
            // the drag shadow fills the Canvas.
            shadow.setBounds(0, 0, width, height)

            // Set the size parameter's width and height values. These get back
            // to the system through the size parameter.
            size.set(width, height)

            // Set the touch point's position to be in the middle of the drag
            // shadow.
            touch.set(width / 2, height / 2)
    }

    // Define a callback that draws the drag shadow in a Canvas that the system
    // constructs from the dimensions passed to onProvideShadowMetrics().
    override fun onDrawShadow(canvas: Canvas) {

            // Draw the ColorDrawable on the Canvas passed in from the system.
            shadow.draw(canvas)
    }
}

Java

private static class MyDragShadowBuilder extends View.DragShadowBuilder {

    // The drag shadow image, defined as a drawable object.
    private static Drawable shadow;

    // Constructor.
    public MyDragShadowBuilder(View view) {

            // Store the View parameter.
            super(view);

            // Create a draggable image that fills the Canvas provided by the
            // system.
            shadow = new ColorDrawable(Color.LTGRAY);
    }

    // Define a callback that sends the drag shadow dimensions and touch point
    // back to the system.
    @Override
    public void onProvideShadowMetrics (Point size, Point touch) {

            // Define local variables.
            int width, height;

            // Set the width of the shadow to half the width of the original
            // View.
            width = getView().getWidth() / 2;

            // Set the height of the shadow to half the height of the original
            // View.
            height = getView().getHeight() / 2;

            // The drag shadow is a ColorDrawable. Set its dimensions to
            // be the same as the Canvas that the system provides. As a result,
            // the drag shadow fills the Canvas.
            shadow.setBounds(0, 0, width, height);

            // Set the size parameter's width and height values. These get back
            // to the system through the size parameter.
            size.set(width, height);

            // Set the touch point's position to be in the middle of the drag
            // shadow.
            touch.set(width / 2, height / 2);
    }

    // Define a callback that draws the drag shadow in a Canvas that the system
    // constructs from the dimensions passed to onProvideShadowMetrics().
    @Override
    public void onDrawShadow(Canvas canvas) {

            // Draw the ColorDrawable on the Canvas passed in from the system.
            shadow.draw(canvas);
    }
}